|
|
|
@ -22,14 +22,222 @@
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <syslog.h>
|
|
|
|
|
#include <ldap.h>
|
|
|
|
|
|
|
|
|
|
#include <asm/unistd.h>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define PAM_LDAP_PATH_CONF "/etc/ldap.conf"
|
|
|
|
|
#define PAM_SM_AUTH
|
|
|
|
|
#define MAX_V 30
|
|
|
|
|
#define WAITTIME 30
|
|
|
|
|
|
|
|
|
|
typedef struct pam_config
|
|
|
|
|
{
|
|
|
|
|
/* file name read from */
|
|
|
|
|
char *configFile;
|
|
|
|
|
/* space delimited list of servers */
|
|
|
|
|
char *host;
|
|
|
|
|
/* port, expected to be common to all servers */
|
|
|
|
|
int port;
|
|
|
|
|
int version;
|
|
|
|
|
/* bind dn/pw for "anonymous" authentication */
|
|
|
|
|
char *binddn;
|
|
|
|
|
char *bindpw;
|
|
|
|
|
|
|
|
|
|
} pam_config_t;
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_alloc_config (pam_config_t ** presult)
|
|
|
|
|
{
|
|
|
|
|
pam_config_t *result;
|
|
|
|
|
|
|
|
|
|
if (*presult == NULL)
|
|
|
|
|
{
|
|
|
|
|
*presult = (pam_config_t *) calloc (1, sizeof (*result));
|
|
|
|
|
if (*presult == NULL)
|
|
|
|
|
return PAM_BUF_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = *presult;
|
|
|
|
|
result->configFile = NULL;
|
|
|
|
|
result->host = NULL;
|
|
|
|
|
result->port = 0;
|
|
|
|
|
result->binddn = NULL;
|
|
|
|
|
result->bindpw = NULL;
|
|
|
|
|
result->version = LDAP_VERSION3;
|
|
|
|
|
return PAM_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_read_config (const char *configFile, pam_config_t ** presult)
|
|
|
|
|
{
|
|
|
|
|
/* this is the same configuration file as nss_ldap */
|
|
|
|
|
FILE *fp;
|
|
|
|
|
char b[BUFSIZ];
|
|
|
|
|
pam_config_t *result;
|
|
|
|
|
|
|
|
|
|
if (_alloc_config (presult) != PAM_SUCCESS)
|
|
|
|
|
{
|
|
|
|
|
return PAM_BUF_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = *presult;
|
|
|
|
|
|
|
|
|
|
/* configuration file location is configurable; default /etc/ldap.conf */
|
|
|
|
|
if (configFile == NULL)
|
|
|
|
|
{
|
|
|
|
|
configFile = PAM_LDAP_PATH_CONF;
|
|
|
|
|
result->configFile = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result->configFile = strdup (configFile);
|
|
|
|
|
if (result->configFile == NULL)
|
|
|
|
|
return PAM_BUF_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fp = fopen (configFile, "r");
|
|
|
|
|
|
|
|
|
|
if (fp == NULL)
|
|
|
|
|
{
|
|
|
|
|
return PAM_SERVICE_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (fgets (b, sizeof (b), fp) != NULL)
|
|
|
|
|
{
|
|
|
|
|
char *k, *v;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
if (*b == '\n' || *b == '#')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
k = b;
|
|
|
|
|
v = k;
|
|
|
|
|
while (*v != '\0' && *v != ' ' && *v != '\t')
|
|
|
|
|
v++;
|
|
|
|
|
|
|
|
|
|
if (*v == '\0')
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
*(v++) = '\0';
|
|
|
|
|
|
|
|
|
|
/* skip all whitespaces between keyword and value */
|
|
|
|
|
while (*v == ' ' || *v == '\t')
|
|
|
|
|
v++;
|
|
|
|
|
|
|
|
|
|
/* kick off all whitespaces and newline at the end of value */
|
|
|
|
|
len = strlen (v) - 1;
|
|
|
|
|
while (v[len] == ' ' || v[len] == '\t' || v[len] == '\n')
|
|
|
|
|
--len;
|
|
|
|
|
v[len + 1] = '\0';
|
|
|
|
|
|
|
|
|
|
if (!strcasecmp (k, "host"))
|
|
|
|
|
{
|
|
|
|
|
result->host = strdup (v);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcasecmp (k, "binddn"))
|
|
|
|
|
{
|
|
|
|
|
result->binddn = strdup (v);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcasecmp (k, "bindpw"))
|
|
|
|
|
{
|
|
|
|
|
result->bindpw = strdup (v);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcasecmp (k, "port"))
|
|
|
|
|
{
|
|
|
|
|
result->port = atoi (v);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcasecmp (k, "ldap_version"))
|
|
|
|
|
{
|
|
|
|
|
result->version = atoi (v);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result->host == NULL || result->binddn == NULL ||
|
|
|
|
|
result->bindpw == NULL)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* According to PAM Documentation, such an error in a config file
|
|
|
|
|
* SHOULD be logged at LOG_ALERT level
|
|
|
|
|
*/
|
|
|
|
|
syslog (LOG_ALERT, "pam_ldap: missing \"host\" in file \"%s\"",
|
|
|
|
|
configFile);
|
|
|
|
|
return PAM_SERVICE_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (result->port == 0)
|
|
|
|
|
{
|
|
|
|
|
result->port = LDAP_PORT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose (fp);
|
|
|
|
|
|
|
|
|
|
/* can't use _pam_overwrite because it only goes to end of string,
|
|
|
|
|
* not the buffer
|
|
|
|
|
*/
|
|
|
|
|
memset (b, 0, BUFSIZ);
|
|
|
|
|
return PAM_SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_release_config (pam_config_t ** pconfig)
|
|
|
|
|
{
|
|
|
|
|
pam_config_t *c;
|
|
|
|
|
c = *pconfig;
|
|
|
|
|
if (c == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (c->configFile != NULL)
|
|
|
|
|
free (c->configFile);
|
|
|
|
|
|
|
|
|
|
if (c->host != NULL)
|
|
|
|
|
free (c->host);
|
|
|
|
|
|
|
|
|
|
if (c->binddn != NULL)
|
|
|
|
|
free (c->binddn);
|
|
|
|
|
if (c->bindpw != NULL)
|
|
|
|
|
free (c->bindpw);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_check_ldap (int retry_count)
|
|
|
|
|
{
|
|
|
|
|
int result;
|
|
|
|
|
struct berval userpw;
|
|
|
|
|
struct berval *servcred;
|
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
LDAP *ld;
|
|
|
|
|
pam_config_t * config= NULL;
|
|
|
|
|
if(_read_config(NULL,&config) != PAM_SUCCESS) {
|
|
|
|
|
if(config)
|
|
|
|
|
_release_config(&config);
|
|
|
|
|
return PAM_SERVICE_ERR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(buf,BUFSIZ,"ldap://%s:%d",config->host,config->port);
|
|
|
|
|
if(ldap_initialize(&ld,buf) == LDAP_SUCCESS &&
|
|
|
|
|
ldap_set_option(ld,LDAP_OPT_PROTOCOL_VERSION,
|
|
|
|
|
&config->version) == LDAP_SUCCESS ) {
|
|
|
|
|
userpw.bv_val = config->bindpw;
|
|
|
|
|
userpw.bv_len = (userpw.bv_val != 0) ? strlen (userpw.bv_val) : 0;
|
|
|
|
|
for(;retry_count;retry_count--) {
|
|
|
|
|
if (ldap_sasl_bind_s(ld,config->binddn,LDAP_SASL_SIMPLE,
|
|
|
|
|
&userpw, NULL, NULL,&servcred) == LDAP_SUCCESS) {
|
|
|
|
|
result = PAM_SUCCESS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
result = PAM_TRY_AGAIN;
|
|
|
|
|
}
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_release_config(&config);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int file_exists(const char *fname) {
|
|
|
|
|
return access(fname, 0) != -1;
|
|
|
|
|
}
|
|
|
|
@ -47,13 +255,15 @@ PAM_EXTERN int pam_sm_authenticate(pam_handle_t * pamh, int flags
|
|
|
|
|
|
|
|
|
|
// wait for client daemon
|
|
|
|
|
if (file_exists(boot_client) || file_exists(default_client)) {
|
|
|
|
|
for(i=0;i<WAITTIME;i++) {
|
|
|
|
|
if(file_exists(started_client) ||
|
|
|
|
|
file_exists(started_local)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
for(i=0;i<WAITTIME;i++) {
|
|
|
|
|
if(file_exists(started_client) ||
|
|
|
|
|
file_exists(started_local)) {
|
|
|
|
|
if(_check_ldap(WAITTIME-i)==PAM_SUCCESS)
|
|
|
|
|
return PAM_SUCCESS;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// break auth if not exists ldap.conf
|
|
|
|
|
if (!file_exists(ldap_conf)) {
|
|
|
|
|