|
|
@ -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)) { |
|
|
|