8
8
*
9
9
*
10
10
* 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 $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -452,7 +452,6 @@ ClientAuthentication(Port *port)
452
452
453
453
case uaPAM :
454
454
#ifdef USE_PAM
455
- pam_port_cludge = port ;
456
455
status = CheckPAMAuth (port , port -> user_name , "" );
457
456
#else
458
457
Assert (false);
@@ -1888,72 +1887,103 @@ static int
1888
1887
pam_passwd_conv_proc (int num_msg , const struct pam_message * * msg ,
1889
1888
struct pam_response * * resp , void * appdata_ptr )
1890
1889
{
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 ;
1907
1893
1908
- if (!appdata_ptr )
1894
+ if (appdata_ptr )
1895
+ passwd = (char * ) appdata_ptr ;
1896
+ else
1909
1897
{
1910
1898
/*
1911
1899
* Workaround for Solaris 2.6 where the PAM library is broken and does
1912
1900
* not pass appdata_ptr to the conversation routine
1913
1901
*/
1914
- appdata_ptr = pam_passwd ;
1902
+ passwd = pam_passwd ;
1915
1903
}
1916
1904
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 */
1930
1906
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 ;
1939
1909
1940
1910
/*
1941
1911
* Explicitly not using palloc here - PAM will free this memory in
1942
1912
* pam_end()
1943
1913
*/
1944
- * resp = calloc (num_msg , sizeof (struct pam_response ));
1945
- if (!* resp )
1914
+ if ((reply = calloc (num_msg , sizeof (struct pam_response ))) == NULL )
1946
1915
{
1947
1916
ereport (LOG ,
1948
1917
(errcode (ERRCODE_OUT_OF_MEMORY ),
1949
1918
errmsg ("out of memory" )));
1950
1919
return PAM_CONV_ERR ;
1951
1920
}
1952
1921
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
+ goto fail ;
1943
+ }
1944
+ if (strlen (passwd ) == 0 )
1945
+ {
1946
+ ereport (LOG ,
1947
+ (errmsg ("empty password returned by client" )));
1948
+ goto fail ;
1949
+ }
1950
+ }
1951
+ if ((reply [i ].resp = strdup (passwd )) == NULL )
1952
+ goto fail ;
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
+ goto fail ;
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
+ goto fail ;
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 );
1955
1985
1956
- return (( * resp )[ 0 ]. resp ? PAM_SUCCESS : PAM_CONV_ERR ) ;
1986
+ return PAM_CONV_ERR ;
1957
1987
}
1958
1988
1959
1989
@@ -1967,10 +1997,12 @@ CheckPAMAuth(Port *port, char *user, char *password)
1967
1997
pam_handle_t * pamh = NULL ;
1968
1998
1969
1999
/*
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.
1972
2003
*/
1973
2004
pam_passwd = password ;
2005
+ pam_port_cludge = port ;
1974
2006
1975
2007
/*
1976
2008
* Set the application data portion of the conversation struct This is
0 commit comments