1010 *
1111 *
1212 * IDENTIFICATION
13- * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.143 2005/06/2805:08:56 tgl Exp $
13+ * $PostgreSQL: pgsql/src/backend/libpq/hba.c,v 1.144 2005/06/2822:16:45 tgl Exp $
1414 *
1515 *-------------------------------------------------------------------------
1616 */
@@ -96,17 +96,23 @@ pg_isblank(const char c)
9696
9797/*
9898 * Grab one token out of fp. Tokens are strings of non-blank
99- * characters bounded by blank characters, beginning of line, and
100- * end of line. Blank means space or tab. Return the token as
101- * *buf. Leave file positioned at the character immediately after the
102- * token or EOF, whichever comes first. If no more tokens on line,
103- * return empty string as *buf and position the file to the beginning
104- * of the next line or EOF, whichever comes first. Allow spaces in
105- * quoted strings. Terminate on unquoted commas. Handle
106- * comments. Treat unquoted keywords that might be role names or
99+ * characters bounded by blank characters, commas, beginning of line, and
100+ * end of line. Blank means space or tab. Tokens can be delimited by
101+ * double quotes (and usually are, in current usage).
102+ *
103+ * The token, if any, is returned at *buf (a buffer of size bufsz).
104+ *
105+ * If successful: store null-terminated token at *buf and return TRUE.
106+ * If no more tokens on line: set *buf = '\0' and return FALSE.
107+ *
108+ * Leave file positioned at the character immediately after the token or EOF,
109+ * whichever comes first. If no more tokens on line, position the file to the
110+ * beginning of the next line or EOF, whichever comes first.
111+ *
112+ * Handle comments. Treat unquoted keywords that might be role names or
107113 * database names specially, by appending a newline to them.
108114 */
109- static void
115+ static bool
110116next_token (FILE * fp ,char * buf ,int bufsz )
111117{
112118int c ;
@@ -125,7 +131,7 @@ next_token(FILE *fp, char *buf, int bufsz)
125131if (c == EOF || c == '\n' )
126132{
127133* buf = '\0' ;
128- return ;
134+ return false ;
129135}
130136
131137/*
@@ -200,32 +206,35 @@ next_token(FILE *fp, char *buf, int bufsz)
200206* buf ++ = '\n' ;
201207* buf = '\0' ;
202208}
209+
210+ return (saw_quote || buf > start_buf );
203211}
204212
205213/*
206214 * Tokenize file and handle file inclusion and comma lists. We have
207215 * to breakapart thecommastoexpandany file names then
208216 * reconstruct with commas.
209217 *
210- * The result is always a palloc'd string. If it's zero-length then
211- * we have reached EOL.
218+ * The result is a palloc'd string, or NULL if we have reached EOL.
212219 */
213220static char *
214221next_token_expand (const char * filename ,FILE * file )
215222{
216223char buf [MAX_TOKEN ];
217224char * comma_str = pstrdup ("" );
225+ bool got_something = false;
218226bool trailing_comma ;
219227char * incbuf ;
220228int needed ;
221229
222230do
223231{
224- next_token (file ,buf ,sizeof (buf ));
225- if (!buf [0 ])
232+ if (!next_token (file ,buf ,sizeof (buf )))
226233break ;
227234
228- if (buf [strlen (buf )- 1 ]== ',' )
235+ got_something = true;
236+
237+ if (strlen (buf )> 0 && buf [strlen (buf )- 1 ]== ',' )
229238{
230239trailing_comma = true;
231240buf [strlen (buf )- 1 ]= '\0' ;
@@ -249,6 +258,12 @@ next_token_expand(const char *filename, FILE *file)
249258pfree (incbuf );
250259}while (trailing_comma );
251260
261+ if (!got_something )
262+ {
263+ pfree (comma_str );
264+ return NULL ;
265+ }
266+
252267return comma_str ;
253268}
254269
@@ -402,7 +417,7 @@ tokenize_file(const char *filename, FILE *file,
402417buf = next_token_expand (filename ,file );
403418
404419/* add token to list, unless we are at EOL or comment start */
405- if (buf [ 0 ] )
420+ if (buf )
406421{
407422if (current_line == NIL )
408423{
@@ -423,8 +438,6 @@ tokenize_file(const char *filename, FILE *file,
423438current_line = NIL ;
424439/* Advance line number whenever we reach EOL */
425440line_number ++ ;
426- /* Don't forget to pfree the next_token_expand result */
427- pfree (buf );
428441}
429442}
430443}
@@ -462,44 +475,58 @@ get_role_line(const char *role)
462475
463476
464477/*
465- * Does member belong to role?
478+ * Does user belong to role?
479+ *
480+ * user is always the name given as the attempted login identifier.
481+ * We check to see if it is a member of the specified role name.
466482 */
467483static bool
468- check_member (const char * role ,const char * member )
484+ is_member (const char * user ,const char * role )
469485{
470486List * * line ;
471- List * * line2 ;
472487ListCell * line_item ;
473488
474- if ((line = get_role_line (member ))== NULL )
475- return false;/* ifmember not exist, say "no" */
489+ if ((line = get_role_line (user ))== NULL )
490+ return false;/* ifuser not exist, say "no" */
476491
477- if ((line2 = get_role_line (role ))== NULL )
478- return false;/* if role not exist, say "no" */
492+ /* A user always belongs to its own role */
493+ if (strcmp (user ,role )== 0 )
494+ return true;
479495
480- /* skip over the role name, password, valuntil, examine all the members */
481- for_each_cell (line_item ,lfourth (* line2 ))
496+ /*
497+ * skip over the role name, password, valuntil, examine all the
498+ * membership entries
499+ */
500+ if (list_length (* line )< 4 )
501+ return false;
502+ for_each_cell (line_item ,lnext (lnext (lnext (list_head (* line )))))
482503{
483- if (strcmp ((char * )lfirst (line_item ),member )== 0 )
504+ if (strcmp ((char * )lfirst (line_item ),role )== 0 )
484505return true;
485506}
486507
487508return false;
488509}
489510
490511/*
491- * Check comma member list for a specific role, handle role names.
512+ * Check comma-separated list for a match to role, allowing group names.
513+ *
514+ * NB: param_str is destructively modified! In current usage, this is
515+ * okay only because this code is run after forking off from the postmaster,
516+ * and so it doesn't matter that we clobber the stored hba info.
492517 */
493518static bool
494- check_role (char * role ,char * param_str )
519+ check_role (const char * role ,char * param_str )
495520{
496521char * tok ;
497522
498- for (tok = strtok (param_str ,MULTI_VALUE_SEP );tok != NULL ;tok = strtok (NULL ,MULTI_VALUE_SEP ))
523+ for (tok = strtok (param_str ,MULTI_VALUE_SEP );
524+ tok != NULL ;
525+ tok = strtok (NULL ,MULTI_VALUE_SEP ))
499526{
500527if (tok [0 ]== '+' )
501528{
502- if (check_member ( tok + 1 , role ))
529+ if (is_member ( role , tok + 1 ))
503530return true;
504531}
505532else if (strcmp (tok ,role )== 0 ||
@@ -512,13 +539,19 @@ check_role(char *role, char *param_str)
512539
513540/*
514541 * Check to see if db/role combination matches param string.
542+ *
543+ * NB: param_str is destructively modified! In current usage, this is
544+ * okay only because this code is run after forking off from the postmaster,
545+ * and so it doesn't matter that we clobber the stored hba info.
515546 */
516547static bool
517- check_db (char * dbname ,char * role ,char * param_str )
548+ check_db (const char * dbname ,const char * role ,char * param_str )
518549{
519550char * tok ;
520551
521- for (tok = strtok (param_str ,MULTI_VALUE_SEP );tok != NULL ;tok = strtok (NULL ,MULTI_VALUE_SEP ))
552+ for (tok = strtok (param_str ,MULTI_VALUE_SEP );
553+ tok != NULL ;
554+ tok = strtok (NULL ,MULTI_VALUE_SEP ))
522555{
523556if (strcmp (tok ,"all\n" )== 0 )
524557return true;
@@ -530,7 +563,7 @@ check_db(char *dbname, char *role, char *param_str)
530563else if (strcmp (tok ,"samegroup\n" )== 0 ||
531564strcmp (tok ,"samerole\n" )== 0 )
532565{
533- if (check_member ( dbname , role ))
566+ if (is_member ( role , dbname ))
534567return true;
535568}
536569else if (strcmp (tok ,dbname )== 0 )
@@ -981,8 +1014,7 @@ read_pg_database_line(FILE *fp, char *dbname,
9811014
9821015if (feof (fp ))
9831016return false;
984- next_token (fp ,buf ,sizeof (buf ));
985- if (!buf [0 ])
1017+ if (!next_token (fp ,buf ,sizeof (buf )))
9861018return false;
9871019if (strlen (buf ) >=NAMEDATALEN )
9881020elog (FATAL ,"bad data in flat pg_database file" );
@@ -1000,8 +1032,7 @@ read_pg_database_line(FILE *fp, char *dbname,
10001032if (!isdigit ((unsignedchar )buf [0 ]))
10011033elog (FATAL ,"bad data in flat pg_database file" );
10021034/* expect EOL next */
1003- next_token (fp ,buf ,sizeof (buf ));
1004- if (buf [0 ])
1035+ if (next_token (fp ,buf ,sizeof (buf )))
10051036elog (FATAL ,"bad data in flat pg_database file" );
10061037return true;
10071038}