--- cvs-1.11.1p1.orig/src/Makefile.in +++ cvs-1.11.1p1/src/Makefile.in @@ -180,7 +180,7 @@ cvs_LDADD = \ ../diff/libdiff.a \ ../lib/libcvs.a \ - ../zlib/libz.a \ + -lz -ldl -lpam \ version.o cvs_EXTRA_DIST = version.c --- cvs-1.11.1p1.orig/src/server.c +++ cvs-1.11.1p1/src/server.c @@ -16,6 +16,13 @@ #include "getline.h" #include "buffer.h" +#define HAVE_PAM + +#ifdef HAVE_PAM +#include +#include +#endif + #if defined(SERVER_SUPPORT) || defined(CLIENT_SUPPORT) # ifdef HAVE_GSSAPI /* This stuff isn't included solely with SERVER_SUPPORT since some of these @@ -5526,6 +5536,106 @@ return retval; } +#ifdef HAVE_PAM +/* The callback function that the pam modules will use to talk to + us. Modelled closely on the misc_conv module of Linux-PAM. This + blatantly subverts one of the principles of PAM - PAM is meant to + handle all the password work. Bu this does the job and means I can + transition to LDAP right now. */ +int cvs_conv(int num_msg, const struct pam_message **msgm, + struct pam_response **response, void *appdata_ptr) +{ + int count=0; + struct pam_response *reply; + + if (num_msg <= 0) + return PAM_CONV_ERR; + + reply = (struct pam_response *) calloc(num_msg, + sizeof(struct pam_response)); + if (reply == NULL) + return PAM_CONV_ERR; + + for (count=0; count < num_msg; ++count) + { + char *string=NULL; + + switch (msgm[count]->msg_style) + { + case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_ON: + string = (char *)appdata_ptr; + break; + default: + break; + } + + if (string) /* must add to reply array */ + { + /* add string to list of responses */ + reply[count].resp_retcode = 0; + reply[count].resp = string; + string = NULL; + } + } + + *response = reply; + reply = NULL; + + return PAM_SUCCESS; +} + +static struct pam_conv conv = { + cvs_conv, + NULL +}; + +/* Modelled very closely on the example code in "The Linux-PAM + Application Developers' Guide" by Andrew G. Morgan. */ +static int +check_pam_password (username, password, repository, host_user_ptr) + char *username, *password, *repository, **host_user_ptr; +{ + pam_handle_t *pamh=NULL; + int retval; + int rc = 0; + + conv.appdata_ptr = password; + + retval = pam_start("cvs", username, &conv, &pamh); + + if (retval == PAM_SUCCESS) + retval = pam_authenticate(pamh, 0); /* is user really user? */ + + if (retval == PAM_SUCCESS) + retval = pam_acct_mgmt(pamh, 0); /* permitted access? */ + + /* This is where we have been authorized or not. */ + + switch(retval) + { + case PAM_SUCCESS: + *host_user_ptr = xstrdup(username); + rc = 1; + break; + case PAM_AUTH_ERR: + *host_user_ptr = NULL; + rc = 2; + break; + default: + *host_user_ptr = NULL; + rc = 0; + break; + } + + if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close PAM */ + pamh = NULL; + fprintf(stderr, "failed to release authenticator\n"); + } + + return rc; /* indicate success */ +} +#endif /* HAVE_PAM */ /* Return a hosting username if password matches, else NULL. */ static char * @@ -5552,6 +5662,24 @@ /* host_user already set by reference, so just return. */ goto handle_return; } + +#ifdef HAVE_PAM + else if(rc == 0 && system_auth) + { + rc = check_pam_password (username, password, repository, + &host_user); + if (rc == 2) + return NULL; + + /* else */ + + if (rc == 1) + { + /* host_user already set by reference, so just return. */ + goto handle_return; + } + } +#else /* HAVE_PAM */ else if (rc == 0 && system_auth) { /* No cvs password found, so try /etc/passwd. */ @@ -5613,6 +5741,7 @@ goto handle_return; } } +#endif /* HAVE_PAM */ else if (rc == 0) { /* Note that the message _does_ distinguish between the case in