Hi Ingo Thanks for your quick reply! I could trace the problem down to pam_unix.so not liking a NULL pointer instead of a username. > > I am not sure if this is a mod_auth_pam or a Solaris pam problem. If > > the process goes crazy nothing is logged at all, neither by > > mod_auth_pam nor by pam_unix.so.1. > > No username is a fairly normal condition, e.g., it can happen when the > user terminates the browsers password dialog. I get it during testing > (on Linux) regularly and the web-server didn't crash so I would be > surprised if its a mod_auth_pam problem. You are right, it's not a mod_auth_pam problem. > Looking at the trace from the crashed server, I can only make a few > guesses" "pam.conf" is opened and "pam_unix.so.1" is opened > afterwards, so that means that the basic PAM initialization worked. > After that, "libcmd.so.1" is opened. Do you know what that library > does? From the name, I would assume it has something to do with > running commands. I have no clue, but share your assumption. > Are you using /etc/shadow? In that case, > Solaris-PAM is probably running some helper application to check the > passwords. Maybe that helper has problems checking an 'empty' > username? Even worse, we are using NIS+ ;-) > Could you trace some other application (preferably one not running as > root) and compare the results? I would really like to find out what > kind of problem that is. Did you check Suns erratas already? Yes, but I could not find anything. Now, let me explain what I did: With the attached source (check_user.c) I can reproduce the behaviour on my machine. Just define SOLARIS8_CRASH, call check_user without a username, the binary hangs and you can see your memory melt. I assume you cannot reproduce this on your linux box, can you? But then it's not clear yet if it's because you are using linux-pam or because you are (probably) not using NIS+. > Anyway, an empty username is not really usefull (whereas an empty > password could be) so I implemented a small change that checks wether > the username is empty before proceeding and refuses the request > completely in case it is. Please try it to see wether it helps. Yes, it helps. As you can see the conversion function I copied into my little test app does a similar check. So it's not that uncommon in the PAM world. Thanks a lot again for your help and the patch! Regards Thomas PS: I also noticed a Mozilla 1.0 bug: if you leave the username empty once, you have no chance to reenter username/password later on. You won't see the password dialog ever, not even after a reload of the page. You have to close/reopen Mozilla. This does not happen with other browsers.
/* This code is a compilation of the check_user.c file from Linux-PAM (http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/pam/Linux-PAM/examples/check_user.c) and the conversation function is taken from the freebsd distro (http://www.freebsd.org/doc/en_US.ISO8859-1/articles/pam/pam-sample-conv.html) compile with: gcc -lpam check_user.c -o check_user You need to add the following (or equivalent) to the /etc/pam.conf file. # check authorization check auth required /usr/lib/security/$ISA/pam_unix.so.1 check account required /usr/lib/security/$ISA/pam_unix.so.1 define SOLARIS8_CRASH (see below), and Solaris will crash if you do not supply a username Thomas Werschlein, 09/13/2002 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <security/pam_appl.h> /* if I define this and do not supply a username this will crash my solaris 8 host (look at top and see how the process is eating up all memory!) */ //#define SOLARIS8_CRASH 1 int converse(int n, const struct pam_message **msg, struct pam_response **resp, void *data) { char buf[PAM_MAX_RESP_SIZE]; int i; data = data; if (n <= 0 || n > PAM_MAX_NUM_MSG) return (PAM_CONV_ERR); if ((*resp = calloc(n, sizeof **resp)) == NULL) return (PAM_BUF_ERR); for (i = 0; i < n; ++i) { resp[i]->resp_retcode = 0; resp[i]->resp = NULL; switch (msg[i]->msg_style) { case PAM_PROMPT_ECHO_OFF: resp[i]->resp = strdup(getpass(msg[i]->msg)); if (resp[i]->resp == NULL) goto fail; break; case PAM_PROMPT_ECHO_ON: #ifdef SOLARIS8_CRASH resp[i]->resp = NULL; #else fputs(msg[i]->msg, stderr); if (fgets(buf, sizeof buf, stdin) == NULL) goto fail; resp[i]->resp = strdup(buf); if (resp[i]->resp == NULL) goto fail; #endif break; case PAM_ERROR_MSG: fputs(msg[i]->msg, stderr); if (strlen(msg[i]->msg) > 0 && msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n') fputc('\n', stderr); break; case PAM_TEXT_INFO: fputs(msg[i]->msg, stdout); if (strlen(msg[i]->msg) > 0 && msg[i]->msg[strlen(msg[i]->msg) - 1] != '\n') fputc('\n', stdout); break; default: goto fail; } } return (PAM_SUCCESS); fail: while (i) free(resp[--i]); free(*resp); *resp = NULL; return (PAM_CONV_ERR); } static struct pam_conv conv = { converse, NULL }; int main(int argc, char *argv[]) { pam_handle_t *pamh=NULL; int retval; const char *user=""; if(argc == 2) { user = argv[1]; } if(argc > 2) { fprintf(stderr, "Usage: check_user [username]\n"); exit(1); } retval = pam_start("check", user, &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. */ if (retval == PAM_SUCCESS) { fprintf(stdout, "Authenticated\n"); } else { fprintf(stdout, "Not Authenticated\n"); } if (pam_end(pamh,retval) != PAM_SUCCESS) { /* close Linux-PAM */ pamh = NULL; fprintf(stderr, "check_user: failed to release authenticator\n"); exit(1); } return ( retval == PAM_SUCCESS ? 0:1 ); /* indicate success */ }