7
7
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
8
8
* Portions Copyright (c) 1994, Regents of the University of California
9
9
*
10
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/dumputils.c,v 1.5 2003/07/24 15:52:53 petere Exp $
10
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/dumputils.c,v 1.6 2003/07/31 17:21:57 tgl Exp $
11
11
*
12
12
*-------------------------------------------------------------------------
13
13
*/
19
19
#include "parser/keywords.h"
20
20
21
21
22
+ #define supports_grant_options (version ) ((version) >= 70400)
23
+
24
+ static bool parseAclArray (const char * acls , char * * * itemarray , int * nitems );
22
25
static bool parseAclItem (const char * item , const char * type , const char * name ,
23
26
int remoteVersion ,
24
27
PQExpBuffer grantee , PQExpBuffer grantor ,
25
28
PQExpBuffer privs , PQExpBuffer privswgo );
29
+ static char * copyAclUserName (PQExpBuffer output , char * input );
26
30
static void AddAcl (PQExpBuffer aclbuf , const char * keyword );
27
- #define supports_grant_options (version ) ((version) >= 70400)
28
31
29
32
30
33
/*
@@ -185,15 +188,23 @@ buildACLCommands(const char *name, const char *type,
185
188
int remoteVersion ,
186
189
PQExpBuffer sql )
187
190
{
188
- char * aclbuf ,
189
- * tok ;
191
+ char * * aclitems ;
192
+ int naclitems ;
193
+ int i ;
190
194
PQExpBuffer grantee , grantor , privs , privswgo ;
191
195
PQExpBuffer firstsql , secondsql ;
192
196
bool found_owner_privs = false;
193
197
194
198
if (strlen (acls ) == 0 )
195
199
return true; /* object has default permissions */
196
200
201
+ if (!parseAclArray (acls , & aclitems , & naclitems ))
202
+ {
203
+ if (aclitems )
204
+ free (aclitems );
205
+ return false;
206
+ }
207
+
197
208
grantee = createPQExpBuffer ();
198
209
grantor = createPQExpBuffer ();
199
210
privs = createPQExpBuffer ();
@@ -217,27 +228,10 @@ buildACLCommands(const char *name, const char *type,
217
228
appendPQExpBuffer (firstsql , "REVOKE ALL ON %s %s FROM PUBLIC;\n" ,
218
229
type , name );
219
230
220
- /* Make a working copy of acls so we can use strtok */
221
- aclbuf = strdup (acls );
222
-
223
- /* Scan comma-separated ACL items */
224
- for (tok = strtok (aclbuf , "," ); tok != NULL ; tok = strtok (NULL , "," ))
231
+ /* Scan individual ACL items */
232
+ for (i = 0 ; i < naclitems ; i ++ )
225
233
{
226
- size_t toklen ;
227
-
228
- /*
229
- * Token may start with '{' and/or '"'. Actually only the start
230
- * of the string should have '{', but we don't verify that.
231
- */
232
- if (* tok == '{' )
233
- tok ++ ;
234
- if (* tok == '"' )
235
- tok ++ ;
236
- toklen = strlen (tok );
237
- while (toklen >=0 && (tok [toklen - 1 ] == '"' || tok [toklen - 1 ] == '}' ))
238
- tok [toklen -- - 1 ] = '\0' ;
239
-
240
- if (!parseAclItem (tok , type , name , remoteVersion ,
234
+ if (!parseAclItem (aclitems [i ], type , name , remoteVersion ,
241
235
grantee , grantor , privs , privswgo ))
242
236
return false;
243
237
@@ -327,7 +321,6 @@ buildACLCommands(const char *name, const char *type,
327
321
type , name , fmtId (owner ));
328
322
}
329
323
330
- free (aclbuf );
331
324
destroyPQExpBuffer (grantee );
332
325
destroyPQExpBuffer (grantor );
333
326
destroyPQExpBuffer (privs );
@@ -337,15 +330,105 @@ buildACLCommands(const char *name, const char *type,
337
330
destroyPQExpBuffer (firstsql );
338
331
destroyPQExpBuffer (secondsql );
339
332
333
+ free (aclitems );
334
+
340
335
return true;
341
336
}
342
337
338
+ /*
339
+ * Deconstruct an ACL array (or actually any 1-dimensional Postgres array)
340
+ * into individual items.
341
+ *
342
+ * On success, returns true and sets *itemarray and *nitems to describe
343
+ * an array of individual strings. On parse failure, returns false;
344
+ * *itemarray may exist or be NULL.
345
+ *
346
+ * NOTE: free'ing itemarray is sufficient to deallocate the working storage.
347
+ */
348
+ static bool
349
+ parseAclArray (const char * acls , char * * * itemarray , int * nitems )
350
+ {
351
+ int inputlen ;
352
+ char * * items ;
353
+ char * strings ;
354
+ int curitem ;
355
+
356
+ /*
357
+ * We expect input in the form of "{item,item,item}" where any item
358
+ * is either raw data, or surrounded by double quotes (in which case
359
+ * embedded characters including backslashes and quotes are backslashed).
360
+ *
361
+ * We build the result as an array of pointers followed by the actual
362
+ * string data, all in one malloc block for convenience of deallocation.
363
+ * The worst-case storage need is not more than one pointer and one
364
+ * character for each input character (consider "{,,,,,,,,,,}").
365
+ */
366
+ * itemarray = NULL ;
367
+ * nitems = 0 ;
368
+ inputlen = strlen (acls );
369
+ if (inputlen < 2 || acls [0 ] != '{' || acls [inputlen - 1 ] != '}' )
370
+ return false; /* bad input */
371
+ items = (char * * ) malloc (inputlen * (sizeof (char * ) + sizeof (char )));
372
+ if (items == NULL )
373
+ return false; /* out of memory */
374
+ * itemarray = items ;
375
+ strings = (char * ) (items + inputlen );
376
+
377
+ acls ++ ; /* advance over initial '{' */
378
+ curitem = 0 ;
379
+ while (* acls != '}' )
380
+ {
381
+ if (* acls == '\0' )
382
+ return false; /* premature end of string */
383
+ items [curitem ] = strings ;
384
+ while (* acls != '}' && * acls != ',' )
385
+ {
386
+ if (* acls == '\0' )
387
+ return false; /* premature end of string */
388
+ if (* acls != '"' )
389
+ * strings ++ = * acls ++ ; /* copy unquoted data */
390
+ else
391
+ {
392
+ /* process quoted substring */
393
+ acls ++ ;
394
+ while (* acls != '"' )
395
+ {
396
+ if (* acls == '\0' )
397
+ return false; /* premature end of string */
398
+ if (* acls == '\\' )
399
+ {
400
+ acls ++ ;
401
+ if (* acls == '\0' )
402
+ return false; /* premature end of string */
403
+ }
404
+ * strings ++ = * acls ++ ; /* copy quoted data */
405
+ }
406
+ acls ++ ;
407
+ }
408
+ }
409
+ * strings ++ = '\0' ;
410
+ if (* acls == ',' )
411
+ acls ++ ;
412
+ curitem ++ ;
413
+ }
414
+ if (acls [1 ] != '\0' )
415
+ return false; /* bogus syntax (embedded '}') */
416
+ * nitems = curitem ;
417
+ return true;
418
+ }
343
419
344
420
/*
345
- * This will take an aclitem string of privilege code letters and
346
- * parse it into grantee, grantor, and privilege information. The
347
- * privilege information is split between privileges with grant option
348
- * (privswgo) and without (privs).
421
+ * This will parse an aclitem string, having the general form
422
+ * username=privilegecodes/grantor
423
+ * or
424
+ * group groupname=privilegecodes/grantor
425
+ * (the /grantor part will not be present if pre-7.4 database).
426
+ *
427
+ * The returned grantee string will be the dequoted username or groupname
428
+ * (preceded with "group " in the latter case). The returned grantor is
429
+ * the dequoted grantor name or empty. Privilege characters are decoded
430
+ * and split between privileges with grant option (privswgo) and without
431
+ * (privs).
349
432
*
350
433
* Note: for cross-version compatibility, it's important to use ALL when
351
434
* appropriate.
@@ -365,19 +448,19 @@ parseAclItem(const char *item, const char *type, const char *name,
365
448
366
449
buf = strdup (item );
367
450
368
- /* user name is string up to = */
369
- eqpos = strchr ( buf , '=' );
370
- if (! eqpos )
451
+ /* user or group name is string up to = */
452
+ eqpos = copyAclUserName ( grantee , buf );
453
+ if (* eqpos != '=' )
371
454
return false;
372
- * eqpos = '\0' ;
373
- printfPQExpBuffer (grantee , "%s" , buf );
374
455
375
456
/* grantor may be listed after / */
376
457
slpos = strchr (eqpos + 1 , '/' );
377
458
if (slpos )
378
459
{
379
- * slpos = '\0' ;
380
- printfPQExpBuffer (grantor , "%s" , slpos + 1 );
460
+ * slpos ++ = '\0' ;
461
+ slpos = copyAclUserName (grantor , slpos );
462
+ if (* slpos != '\0' )
463
+ return false;
381
464
}
382
465
else
383
466
resetPQExpBuffer (grantor );
@@ -457,6 +540,38 @@ parseAclItem(const char *item, const char *type, const char *name,
457
540
return true;
458
541
}
459
542
543
+ /*
544
+ * Transfer a user or group name starting at *input into the output buffer,
545
+ * dequoting if needed. Returns a pointer to just past the input name.
546
+ * The name is taken to end at an unquoted '=' or end of string.
547
+ */
548
+ static char *
549
+ copyAclUserName (PQExpBuffer output , char * input )
550
+ {
551
+ resetPQExpBuffer (output );
552
+ while (* input && * input != '=' )
553
+ {
554
+ if (* input != '"' )
555
+ appendPQExpBufferChar (output , * input ++ );
556
+ else
557
+ {
558
+ input ++ ;
559
+ while (* input != '"' )
560
+ {
561
+ if (* input == '\0' )
562
+ return input ; /* really a syntax error... */
563
+ /*
564
+ * There is no quoting convention here, thus we can't cope
565
+ * with usernames containing double quotes. Keep this code
566
+ * in sync with putid() in backend's acl.c.
567
+ */
568
+ appendPQExpBufferChar (output , * input ++ );
569
+ }
570
+ input ++ ;
571
+ }
572
+ }
573
+ return input ;
574
+ }
460
575
461
576
/*
462
577
* Append a privilege keyword to a keyword list, inserting comma if needed.
0 commit comments