Index: nslcd/cfg.h
===================================================================
--- nslcd/cfg.h (revision 1135)
+++ nslcd/cfg.h (working copy)
@@ -95,6 +95,8 @@
char *ldc_bindpw;
/* bind DN for password modification by administrator */
char *ldc_rootpwmoddn;
+ /* bind password for password modification by root */
+ char *ldc_rootpwmodpw;
/* sasl authentication id */
char *ldc_sasl_authcid;
/* sasl authorization id */
Index: nslcd/cfg.c
===================================================================
--- nslcd/cfg.c (revision 1135)
+++ nslcd/cfg.c (working copy)
@@ -97,6 +97,7 @@
cfg->ldc_binddn=NULL;
cfg->ldc_bindpw=NULL;
cfg->ldc_rootpwmoddn=NULL;
+ cfg->ldc_rootpwmodpw=NULL;
cfg->ldc_sasl_authcid=NULL;
cfg->ldc_sasl_authzid=NULL;
cfg->ldc_sasl_secprops=NULL;
@@ -818,6 +819,10 @@
{
get_restdup(filename,lnr,keyword,&line,&cfg->ldc_rootpwmoddn);
}
+ else if (strcasecmp(keyword,"rootpwmodpw")==0)
+ {
+ get_restdup(filename,lnr,keyword,&line,&cfg->ldc_rootpwmodpw);
+ }
/* SASL authentication options */
else if (strcasecmp(keyword,"sasl_authcid")==0)
{
Index: nslcd/pam.c
===================================================================
--- nslcd/pam.c (revision 1135)
+++ nslcd/pam.c (working copy)
@@ -129,7 +129,7 @@
}
/* check authentication credentials of the user */
-int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session)
+int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid)
{
int32_t tmpint32;
int rc;
@@ -148,8 +148,8 @@
/* write the response header */
WRITE_INT32(fp,NSLCD_VERSION);
WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC);
- /* if the username is blank and rootpwmoddn is configure, try to authenticate
- as administrator, otherwise validate request as usual */
+ /* if the username is blank and rootpwmoddn is configured, try to
+ authenticate as administrator */
if ((*username=='\0')&&(nslcd_cfg->ldc_rootpwmoddn!=NULL))
{
if (strlen(nslcd_cfg->ldc_rootpwmoddn)>=sizeof(userdn))
@@ -158,6 +158,16 @@
return -1;
}
strcpy(userdn,nslcd_cfg->ldc_rootpwmoddn);
+ /* if the caller is root we will allow the use of the rootpwmodpw option */
+ if ((*password=='\0')&&(calleruid==0)&&(nslcd_cfg->ldc_rootpwmodpw!=NULL))
+ {
+ if (strlen(nslcd_cfg->ldc_rootpwmodpw)>=sizeof(password))
+ {
+ log_log(LOG_ERR,"nslcd_pam_authc(): rootpwmodpw will not fit in password");
+ return -1;
+ }
+ strcpy(password,nslcd_cfg->ldc_rootpwmodpw);
+ }
}
else if (validate_user(session,userdn,sizeof(userdn),username,sizeof(username)))
{
@@ -423,7 +433,7 @@
return rc;
}
-int nslcd_pam_pwmod(TFILE *fp,MYLDAP_SESSION *session)
+int nslcd_pam_pwmod(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid)
{
int32_t tmpint32;
char username[256];
@@ -451,6 +461,16 @@
{
binddn=nslcd_cfg->ldc_rootpwmoddn;
userdn[0]='\0'; /* cause validate_user() to get the user DN */
+ /* check if rootpwmodpw should be used */
+ if ((*oldpassword=='\0')&&(calleruid==0)&&(nslcd_cfg->ldc_rootpwmodpw!=NULL))
+ {
+ if (strlen(nslcd_cfg->ldc_rootpwmodpw)>=sizeof(oldpassword))
+ {
+ log_log(LOG_ERR,"nslcd_pam_pwmod(): rootpwmodpw will not fit in oldpassword");
+ return -1;
+ }
+ strcpy(oldpassword,nslcd_cfg->ldc_rootpwmodpw);
+ }
}
/* validate request and fill in the blanks */
if (validate_user(session,userdn,sizeof(userdn),username,sizeof(username)))
Index: nslcd/common.h
===================================================================
--- nslcd/common.h (revision 1135)
+++ nslcd/common.h (working copy)
@@ -140,11 +140,11 @@
int nslcd_service_all(TFILE *fp,MYLDAP_SESSION *session);
int nslcd_shadow_byname(TFILE *fp,MYLDAP_SESSION *session);
int nslcd_shadow_all(TFILE *fp,MYLDAP_SESSION *session);
-int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session);
+int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid);
int nslcd_pam_authz(TFILE *fp,MYLDAP_SESSION *session);
int nslcd_pam_sess_o(TFILE *fp,MYLDAP_SESSION *session);
int nslcd_pam_sess_c(TFILE *fp,MYLDAP_SESSION *session);
-int nslcd_pam_pwmod(TFILE *fp,MYLDAP_SESSION *session);
+int nslcd_pam_pwmod(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid);
/* macros for generating service handling code */
#define NSLCD_HANDLE(db,fn,readfn,logcall,action,mkfilter,writefn) \
Index: nslcd/nslcd.c
===================================================================
--- nslcd/nslcd.c (revision 1135)
+++ nslcd/nslcd.c (working copy)
@@ -420,11 +420,11 @@
case NSLCD_ACTION_SERVICE_ALL: (void)nslcd_service_all(fp,session); break;
case NSLCD_ACTION_SHADOW_BYNAME: if (uid==0) (void)nslcd_shadow_byname(fp,session); break;
case NSLCD_ACTION_SHADOW_ALL: if (uid==0) (void)nslcd_shadow_all(fp,session); break;
- case NSLCD_ACTION_PAM_AUTHC: (void)nslcd_pam_authc(fp,session); break;
+ case NSLCD_ACTION_PAM_AUTHC: (void)nslcd_pam_authc(fp,session,uid); break;
case NSLCD_ACTION_PAM_AUTHZ: (void)nslcd_pam_authz(fp,session); break;
case NSLCD_ACTION_PAM_SESS_O: (void)nslcd_pam_sess_o(fp,session); break;
case NSLCD_ACTION_PAM_SESS_C: (void)nslcd_pam_sess_c(fp,session); break;
- case NSLCD_ACTION_PAM_PWMOD: (void)nslcd_pam_pwmod(fp,session); break;
+ case NSLCD_ACTION_PAM_PWMOD: (void)nslcd_pam_pwmod(fp,session,uid); break;
/* TODO: maybe only do pwmod for (suid) root users */
default:
log_log(LOG_WARNING,"invalid request id: %d",(int)action);
Index: pam/pam.c
===================================================================
--- pam/pam.c (revision 1135)
+++ pam/pam.c (working copy)
@@ -513,6 +513,7 @@
const char *username,*service;
const char *oldpassword=NULL,*newpassword=NULL;
struct passwd *pwent;
+ uid_t myuid;
/* set up configuration */
rc=init(pamh,flags,argc,argv,&cfg,&ctx,&username,&service);
if (rc!=PAM_SUCCESS)
@@ -523,8 +524,17 @@
{
/* see if the user is trying to modify another user's password */
pwent=getpwnam(username);
- if ((pwent!=NULL)&&(pwent->pw_uid!=getuid()))
+ myuid=getuid();
+ if ((pwent!=NULL)&&(pwent->pw_uid!=myuid))
{
+ /* we are root so we can test if nslcd will allow us to change the
+ user's password without the admin password */
+ if (myuid==0)
+ {
+ rc=nslcd_request_authc(pamh,ctx,&cfg,"",service,"");
+ if ((rc==PAM_SUCCESS)&&(ctx->authok==PAM_SUCCESS))
+ return pam_set_item(pamh,PAM_OLDAUTHTOK,"");
+ }
/* try to authenticate with the LDAP administrator password by passing
an empty username to the authc request */
rc=pam_get_authtok(pamh,PAM_OLDAUTHTOK,&oldpassword,"LDAP administrator password: ");
@@ -558,6 +568,9 @@
pam_syslog(pamh,LOG_NOTICE,"%s; user=%s",pam_strerror(pamh,ctx->authok),username);
else if (cfg.debug)
pam_syslog(pamh,LOG_DEBUG,"authentication succeeded");
+ /* store password (needed if oldpassword was retreived from context) */
+ if (rc==PAM_SUCCESS)
+ return pam_set_item(pamh,PAM_OLDAUTHTOK,oldpassword);
/* remap error code */
return remap_pam_rc(ctx->authok,&cfg);
}
Index: man/nslcd.conf.5.xml
===================================================================
--- man/nslcd.conf.5.xml (revision 1135)
+++ man/nslcd.conf.5.xml (working copy)
@@ -192,12 +192,28 @@
Specifies the distinguished name to use when the root user tries to
- modify a user's password using the PAM module. The PAM module prompts
- the user for the admin password instead of the user's password.
+ modify a user's password using the PAM module.
+
+ PASSWORD
+
+
+ Specifies the clear text credentials with which to bind if the root
+ user tries to change a user's password.
+ This option is only applicable when used with
+ above.
+ If this option is not specified the PAM module prompts the user for
+ this password.
+ If you set this option you should consider changing the permissions
+ of the nslcd.conf file to only grant access to
+ the root user.
+
+
+
+