*** src/backend/libpq/auth.c Mon Feb 25 15:07:33 2002 --- auth.c Mon Oct 28 20:34:06 2002 *************** *** 44,65 **** char *pg_krb_server_keyfile; #ifdef USE_PAM ! #include ! ! #define PGSQL_PAM_SERVICE "postgresql" /* Service name passed to PAM */ ! ! static int CheckPAMAuth(Port *port, char *user, char *password); ! static int pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, ! struct pam_response ** resp, void *appdata_ptr); ! ! static struct pam_conv pam_passw_conv = { ! &pam_passwd_conv_proc, ! NULL ! }; ! ! static char *pam_passwd = NULL; /* Workaround for Solaris 2.6 brokenness */ ! static Port *pam_port_cludge; /* Workaround for passing "Port *port" ! * into pam_passwd_conv_proc */ #endif /* USE_PAM */ #ifdef KRB4 --- 44,58 ---- char *pg_krb_server_keyfile; #ifdef USE_PAM ! #include ! ! /* Constants */ ! #define PGSQL_PAM_SERVICE "postgresql" /* Service name passed to PAM */ ! ! /* PAM functions */ ! static int doPAMAuth(Port *port, char *user, char *password); ! static int doPAMConversation(int num_msg, const struct pam_message **msg, ! struct pam_response **resp, void *appdata_ptr); #endif /* USE_PAM */ #ifdef KRB4 *************** *** 583,590 **** #ifdef USE_PAM case uaPAM: ! pam_port_cludge = port; ! status = CheckPAMAuth(port, port->user, ""); break; #endif /* USE_PAM */ --- 576,583 ---- #ifdef USE_PAM case uaPAM: ! sendAuthRequest(port, AUTH_REQ_PASSWORD); ! status = recv_and_check_password_packet(port); break; #endif /* USE_PAM */ *************** *** 625,823 **** #ifdef USE_PAM /* ! * PAM conversation function */ ! ! static int ! pam_passwd_conv_proc(int num_msg, const struct pam_message ** msg, struct pam_response ** resp, void *appdata_ptr) { ! StringInfoData buf; ! int32 len; ! ! if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) ! { ! switch (msg[0]->msg_style) ! { ! case PAM_ERROR_MSG: ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "pam_passwd_conv_proc: Error from underlying PAM layer: '%s'\n", msg[0]->msg); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return PAM_CONV_ERR; ! default: ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "pam_passwd_conv_proc: Unexpected PAM conversation %d/'%s'\n", ! msg[0]->msg_style, msg[0]->msg); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return PAM_CONV_ERR; ! } ! } ! ! if (!appdata_ptr) ! { ! /* ! * Workaround for Solaris 2.6 where the PAM library is broken and ! * does not pass appdata_ptr to the conversation routine ! */ ! appdata_ptr = pam_passwd; ! } ! ! /* ! * Password wasn't passed to PAM the first time around - let's go ask ! * the client to send a password, which we then stuff into PAM. ! */ ! if (strlen(appdata_ptr) == 0) ! { ! sendAuthRequest(pam_port_cludge, AUTH_REQ_PASSWORD); ! if (pq_eof() == EOF || pq_getint(&len, 4) == EOF) ! { ! return PAM_CONV_ERR; /* client didn't want to send password */ ! } ! ! initStringInfo(&buf); ! pq_getstr(&buf); ! if (DebugLvl > 5) ! fprintf(stderr, "received PAM packet with len=%d, pw=%s\n", ! len, buf.data); ! ! if (strlen(buf.data) == 0) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pam_passwd_conv_proc: no password\n"); ! fputs(PQerrormsg, stderr); ! return PAM_CONV_ERR; ! } ! appdata_ptr = buf.data; ! } ! ! /* ! * Explicitly not using palloc here - PAM will free this memory in ! * pam_end() ! */ ! *resp = calloc(num_msg, sizeof(struct pam_response)); ! if (!*resp) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, "pam_passwd_conv_proc: Out of memory!\n"); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! if (buf.data) ! pfree(buf.data); ! return PAM_CONV_ERR; ! } ! ! (*resp)[0].resp = strdup((char *) appdata_ptr); ! (*resp)[0].resp_retcode = 0; ! ! return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR); } /* * Check authentication against PAM. */ ! static int ! CheckPAMAuth(Port *port, char *user, char *password) { ! int retval; ! pam_handle_t *pamh = NULL; ! ! /* ! * Apparently, Solaris 2.6 is broken, and needs ugly static variable ! * workaround ! */ ! pam_passwd = password; ! ! /* ! * Set the application data portion of the conversation struct This is ! * later used inside the PAM conversation to pass the password to the ! * authentication module. ! */ ! pam_passw_conv.appdata_ptr = (char *) password; /* from password above, ! * not allocated */ ! ! /* Optionally, one can set the service name in pg_hba.conf */ ! if (port->auth_arg[0] == '\0') ! retval = pam_start(PGSQL_PAM_SERVICE, "pgsql@", &pam_passw_conv, &pamh); ! else ! retval = pam_start(port->auth_arg, "pgsql@", &pam_passw_conv, &pamh); ! ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "CheckPAMAuth: Failed to create PAM authenticator: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! pam_passwd = NULL; /* Unset pam_passwd */ ! return STATUS_ERROR; ! } ! ! retval = pam_set_item(pamh, PAM_USER, user); ! ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "CheckPAMAuth: pam_set_item(PAM_USER) failed: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! pam_passwd = NULL; /* Unset pam_passwd */ ! return STATUS_ERROR; ! } ! ! retval = pam_set_item(pamh, PAM_CONV, &pam_passw_conv); ! ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "CheckPAMAuth: pam_set_item(PAM_CONV) failed: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! pam_passwd = NULL; /* Unset pam_passwd */ ! return STATUS_ERROR; ! } ! ! retval = pam_authenticate(pamh, 0); ! ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "CheckPAMAuth: pam_authenticate failed: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! pam_passwd = NULL; /* Unset pam_passwd */ ! return STATUS_ERROR; ! } ! ! retval = pam_acct_mgmt(pamh, 0); ! ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "CheckPAMAuth: pam_acct_mgmt failed: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! pam_passwd = NULL; /* Unset pam_passwd */ ! return STATUS_ERROR; ! } ! ! retval = pam_end(pamh, retval); ! ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "CheckPAMAuth: Failed to release PAM authenticator: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! } ! ! pam_passwd = NULL; /* Unset pam_passwd */ ! ! return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR); } #endif /* USE_PAM */ --- 618,729 ---- #ifdef USE_PAM /* ! * PAM conversation function - Not really doing any conversation here just ! * shoving the password into PAM */ ! static int doPAMConversation(int num_msg, const struct pam_message **msg, ! struct pam_response **resp, void *appdata_ptr) { ! if (num_msg != 1 || msg[0]->msg_style != PAM_PROMPT_ECHO_OFF) ! { ! switch (msg[0]->msg_style) ! { ! case PAM_ERROR_MSG: ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMConversation: Error from underlying PAM layer: '%s'\n", ! msg[0]->msg); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return PAM_CONV_ERR; ! ! default: ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMConversation: Unexpected PAM conversation %d/'%s'\n", ! msg[0]->msg_style, msg[0]->msg); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return PAM_CONV_ERR; ! } ! } ! ! /* ! * Explicitly not using palloc here - PAM will free this memory in ! * pam_end() ! */ ! *resp = calloc(num_msg, sizeof(struct pam_response)); ! if (!*resp) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMConversation: Out of memory!\n"); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return PAM_CONV_ERR; ! } ! (*resp)[0].resp = strdup((char *) appdata_ptr); ! (*resp)[0].resp_retcode = 0; ! return ((*resp)[0].resp ? PAM_SUCCESS : PAM_CONV_ERR); } /* * Check authentication against PAM. */ ! static int doPAMAuth(Port *port, char *user, char *password) { ! int retval; ! pam_handle_t *pamh = NULL; ! struct pam_conv pam_conversation = { &doPAMConversation, password }; ! ! /* Start PAM */ ! if (port->auth_arg[0] == '\0') ! retval = pam_start(PGSQL_PAM_SERVICE, user, &pam_conversation, &pamh); ! else ! retval = pam_start(port->auth_arg, user, &pam_conversation, &pamh); ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMAuth: Failed to create PAM authenticator: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return STATUS_ERROR; ! } ! ! /* Do the authentication */ ! retval = pam_authenticate(pamh, 0); ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMAuth: pam_authenticate failed: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return STATUS_ERROR; ! } ! ! /* Do account management */ ! retval = pam_acct_mgmt(pamh, 0); ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMAuth: pam_acct_mgmt failed: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! return STATUS_ERROR; ! } ! ! /* Cleanup */ ! retval = pam_end(pamh, retval); ! if (retval != PAM_SUCCESS) ! { ! snprintf(PQerrormsg, PQERRORMSG_LENGTH, ! "doPAMAuth: Failed to release PAM authenticator: '%s'\n", ! pam_strerror(pamh, retval)); ! fputs(PQerrormsg, stderr); ! pqdebug("%s", PQerrormsg); ! } ! return (retval == PAM_SUCCESS ? STATUS_OK : STATUS_ERROR); } #endif /* USE_PAM */ *************** *** 846,852 **** --- 752,762 ---- fprintf(stderr, "received password packet with len=%d, pw=%s\n", len, buf.data); + #ifndef USE_PAM result = checkPassword(port, port->user, buf.data); + #else + result = doPAMAuth(port, port->user, buf.data); + #endif pfree(buf.data); return result; }