44 * Look into pg_user and check the encrypted password with the one
55 * passed in from the frontend.
66 *
7+ * Modification History
8+ *
9+ * Dec 17, 1997 - Todd A. Brandys
10+ *Orignal Version Completed.
11+ *
712 *
813 *-------------------------------------------------------------------------
914 */
1823
1924#include "postgres.h"
2025#include "miscadmin.h"
21- #include "libpq/crypt.h"
2226#include "utils/nabstime.h"
23- #include "utils/palloc.h"
2427#include "storage/fd.h"
28+ #include "libpq/crypt.h"
29+
30+ char * * pwd_cache = NULL ;
31+ int pwd_cache_count = 0 ;
32+
33+ /*-------------------------------------------------------------------------*/
2534
2635char * crypt_getpwdfilename () {
2736
28- static char * filename = NULL ;
37+ static char * pfnam = NULL ;
2938
30- if (!filename ) {
31- filename = (char * )palloc (strlen (DataDir )+ strlen (CRYPT_PWD_FILE )+ 2 );
32- sprintf (filename ,"%s/%s" ,DataDir ,CRYPT_PWD_FILE );
39+ if (!pfnam ) {
40+ pfnam = (char * )malloc (strlen (DataDir )+ strlen (CRYPT_PWD_FILE )+ 2 );
41+ sprintf (pfnam ,"%s/%s" ,DataDir ,CRYPT_PWD_FILE );
3342 }
3443
35- return filename ;
44+ return pfnam ;
45+ }
46+
47+ /*-------------------------------------------------------------------------*/
48+
49+ char * crypt_getpwdreloadfilename () {
50+
51+ static char * rpfnam = NULL ;
52+
53+ if (!rpfnam ) {
54+ char * pwdfilename ;
55+
56+ pwdfilename = crypt_getpwdfilename ();
57+ rpfnam = (char * )malloc (strlen (pwdfilename )+ strlen (CRYPT_PWD_RELOAD_SUFX )+ 1 );
58+ sprintf (rpfnam ,"%s%s" ,pwdfilename ,CRYPT_PWD_RELOAD_SUFX );
59+ }
60+
61+ return rpfnam ;
3662}
3763
3864/*-------------------------------------------------------------------------*/
3965
4066static
4167FILE * crypt_openpwdfile () {
42-
4368char * filename ;
69+ FILE * pwdfile ;
4470
4571filename = crypt_getpwdfilename ();
46- return (AllocateFile (filename ,"r" ));
72+ pwdfile = AllocateFile (filename ,"r" );
73+
74+ return pwdfile ;
4775}
4876
4977/*-------------------------------------------------------------------------*/
5078
5179static
52- void crypt_parsepwdfile ( FILE * datafile , char * * login , char * * pwd , char * * valdate ) {
80+ int compar_user ( const void * user_a , const void * user_b ) {
5381
54- char buffer [ 256 ];
55- char * parse ;
56- int count ,
57- i ;
82+ int min ,
83+ value ;
84+ char * login_a ;
85+ char * login_b ;
5886
59- fgets ( buffer , 256 , datafile );
60- parse = buffer ;
87+ login_a = * (( char * * ) user_a );
88+ login_b = * (( char * * ) user_b ) ;
6189
62- /* store a copy of user login to return
90+ /* We only really want to compare the user logins which are first. We look
91+ * for the first SEPSTR char getting the number of chars there are before it.
92+ * We only need to compare to the min count from the two strings.
6393 */
64- count = strcspn (parse ,"#" );
65- * login = (char * )palloc (count + 1 );
66- strncpy (* login ,parse ,count );
67- (* login )[count ]= '\0' ;
68- parse += (count + 1 );
94+ min = strcspn (login_a ,CRYPT_PWD_FILE_SEPSTR );
95+ value = strcspn (login_b ,CRYPT_PWD_FILE_SEPSTR );
96+ if (value < min )
97+ min = value ;
98+
99+ /* We add one to min so that the separator character is included in the
100+ * comparison. Why? I believe this will prevent logins that are proper
101+ * prefixes of other logins from being 'masked out'. Being conservative!
102+ */
103+ return strncmp (login_a ,login_b ,min + 1 );
104+ }
105+
106+ /*-------------------------------------------------------------------------*/
107+
108+ static
109+ void crypt_loadpwdfile () {
110+
111+ char * filename ;
112+ int result ;
113+ FILE * pwd_file ;
114+ char buffer [256 ];
115+
116+ filename = crypt_getpwdreloadfilename ();
117+ result = unlink (filename );
118+
119+ /* We want to delete the flag file before reading the contents of the pg_pwd
120+ * file. If result == 0 then the unlink of the reload file was successful.
121+ * This means that a backend performed a COPY of the pg_user file to
122+ * pg_pwd. Therefore we must now do a reload.
123+ */
124+ if (!pwd_cache || !result ) {
125+ if (pwd_cache ) {/* free the old data only if this is a reload */
126+ while (pwd_cache_count -- ) {
127+ free ((void * )pwd_cache [pwd_cache_count ]);
128+ }
129+ free ((void * )pwd_cache );
130+ pwd_cache = NULL ;
131+ pwd_cache_count = 0 ;
132+ }
133+
134+ if (!(pwd_file = crypt_openpwdfile ()))
135+ return ;
136+
137+ /* Here is where we load the data from pg_pwd.
138+ */
139+ while (fgets (buffer ,256 ,pwd_file )!= NULL ) {
140+ /* We must remove the return char at the end of the string, as this will
141+ * affect the correct parsing of the password entry.
142+ */
143+ if (buffer [(result = strlen (buffer )- 1 )]== '\n' )
144+ buffer [result ]= '\0' ;
145+
146+ pwd_cache = (char * * )realloc ((void * )pwd_cache ,sizeof (char * )* (pwd_cache_count + 1 ));
147+ pwd_cache [pwd_cache_count ++ ]= strdup (buffer );
148+ }
149+ fclose (pwd_file );
150+
151+ /* Now sort the entries in the cache for faster searching later.
152+ */
153+ qsort ((void * )pwd_cache ,pwd_cache_count ,sizeof (char * ),compar_user );
154+ }
155+ }
156+
157+ /*-------------------------------------------------------------------------*/
158+
159+ static
160+ void crypt_parsepwdentry (char * buffer ,char * * pwd ,char * * valdate ) {
161+
162+ char * parse = buffer ;
163+ int count ,
164+ i ;
69165
70166/* skip to the password field
71167 */
72- for (i = 0 ;i < 5 ;i ++ )
73- parse += (strcspn (parse ,"#" )+ 1 );
168+ for (i = 0 ;i < 6 ;i ++ )
169+ parse += (strcspn (parse ,CRYPT_PWD_FILE_SEPSTR )+ 1 );
74170
75171/* store a copy of user password to return
76172 */
77- count = strcspn (parse ,"#" );
78- * pwd = (char * )palloc (count + 1 );
173+ count = strcspn (parse ,CRYPT_PWD_FILE_SEPSTR );
174+ * pwd = (char * )malloc (count + 1 );
79175strncpy (* pwd ,parse ,count );
80176 (* pwd )[count ]= '\0' ;
81177parse += (count + 1 );
82178
83179/* store a copy of date login becomes invalid
84180 */
85- count = strcspn (parse ,"#" );
86- * valdate = (char * )palloc (count + 1 );
181+ count = strcspn (parse ,CRYPT_PWD_FILE_SEPSTR );
182+ * valdate = (char * )malloc (count + 1 );
87183strncpy (* valdate ,parse ,count );
88184 (* valdate )[count ]= '\0' ;
89185parse += (count + 1 );
@@ -92,33 +188,33 @@ void crypt_parsepwdfile(FILE* datafile, char** login, char** pwd, char** valdate
92188/*-------------------------------------------------------------------------*/
93189
94190static
95- void crypt_getloginfo (const char * user ,char * * passwd ,char * * valuntil ) {
191+ int crypt_getloginfo (const char * user ,char * * passwd ,char * * valuntil ) {
96192
97- FILE * datafile ;
98- char * login ;
99193char * pwd ;
100194char * valdate ;
195+ void * fakeout ;
101196
102197* passwd = NULL ;
103198* valuntil = NULL ;
199+ crypt_loadpwdfile ();
104200
105- if (!(datafile = crypt_openpwdfile ()))
106- return ;
201+ if (pwd_cache ) {
202+ char * * pwd_entry ;
203+ char user_search [NAMEDATALEN + 2 ];
107204
108- while (! feof ( datafile )) {
109- crypt_parsepwdfile ( datafile , & login , & pwd , & valdate ) ;
110- if (! strcmp ( login , user )) {
111- pfree (( void * ) login );
205+ sprintf ( user_search , "%s\t" , user );
206+ fakeout = ( void * ) & user_search ;
207+ if (( pwd_entry = ( char * * ) bsearch (( void * ) & fakeout , ( void * ) pwd_cache , pwd_cache_count , sizeof ( char * ), compar_user ) )) {
208+ crypt_parsepwdentry ( * pwd_entry , & pwd , & valdate );
112209* passwd = pwd ;
113210* valuntil = valdate ;
114- fclose (datafile );
115- return ;
211+ return STATUS_OK ;
116212 }
117- pfree ((void * )login );
118- pfree ((void * )pwd );
119- pfree ((void * )valdate );
213+
214+ return STATUS_OK ;
120215 }
121- fclose (datafile );
216+
217+ return STATUS_ERROR ;
122218}
123219
124220/*-------------------------------------------------------------------------*/
@@ -128,16 +224,17 @@ MsgType crypt_salt(const char* user) {
128224char * passwd ;
129225char * valuntil ;
130226
131- crypt_getloginfo (user ,& passwd ,& valuntil );
227+ if (crypt_getloginfo (user ,& passwd ,& valuntil )== STATUS_ERROR )
228+ return STARTUP_UNSALT_MSG ;
132229
133230if (passwd == NULL || * passwd == '\0' || !strcmp (passwd ,"\\N" )) {
134- if (passwd )pfree ((void * )passwd );
135- if (valuntil )pfree ((void * )valuntil );
231+ if (passwd )free ((void * )passwd );
232+ if (valuntil )free ((void * )valuntil );
136233return STARTUP_UNSALT_MSG ;
137234 }
138235
139- pfree ((void * )passwd );
140- if (valuntil )pfree ((void * )valuntil );
236+ free ((void * )passwd );
237+ if (valuntil )free ((void * )valuntil );
141238return STARTUP_SALT_MSG ;
142239}
143240
@@ -152,11 +249,12 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) {
152249AbsoluteTime vuntil ,
153250current ;
154251
155- crypt_getloginfo (user ,& passwd ,& valuntil );
252+ if (crypt_getloginfo (user ,& passwd ,& valuntil )== STATUS_ERROR )
253+ return STATUS_ERROR ;
156254
157255if (passwd == NULL || * passwd == '\0' ) {
158- if (passwd )pfree ((void * )passwd );
159- if (valuntil )pfree ((void * )valuntil );
256+ if (passwd )free ((void * )passwd );
257+ if (valuntil )free ((void * )valuntil );
160258return STATUS_ERROR ;
161259 }
162260
@@ -175,8 +273,8 @@ int crypt_verify(Port* port, const char* user, const char* pgpass) {
175273retval = STATUS_OK ;
176274 }
177275
178- pfree ((void * )passwd );
179- if (valuntil )pfree ((void * )valuntil );
276+ free ((void * )passwd );
277+ if (valuntil )free ((void * )valuntil );
180278
181279return retval ;
182280}