diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2009-05-08 22:55:24 +0000 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2009-05-08 22:55:24 +0000 |
commit | 57af21c442f9dbd61525ba2ba77afc93dfcf81c3 (patch) | |
tree | d44875c4aedcb2d39a9361e9fe7f376bd2baddf0 | |
parent | 5ccf22cdedf722d0de4ff283a85ee6575bb2e600 (diff) |
set up basic PAM protocol handling and get authentication call working by binding to the server
git-svn-id: http://arthurdejong.org/svn/nss-pam-ldapd/nss-pam-ldapd@870 ef36b2f9-881f-0410-afb5-c4e39611909c
-rw-r--r-- | nslcd/common.h | 4 | ||||
-rw-r--r-- | nslcd/myldap.c | 29 | ||||
-rw-r--r-- | nslcd/myldap.h | 7 | ||||
-rw-r--r-- | nslcd/pam.c | 290 | ||||
-rw-r--r-- | nslcd/passwd.c | 10 |
5 files changed, 228 insertions, 112 deletions
diff --git a/nslcd/common.h b/nslcd/common.h index d1c4c50..6013fa0 100644 --- a/nslcd/common.h +++ b/nslcd/common.h @@ -79,6 +79,10 @@ int read_address(TFILE *fp,char *addr,int *addrlen,int *af); /* checks to see if the specified string is a valid user or group name */ MUST_USE int isvalidname(const char *name); +/* Perform an LDAP lookup to translate the DN into a uid. + This function either returns NULL or a strdup()ed string. */ +char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn,int *rcp); + /* transforms the DN info a uid doing an LDAP lookup if needed */ MUST_USE char *dn2uid(MYLDAP_SESSION *session,const char *dn,char *buf,size_t buflen); diff --git a/nslcd/myldap.c b/nslcd/myldap.c index f4f4980..2afb8af 100644 --- a/nslcd/myldap.c +++ b/nslcd/myldap.c @@ -96,6 +96,10 @@ struct ldap_session { /* the connection */ LDAP *ld; + /* the username to bind with */ + char binddn[256]; + /* the password to bind with if any */ + char bindpw[64]; /* timestamp of last activity */ time_t lastactivity; /* index into ldc_uris: currently connected LDAP uri */ @@ -277,6 +281,8 @@ static MYLDAP_SESSION *myldap_session_new(void) } /* initialize the session */ session->ld=NULL; + session->binddn[0]='\0'; + session->bindpw[0]='\0'; session->lastactivity=0; session->current_uri=0; for (i=0;i<MAX_SEARCHES_IN_SESSION;i++) @@ -371,6 +377,7 @@ static int do_bind(MYLDAP_SESSION *session,const char *uri) #ifndef HAVE_SASL_INTERACT_T struct berval cred; #endif /* not HAVE_SASL_INTERACT_T */ +#endif /* HAVE_LDAP_SASL_INTERACTIVE_BIND_S */ #ifdef LDAP_OPT_X_TLS /* check if StartTLS is requested */ if (nslcd_cfg->ldc_ssl_on==SSL_START_TLS) @@ -386,6 +393,15 @@ static int do_bind(MYLDAP_SESSION *session,const char *uri) } } #endif /* LDAP_OPT_X_TLS */ + /* check if the binddn and bindpw are overwritten in the session */ + if (session->binddn[0]!='\0') + { + /* do a simple bind */ + log_log(LOG_DEBUG,"ldap_simple_bind_s(\"%s\",%s) (uri=\"%s\")",session->binddn, + (session->bindpw[0]!='\0')?"\"*****\"":"empty",uri); + return ldap_simple_bind_s(session->ld,session->binddn,session->bindpw); + } +#ifdef HAVE_LDAP_SASL_INTERACTIVE_BIND_S /* TODO: store this information in the session */ if (!nslcd_cfg->ldc_usesasl) { @@ -670,6 +686,19 @@ static int do_open(MYLDAP_SESSION *session) return LDAP_SUCCESS; } +/* Set alternative credentials for the session. */ +int myldap_set_credentials(MYLDAP_SESSION *session,const char *dn, + const char *password) +{ + /* copy dn and password into session */ + strncpy(session->binddn,dn,sizeof(session->binddn)); + session->binddn[sizeof(session->binddn)-1]='\0'; + strncpy(session->bindpw,password,sizeof(session->bindpw)); + session->bindpw[sizeof(session->bindpw)-1]='\0'; + /* try to open a connection */ + return do_open(session); +} + static int do_try_search(MYLDAP_SEARCH *search) { int rc; diff --git a/nslcd/myldap.h b/nslcd/myldap.h index 01ee55d..c990e86 100644 --- a/nslcd/myldap.h +++ b/nslcd/myldap.h @@ -68,6 +68,11 @@ typedef struct myldap_entry MYLDAP_ENTRY; uses the configuration to find the URLs to attempt connections to. */ MUST_USE MYLDAP_SESSION *myldap_create_session(void); +/* Set alternative credentials for the session and try to open a connection + with those credentials. Returns an LDAP status code. */ +int myldap_set_credentials(MYLDAP_SESSION *session,const char *dn, + const char *password); + /* Closes all pending searches and deallocates any memory that is allocated with these searches. This does not close the session. */ void myldap_session_cleanup(MYLDAP_SESSION *session); @@ -122,7 +127,7 @@ MUST_USE const char *myldap_cpy_rdn_value(const char *dn,const char *attr, /* Escapes characters in a string for use in a search filter. */ MUST_USE int myldap_escape(const char *src,char *buffer,size_t buflen); -/* Set the debug level globally. */ +/* Set the debug level globally. Returns an LDAP status code. */ int myldap_set_debuglevel(int i); #endif /* not _MYLDAP_H */ diff --git a/nslcd/pam.c b/nslcd/pam.c index 91a6416..33b6699 100644 --- a/nslcd/pam.c +++ b/nslcd/pam.c @@ -34,159 +34,231 @@ #include "myldap.h" #include "cfg.h" -/* for PAM status codes */ -#include <security/pam_modules.h> + +/* set up a connection and try to bind with the specified DN and password + returns a NSLCD_PAM_* error code */ +static int try_bind(const char *userdn,const char *password) +{ + MYLDAP_SESSION *session; + char *username; + int rc; + /* set up a new connection */ + session=myldap_create_session(); + if (session==NULL) + return NSLCD_PAM_AUTH_ERR; + /* set up credentials for the session */ + rc=myldap_set_credentials(session,userdn,password); + /* TODO: test rc */ + if (rc==LDAP_SUCCESS) + { + /* perform search for own object */ + username=lookup_dn2uid(session,userdn,&rc); + /* TODO: return this as cannonical name */ + if (username!=NULL) + free(username); + } + /* close the session */ + myldap_session_close(session); + /* handle the results */ + switch(rc) + { + case LDAP_SUCCESS: return NSLCD_PAM_SUCCESS; + case LDAP_INVALID_CREDENTIALS: return NSLCD_PAM_AUTH_ERR; + default: return NSLCD_PAM_AUTH_ERR; + } +} /* check authentication credentials of the user */ int nslcd_pam_authc(TFILE *fp,MYLDAP_SESSION *session) { - /* define common variables */ int32_t tmpint32; - MYLDAP_SEARCH *search; - MYLDAP_ENTRY *entry; - int rc=PAM_AUTH_ERR; - char uid[256]; - char svc[256]; - char pwd[256]; + int rc; + char username[256]; char userdn[256]; + char servicename[64]; + char password[64]; /* read request parameters */ - READ_STRING_BUF2(fp,uid,sizeof(uid)); - if (!isvalidname(uid)) { - log_log(LOG_WARNING,"nslcd_pam_authc(%s): invalid user name",uid); - /* write a response message anyway */ - /* TODO: probably just write NSLCD_RESULT_END to indicate failure */ - WRITE_INT32(fp,NSLCD_VERSION); - WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC); - WRITE_INT32(fp,NSLCD_RESULT_BEGIN); - WRITE_INT32(fp,PAM_USER_UNKNOWN); /* authok */ - WRITE_INT32(fp,PAM_SUCCESS); /* authz */ - WRITE_STRING(fp,""); /* dn */ - WRITE_STRING(fp,""); /* authzmsg */ - WRITE_STRING(fp,""); /* tmpluser */ - return -1; - } - READ_STRING_BUF2(fp,svc,sizeof(svc)); - READ_STRING_BUF2(fp,pwd,sizeof(pwd)); + READ_STRING_BUF2(fp,username,sizeof(username)); + READ_STRING_BUF2(fp,userdn,sizeof(userdn)); + READ_STRING_BUF2(fp,servicename,sizeof(servicename)); + READ_STRING_BUF2(fp,password,sizeof(password)); /* log call */ - log_log(LOG_DEBUG,"nslcd_pam_authc(%s,%s,passwd)",uid,svc); + log_log(LOG_DEBUG,"nslcd_pam_authc(\"%s\",\"%s\",\"%s\")",username,userdn,servicename); /* write the response header */ WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHC); - /* set up a new connection */ - - /* FIXME: implement setting up connection, perform uid->DN expansion - and bind with DN and pwd */ - - /* maye use existing session for uid2dn lookup and make new connection - just for binding, also be sure to clean up session (probably set up a - session here, call another function to get the results, etc) */ - - /* perform uid to DN translation */ - if (uid2dn(session,uid,userdn,sizeof(userdn))==NULL) + /* validate request */ + if (!isvalidname(username)) { - log_log(LOG_WARNING,"nslcd_pam_authc(%s): user not found",uid); - /* return error to client */ - /* FIXME: probably return NSLCD_RESULT_END instead */ + log_log(LOG_WARNING,"nslcd_pam_authc(\"%s\"): invalid user name",username); + /* write a response message anyway */ + /* TODO: maybe just write NSLCD_RESULT_END to indicate failure */ WRITE_INT32(fp,NSLCD_RESULT_BEGIN); - WRITE_INT32(fp,PAM_USER_UNKNOWN); /* authok */ - WRITE_INT32(fp,PAM_SUCCESS); /* authz */ - WRITE_STRING(fp,""); /* dn */ - WRITE_STRING(fp,""); /* authzmsg */ - WRITE_STRING(fp,""); /* tmpluser */ + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authc */ + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authz */ + WRITE_STRING(fp,"invalid username"); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); return -1; } - - /* TODO: perform bind - - switch(rs.sr_err) { - case LDAP_SUCCESS: rc = PAM_SUCCESS; break; - case LDAP_INVALID_CREDENTIALS: rc = PAM_AUTH_ERR; break; - default: rc = PAM_AUTH_ERR; break; - }*/ - + if (userdn[0]=='\0') + { + /* perform username to DN translation */ + if (uid2dn(session,username,userdn,sizeof(userdn))==NULL) + { + log_log(LOG_WARNING,"nslcd_pam_authc(\"%s\"): user not found",username); + /* return error to client */ + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authc */ + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authz */ + WRITE_STRING(fp,"unknown username"); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); + return -1; + } + } + /* try authentication */ + rc=try_bind(userdn,password); + /* write response */ WRITE_INT32(fp,NSLCD_RESULT_BEGIN); - WRITE_INT32(fp,rc); /* authok */ - WRITE_INT32(fp,PAM_SUCCESS); /* authz */ - WRITE_STRING(fp,userdn); /* dn */ - WRITE_STRING(fp,""); /* authzmsg */ - WRITE_STRING(fp,""); /* tmpluser */ - + WRITE_STRING(fp,username); /* TODO: get canonical name */ + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,rc); /* authc */ + WRITE_INT32(fp,rc); /* authz */ + WRITE_STRING(fp,""); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); return 0; } /* check authorisation of the user */ int nslcd_pam_authz(TFILE *fp,MYLDAP_SESSION *session) { -/* - struct berval dn, svc; - struct berval authzmsg = BER_BVNULL; int32_t tmpint32; - char dnc[1024]; - char svcc[256]; - - READ_STRING_BUF2(fp,dnc,sizeof(dnc)); - dn.bv_val = dnc; - dn.bv_len = tmpint32; - READ_STRING_BUF2(fp,svcc,sizeof(svcc)); - svc.bv_val = svcc; - svc.bv_len = tmpint32; - - Debug(LDAP_DEBUG_TRACE,"nssov_pam_authz(%s)\n",dn.bv_val,0,0); - + int rc; + char username[256]; + char userdn[256]; + char servicename[64]; + /* read request parameters */ + READ_STRING_BUF2(fp,username,sizeof(username)); + READ_STRING_BUF2(fp,userdn,sizeof(userdn)); + READ_STRING_BUF2(fp,servicename,sizeof(servicename)); + /* log call */ + log_log(LOG_DEBUG,"nslcd_pam_authz(\"%s\",\"%s\",\"%s\")",username,userdn,servicename); + /* write the response header */ WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_AUTHZ); + /* validate request */ + if (!isvalidname(username)) + { + log_log(LOG_WARNING,"nslcd_pam_authc(\"%s\"): invalid user name",username); + /* write a response message anyway */ + /* TODO: maybe just write NSLCD_RESULT_END to indicate failure */ + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authz */ + WRITE_STRING(fp,"invalid username"); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); + return -1; + } + if (userdn[0]=='\0') + { + /* perform username to DN translation */ + if (uid2dn(session,username,userdn,sizeof(userdn))==NULL) + { + log_log(LOG_WARNING,"nslcd_pam_authc(\"%s\"): user not found",username); + /* return error to client */ + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authz */ + WRITE_STRING(fp,"unknown username"); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); + return -1; + } + } + /* try dn to username lookup */ + if (dn2uid(session,userdn,username,sizeof(username))==NULL) + { + log_log(LOG_WARNING,"nslcd_pam_authc(\"%s\"): username not found",userdn); + /* return error to client */ + WRITE_INT32(fp,NSLCD_RESULT_BEGIN); + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,NSLCD_PAM_USER_UNKNOWN); /* authz */ + WRITE_STRING(fp,"unknown username"); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); + return -1; + } + /* write response */ WRITE_INT32(fp,NSLCD_RESULT_BEGIN); - WRITE_INT32(fp,PAM_SUCCESS); - WRITE_BERVAL(fp,&authzmsg); -*/ + WRITE_STRING(fp,username); + WRITE_STRING(fp,userdn); + WRITE_INT32(fp,rc); /* authz */ + WRITE_STRING(fp,""); /* authzmsg */ + WRITE_INT32(fp,NSLCD_RESULT_END); return 0; } int nslcd_pam_sess_o(TFILE *fp,MYLDAP_SESSION *session) { -/* - struct berval dn, svc; int32_t tmpint32; - char dnc[1024]; - char svcc[256]; - - READ_STRING_BUF2(fp,dnc,sizeof(dnc)); - dn.bv_val = dnc; - dn.bv_len = tmpint32; - READ_STRING_BUF2(fp,svcc,sizeof(svcc)); - svc.bv_val = svcc; - svc.bv_len = tmpint32; - - Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_o(%s)\n",dn.bv_val,0,0); - + int rc; + char username[256]; + char userdn[256]; + char servicename[64]; + char tty[64],rhost[64],ruser[256]; + int32_t sessionid; + /* read request parameters */ + READ_STRING_BUF2(fp,username,sizeof(username)); + READ_STRING_BUF2(fp,userdn,sizeof(userdn)); + READ_STRING_BUF2(fp,servicename,sizeof(servicename)); + READ_STRING_BUF2(fp,tty,sizeof(tty)); + READ_STRING_BUF2(fp,rhost,sizeof(rhost)); + READ_STRING_BUF2(fp,ruser,sizeof(ruser)); + READ_INT32(fp,sessionid); + /* log call */ + log_log(LOG_DEBUG,"nslcd_pam_sess_o(\"%s\",\"%s\",\"%s\",\"%s\",\"%s\",\"%s\")", + username,userdn,servicename,tty,rhost,ruser); + /* write the response header */ WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_O); + /* write response */ WRITE_INT32(fp,NSLCD_RESULT_BEGIN); -*/ + WRITE_INT32(fp,12345); /* session id */ + WRITE_INT32(fp,NSLCD_RESULT_END); return 0; } int nslcd_pam_sess_c(TFILE *fp,MYLDAP_SESSION *session) { -/* - struct berval dn, svc; int32_t tmpint32; - char dnc[1024]; - char svcc[256]; - - READ_STRING_BUF2(fp,dnc,sizeof(dnc)); - dn.bv_val = dnc; - dn.bv_len = tmpint32; - READ_STRING_BUF2(fp,svcc,sizeof(svcc)); - svc.bv_val = svcc; - svc.bv_len = tmpint32; - - Debug(LDAP_DEBUG_TRACE,"nssov_pam_sess_c(%s)\n",dn.bv_val,0,0); - + int rc; + char username[256]; + char userdn[256]; + char servicename[64]; + char tty[64],rhost[64],ruser[256]; + int32_t sessionid; + /* read request parameters */ + READ_STRING_BUF2(fp,username,sizeof(username)); + READ_STRING_BUF2(fp,userdn,sizeof(userdn)); + READ_STRING_BUF2(fp,servicename,sizeof(servicename)); + READ_STRING_BUF2(fp,tty,sizeof(tty)); + READ_STRING_BUF2(fp,rhost,sizeof(rhost)); + READ_STRING_BUF2(fp,ruser,sizeof(ruser)); + READ_INT32(fp,sessionid); + /* log call */ + log_log(LOG_DEBUG,"nslcd_pam_sess_c(\"%s\",\"%s\",\"%s\",%d)", + username,userdn,servicename,(int)sessionid); + /* write the response header */ WRITE_INT32(fp,NSLCD_VERSION); WRITE_INT32(fp,NSLCD_ACTION_PAM_SESS_C); + /* write response */ WRITE_INT32(fp,NSLCD_RESULT_BEGIN); -*/ + WRITE_INT32(fp,0); /* session id */ + WRITE_INT32(fp,NSLCD_RESULT_END); return 0; } diff --git a/nslcd/passwd.c b/nslcd/passwd.c index a8cc603..1f2f657 100644 --- a/nslcd/passwd.c +++ b/nslcd/passwd.c @@ -139,7 +139,7 @@ struct dn2uid_cache_entry /* Perform an LDAP lookup to translate the DN into a uid. This function either returns NULL or a strdup()ed string. */ -static char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn) +char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn,int *rcp) { MYLDAP_SEARCH *search; MYLDAP_ENTRY *entry; @@ -147,6 +147,8 @@ static char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn) int rc; const char **values; char *uid; + if (rcp!=NULL) + *rcp=LDAP_SUCCESS; /* we have to look up the entry */ attrs[0]=attmap_passwd_uid; attrs[1]=NULL; @@ -160,7 +162,11 @@ static char *lookup_dn2uid(MYLDAP_SESSION *session,const char *dn) if (entry==NULL) { if (rc!=LDAP_SUCCESS) + { log_log(LOG_WARNING,"lookup of user %s failed: %s",dn,ldap_err2string(rc)); + if (rcp!=NULL) + *rcp=rc; + } return NULL; } /* get uid (just use first one) */ @@ -213,7 +219,7 @@ char *dn2uid(MYLDAP_SESSION *session,const char *dn,char *buf,size_t buflen) } pthread_mutex_unlock(&dn2uid_cache_mutex); /* look up the uid using an LDAP query */ - uid=lookup_dn2uid(session,dn); + uid=lookup_dn2uid(session,dn,NULL); /* store the result in the cache */ pthread_mutex_lock(&dn2uid_cache_mutex); if (cacheentry==NULL) |