88 *
99 *
1010 * IDENTIFICATION
11- * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.186 2009/10/14 22:09:46 heikki Exp $
11+ * $PostgreSQL: pgsql/src/backend/libpq/auth.c,v 1.187 2009/10/16 22:08:36 tgl Exp $
1212 *
1313 *-------------------------------------------------------------------------
1414 */
@@ -452,7 +452,6 @@ ClientAuthentication(Port *port)
452452
453453case uaPAM :
454454#ifdef USE_PAM
455- pam_port_cludge = port ;
456455status = CheckPAMAuth (port ,port -> user_name ,"" );
457456#else
458457Assert (false);
@@ -1888,72 +1887,103 @@ static int
18881887pam_passwd_conv_proc (int num_msg ,const struct pam_message * * msg ,
18891888struct pam_response * * resp ,void * appdata_ptr )
18901889{
1891- if (num_msg != 1 || msg [0 ]-> msg_style != PAM_PROMPT_ECHO_OFF )
1892- {
1893- switch (msg [0 ]-> msg_style )
1894- {
1895- case PAM_ERROR_MSG :
1896- ereport (LOG ,
1897- (errmsg ("error from underlying PAM layer: %s" ,
1898- msg [0 ]-> msg )));
1899- return PAM_CONV_ERR ;
1900- default :
1901- ereport (LOG ,
1902- (errmsg ("unsupported PAM conversation %d/%s" ,
1903- msg [0 ]-> msg_style ,msg [0 ]-> msg )));
1904- return PAM_CONV_ERR ;
1905- }
1906- }
1890+ char * passwd ;
1891+ struct pam_response * reply ;
1892+ int i ;
19071893
1908- if (!appdata_ptr )
1894+ if (appdata_ptr )
1895+ passwd = (char * )appdata_ptr ;
1896+ else
19091897{
19101898/*
19111899 * Workaround for Solaris 2.6 where the PAM library is broken and does
19121900 * not pass appdata_ptr to the conversation routine
19131901 */
1914- appdata_ptr = pam_passwd ;
1902+ passwd = pam_passwd ;
19151903}
19161904
1917- /*
1918- * Password wasn't passed to PAM the first time around - let's go ask the
1919- * client to send a password, which we then stuff into PAM.
1920- */
1921- if (strlen (appdata_ptr )== 0 )
1922- {
1923- char * passwd ;
1924-
1925- sendAuthRequest (pam_port_cludge ,AUTH_REQ_PASSWORD );
1926- passwd = recv_password_packet (pam_port_cludge );
1927-
1928- if (passwd == NULL )
1929- return PAM_CONV_ERR ;/* client didn't want to send password */
1905+ * resp = NULL ;/* in case of error exit */
19301906
1931- if (strlen (passwd )== 0 )
1932- {
1933- ereport (LOG ,
1934- (errmsg ("empty password returned by client" )));
1935- return PAM_CONV_ERR ;
1936- }
1937- appdata_ptr = passwd ;
1938- }
1907+ if (num_msg <=0 || num_msg > PAM_MAX_NUM_MSG )
1908+ return PAM_CONV_ERR ;
19391909
19401910/*
19411911 * Explicitly not using palloc here - PAM will free this memory in
19421912 * pam_end()
19431913 */
1944- * resp = calloc (num_msg ,sizeof (struct pam_response ));
1945- if (!* resp )
1914+ if ((reply = calloc (num_msg ,sizeof (struct pam_response )))== NULL )
19461915{
19471916ereport (LOG ,
19481917(errcode (ERRCODE_OUT_OF_MEMORY ),
19491918errmsg ("out of memory" )));
19501919return PAM_CONV_ERR ;
19511920}
19521921
1953- (* resp )[0 ].resp = strdup ((char * )appdata_ptr );
1954- (* resp )[0 ].resp_retcode = 0 ;
1922+ for (i = 0 ;i < num_msg ;i ++ )
1923+ {
1924+ switch (msg [i ]-> msg_style )
1925+ {
1926+ case PAM_PROMPT_ECHO_OFF :
1927+ if (strlen (passwd )== 0 )
1928+ {
1929+ /*
1930+ * Password wasn't passed to PAM the first time around -
1931+ * let's go ask the client to send a password, which we
1932+ * then stuff into PAM.
1933+ */
1934+ sendAuthRequest (pam_port_cludge ,AUTH_REQ_PASSWORD );
1935+ passwd = recv_password_packet (pam_port_cludge );
1936+ if (passwd == NULL )
1937+ {
1938+ /*
1939+ * Client didn't want to send password. We
1940+ * intentionally do not log anything about this.
1941+ */
1942+ gotofail ;
1943+ }
1944+ if (strlen (passwd )== 0 )
1945+ {
1946+ ereport (LOG ,
1947+ (errmsg ("empty password returned by client" )));
1948+ gotofail ;
1949+ }
1950+ }
1951+ if ((reply [i ].resp = strdup (passwd ))== NULL )
1952+ gotofail ;
1953+ reply [i ].resp_retcode = PAM_SUCCESS ;
1954+ break ;
1955+ case PAM_ERROR_MSG :
1956+ ereport (LOG ,
1957+ (errmsg ("error from underlying PAM layer: %s" ,
1958+ msg [i ]-> msg )));
1959+ /* FALL THROUGH */
1960+ case PAM_TEXT_INFO :
1961+ /* we don't bother to log TEXT_INFO messages */
1962+ if ((reply [i ].resp = strdup ("" ))== NULL )
1963+ gotofail ;
1964+ reply [i ].resp_retcode = PAM_SUCCESS ;
1965+ break ;
1966+ default :
1967+ elog (LOG ,"unsupported PAM conversation %d/\"%s\"" ,
1968+ msg [i ]-> msg_style ,
1969+ msg [i ]-> msg ?msg [i ]-> msg :"(none)" );
1970+ gotofail ;
1971+ }
1972+ }
1973+
1974+ * resp = reply ;
1975+ return PAM_SUCCESS ;
1976+
1977+ fail :
1978+ /* free up whatever we allocated */
1979+ for (i = 0 ;i < num_msg ;i ++ )
1980+ {
1981+ if (reply [i ].resp != NULL )
1982+ free (reply [i ].resp );
1983+ }
1984+ free (reply );
19551985
1956- return (( * resp )[ 0 ]. resp ? PAM_SUCCESS : PAM_CONV_ERR ) ;
1986+ return PAM_CONV_ERR ;
19571987}
19581988
19591989
@@ -1967,10 +1997,12 @@ CheckPAMAuth(Port *port, char *user, char *password)
19671997pam_handle_t * pamh = NULL ;
19681998
19691999/*
1970- * Apparently, Solaris 2.6 is broken, and needs ugly static variable
1971- * workaround
2000+ * We can't entirely rely on PAM to pass through appdata --- it appears
2001+ * not to work on at least Solaris 2.6. So use these ugly static
2002+ * variables instead.
19722003 */
19732004pam_passwd = password ;
2005+ pam_port_cludge = port ;
19742006
19752007/*
19762008 * Set the application data portion of the conversation struct This is