lists.arthurdejong.org
RSS feed

nss-pam-ldapd commit: r1446 - nss-pam-ldapd/nslcd

[Date Prev][Date Next] [Thread Prev][Thread Next]

nss-pam-ldapd commit: r1446 - nss-pam-ldapd/nslcd



Author: arthur
Date: Sat Apr 30 16:37:43 2011
New Revision: 1446
URL: http://arthurdejong.org/viewvc/nss-pam-ldapd?view=rev&revision=1446

Log:
check shadow properties (similarly to what pam_unix does) in the PAM handling 
code

Modified:
   nss-pam-ldapd/nslcd/common.h
   nss-pam-ldapd/nslcd/pam.c
   nss-pam-ldapd/nslcd/shadow.c

Modified: nss-pam-ldapd/nslcd/common.h
==============================================================================
--- nss-pam-ldapd/nslcd/common.h        Sat Apr 30 11:15:09 2011        (r1445)
+++ nss-pam-ldapd/nslcd/common.h        Sat Apr 30 16:37:43 2011        (r1446)
@@ -111,6 +111,15 @@
 /* try to update the shadowLastChange attribute of the entry if possible */
 int update_lastchange(MYLDAP_SESSION *session,const char *userdn);
 
+/* use the user id to lookup an LDAP entry with the shadow attributes
+   requested*/
+MYLDAP_ENTRY *shadow_uid2entry(MYLDAP_SESSION *session,const char 
*username,int *rcp);
+
+/* return shadown information */
+void get_shadow_properties(MYLDAP_ENTRY *entry,long *lastchangedate,
+                           long *mindays,long *maxdays,long *warndays,
+                           long *inactdays,long *expiredate,unsigned long 
*flag);
+
 /* fallback definition of HOST_NAME_MAX */
 #ifndef HOST_NAME_MAX
 #ifdef _POSIX_HOST_NAME_MAX

Modified: nss-pam-ldapd/nslcd/pam.c
==============================================================================
--- nss-pam-ldapd/nslcd/pam.c   Sat Apr 30 11:15:09 2011        (r1445)
+++ nss-pam-ldapd/nslcd/pam.c   Sat Apr 30 16:37:43 2011        (r1446)
@@ -29,6 +29,7 @@
 #include <stdint.h>
 #endif /* HAVE_STDINT_H */
 #include <unistd.h>
+#include <time.h>
 
 #include "common.h"
 #include "log.h"
@@ -136,6 +137,98 @@
   }
 }
 
+static int check_shadow(MYLDAP_SESSION *session,const char *username,
+                        char *authzmsg,size_t authzmsgsz,
+                        int check_maxdays,int check_mindays)
+{
+  MYLDAP_ENTRY *entry=NULL;
+  long today,lastchangedate,mindays,maxdays,warndays,inactdays,expiredate;
+  unsigned long flag;
+  long daysleft,inactleft;
+  /* get the shadow entry */
+  entry=shadow_uid2entry(session,username,NULL);
+  if (entry==NULL)
+    return NSLCD_PAM_SUCCESS; /* no shadow entry found, nothing to check */
+  /* get today's date */
+  today=(long)(time(NULL)/(60*60*24));
+  /* get shadown information */
+  get_shadow_properties(entry,&lastchangedate,&mindays,&maxdays,&warndays,
+                        &inactdays,&expiredate,&flag);
+  /* check account expiry date */
+  if ((expiredate!=-1)&&(today>=expiredate))
+  {
+    daysleft=today-expiredate;
+    mysnprintf(authzmsg,authzmsgsz-1,"account expired %ld days ago",daysleft);
+    log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
+    return NSLCD_PAM_ACCT_EXPIRED;
+  }
+  /* password expiration isn't interesting at this point because the user
+     may not have authenticated with a password and if he did that would be
+     checked in the authc phase */
+  if (check_maxdays)
+  {
+    /* check lastchanged */
+    if (lastchangedate==0)
+    {
+      mysnprintf(authzmsg,authzmsgsz-1,"need a new password");
+      log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
+      return NSLCD_PAM_NEW_AUTHTOK_REQD;
+    }
+    else if (today<lastchangedate)
+      log_log(LOG_WARNING,"%s: password changed in the 
future",myldap_get_dn(entry));
+    else if (maxdays!=-1)
+    {
+      /* check maxdays */
+      daysleft=lastchangedate+maxdays-today;
+      if (daysleft==0)
+        mysnprintf(authzmsg,authzmsgsz-1,"password will expire today");
+      else if (daysleft<0)
+        mysnprintf(authzmsg,authzmsgsz-1,"password expired %ld days 
ago",-daysleft);
+      /* check inactdays */
+      if ((daysleft<=0)&&(inactdays!=-1))
+      {
+        inactleft=lastchangedate+maxdays+inactdays-today;
+        if (inactleft==0)
+          mysnprintf(authzmsg+strlen(authzmsg),authzmsgsz-strlen(authzmsg)-1,
+                     ", account will expire today");
+        else if (inactleft>0)
+          mysnprintf(authzmsg+strlen(authzmsg),authzmsgsz-strlen(authzmsg)-1,
+                     ", account will expire in %ld days",inactleft);
+        else
+        {
+          mysnprintf(authzmsg+strlen(authzmsg),authzmsgsz-strlen(authzmsg)-1,
+                     ", account expired %ld days ago",-inactleft);
+          log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
+          return NSLCD_PAM_AUTHTOK_EXPIRED;
+        }
+      }
+      if (daysleft<=0)
+      {
+        /* log previously built message */
+        log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
+        return NSLCD_PAM_NEW_AUTHTOK_REQD;
+      }
+      /* check warndays */
+      if ((warndays>0)&&(daysleft<=warndays))
+      {
+        mysnprintf(authzmsg,authzmsgsz-1,"password will expire in %ld 
days",daysleft);
+        log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
+      }
+    }
+  }
+  if (check_mindays)
+  {
+    daysleft=lastchangedate+mindays-today;
+    if ((mindays!=-1)&&(daysleft>0))
+    {
+      mysnprintf(authzmsg,authzmsgsz-1,"password cannot be changed for another 
%ld days",daysleft);
+      log_log(LOG_WARNING,"%s: %s",myldap_get_dn(entry),authzmsg);
+      return NSLCD_PAM_AUTHTOK_ERR;
+    }
+  }
+  return NSLCD_PAM_SUCCESS;
+}
+
 /* check authentication credentials of the user */
 int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session,uid_t calleruid)
 {
@@ -146,6 +239,9 @@
   char password[64];
   const char *userdn;
   MYLDAP_ENTRY *entry;
+  int authzrc=NSLCD_PAM_SUCCESS;
+  char authzmsg[1024];
+  authzmsg[0]='\0';
   /* read request parameters */
   READ_STRING(fp,username);
   SKIP_STRING(fp);
@@ -207,13 +303,16 @@
     case LDAP_INVALID_CREDENTIALS: rc=NSLCD_PAM_AUTH_ERR; break;
     default:                       rc=NSLCD_PAM_AUTH_ERR;
   }
+  /* perform shadow attribute checks */
+  if (*username!='\0')
+    authzrc=check_shadow(session,username,authzmsg,sizeof(authzmsg),0,0);
   /* write response */
   WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
   WRITE_STRING(fp,username);
   WRITE_STRING(fp,userdn);
-  WRITE_INT32(fp,rc);                 /* authc */
-  WRITE_INT32(fp,NSLCD_PAM_SUCCESS);  /* authz */
-  WRITE_STRING(fp,"");                /* authzmsg */
+  WRITE_INT32(fp,rc);
+  WRITE_INT32(fp,authzrc);
+  WRITE_STRING(fp,authzmsg);
   WRITE_INT32(fp,NSLCD_RESULT_END);
   return 0;
 }
@@ -344,6 +443,8 @@
   char servicename[64];
   char ruser[256],rhost[HOST_NAME_MAX+1],tty[64];
   MYLDAP_ENTRY *entry;
+  char authzmsg[1024];
+  authzmsg[0]='\0';
   /* read request parameters */
   READ_STRING(fp,username);
   SKIP_STRING(fp);
@@ -382,17 +483,19 @@
     WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
     WRITE_STRING(fp,username);
     WRITE_STRING(fp,"");
-    WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED);  /* authz */
-    WRITE_STRING(fp,"LDAP authorisation check failed"); /* authzmsg */
+    WRITE_INT32(fp,NSLCD_PAM_PERM_DENIED);
+    WRITE_STRING(fp,"LDAP authorisation check failed");
     WRITE_INT32(fp,NSLCD_RESULT_END);
     return 0;
   }
+  /* perform shadow attribute checks */
+  rc=check_shadow(session,username,authzmsg,sizeof(authzmsg),1,0);
   /* write response */
   WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
   WRITE_STRING(fp,username);
   WRITE_STRING(fp,myldap_get_dn(entry));
-  WRITE_INT32(fp,NSLCD_PAM_SUCCESS);  /* authz */
-  WRITE_STRING(fp,""); /* authzmsg */
+  WRITE_INT32(fp,rc);
+  WRITE_STRING(fp,authzmsg);
   WRITE_INT32(fp,NSLCD_RESULT_END);
   return 0;
 }
@@ -500,6 +603,8 @@
   char newpassword[64];
   const char *binddn=NULL; /* the user performing the modification */
   MYLDAP_ENTRY *entry;
+  char authzmsg[1024];
+  authzmsg[0]='\0';
   /* read request parameters */
   READ_STRING(fp,username);
   READ_STRING(fp,userdn); /* we can't ignore userdn for now here because we
@@ -539,7 +644,21 @@
     }
   }
   else
+  {
     binddn=myldap_get_dn(entry);
+    /* check whether shadow properties allow password change */
+    rc=check_shadow(session,username,authzmsg,sizeof(authzmsg),0,1);
+    if (rc!=NSLCD_PAM_SUCCESS)
+    {
+      WRITE_INT32(fp,NSLCD_RESULT_BEGIN);
+      WRITE_STRING(fp,username);
+      WRITE_STRING(fp,"");
+      WRITE_INT32(fp,rc);
+      WRITE_STRING(fp,authzmsg);
+      WRITE_INT32(fp,NSLCD_RESULT_END);
+      return 0;
+    }
+  }
   /* perform password modification */
   rc=try_pwmod(binddn,myldap_get_dn(entry),oldpassword,newpassword);
   /* write response */

Modified: nss-pam-ldapd/nslcd/shadow.c
==============================================================================
--- nss-pam-ldapd/nslcd/shadow.c        Sat Apr 30 11:15:09 2011        (r1445)
+++ nss-pam-ldapd/nslcd/shadow.c        Sat Apr 30 16:37:43 2011        (r1446)
@@ -164,9 +164,9 @@
     var=fallback; \
   }
 
-static void get_shadow_properties(MYLDAP_ENTRY *entry,long *lastchangedate,
-                                  long *mindays,long *maxdays,long *warndays,
-                                  long *inactdays,long *expiredate,unsigned 
long *flag)
+void get_shadow_properties(MYLDAP_ENTRY *entry,long *lastchangedate,
+                           long *mindays,long *maxdays,long *warndays,
+                           long *inactdays,long *expiredate,unsigned long 
*flag)
 {
   char buffer[80];
   const char *tmpvalue;
@@ -304,6 +304,40 @@
   return 0;
 }
 
+MYLDAP_ENTRY *shadow_uid2entry(MYLDAP_SESSION *session,const char 
*username,int *rcp)
+{
+  MYLDAP_SEARCH *search=NULL;
+  MYLDAP_ENTRY *entry=NULL;
+  const char *base;
+  char filter[1024];
+  int i;
+  /* if it isn't a valid username, just bail out now */
+  if (!isvalidname(username))
+  {
+    if (rcp!=NULL)
+      *rcp=LDAP_INVALID_SYNTAX;
+    return NULL;
+  }
+  /* we have to look up the entry */
+  mkfilter_shadow_byname(username,filter,sizeof(filter));
+  for (i=0;(i<NSS_LDAP_CONFIG_MAX_BASES)&&((base=shadow_bases[i])!=NULL);i++)
+  {
+    search=myldap_search(session,base,shadow_scope,filter,shadow_attrs,rcp);
+    if (search==NULL)
+    {
+      if ((rcp!=NULL)&&(*rcp==LDAP_SUCCESS))
+        *rcp=LDAP_NO_SUCH_OBJECT;
+      return NULL;
+    }
+    entry=myldap_get_entry(search,rcp);
+    if (entry!=NULL)
+      return entry;
+  }
+  if ((rcp!=NULL)&&(*rcp==LDAP_SUCCESS))
+    *rcp=LDAP_NO_SUCH_OBJECT;
+  return NULL;
+}
+
 NSLCD_HANDLE(
   shadow,byname,
   char name[256];
-- 
To unsubscribe send an email to
nss-pam-ldapd-commits-unsubscribe@lists.arthurdejong.org or see
http://lists.arthurdejong.org/nss-pam-ldapd-commits