@@ -81,11 +81,11 @@ static List *cached_roles[] = {NIL, NIL, NIL};
81
81
static uint32 cached_db_hash ;
82
82
83
83
84
- static const char * getid (const char * s , char * n );
84
+ static const char * getid (const char * s , char * n , Node * escontext );
85
85
static void putid (char * p , const char * s );
86
86
static Acl * allocacl (int n );
87
87
static void check_acl (const Acl * acl );
88
- static const char * aclparse (const char * s , AclItem * aip );
88
+ static const char * aclparse (const char * s , AclItem * aip , Node * escontext );
89
89
static bool aclitem_match (const AclItem * a1 , const AclItem * a2 );
90
90
static int aclitemComparator (const void * arg1 , const void * arg2 );
91
91
static void check_circularity (const Acl * old_acl , const AclItem * mod_aip ,
@@ -135,9 +135,12 @@ static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue
135
135
* in 's', after any quotes. Also:
136
136
* - loads the identifier into 'n'. (If no identifier is found, 'n'
137
137
* contains an empty string.) 'n' must be NAMEDATALEN bytes.
138
+ *
139
+ * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
140
+ * in which case we log the error there and return NULL.
138
141
*/
139
142
static const char *
140
- getid (const char * s , char * n )
143
+ getid (const char * s , char * n , Node * escontext )
141
144
{
142
145
int len = 0 ;
143
146
bool in_quotes = false;
@@ -169,7 +172,7 @@ getid(const char *s, char *n)
169
172
170
173
/* Add the character to the string */
171
174
if (len >= NAMEDATALEN - 1 )
172
- ereport ( ERROR ,
175
+ ereturn ( escontext , NULL ,
173
176
(errcode (ERRCODE_NAME_TOO_LONG ),
174
177
errmsg ("identifier too long" ),
175
178
errdetail ("Identifier must be less than %d characters." ,
@@ -236,9 +239,12 @@ putid(char *p, const char *s)
236
239
* specification. Also:
237
240
* - loads the structure pointed to by 'aip' with the appropriate
238
241
* UID/GID, id type identifier and mode type values.
242
+ *
243
+ * Errors are reported via ereport, unless escontext is an ErrorSaveData node,
244
+ * in which case we log the error there and return NULL.
239
245
*/
240
246
static const char *
241
- aclparse (const char * s , AclItem * aip )
247
+ aclparse (const char * s , AclItem * aip , Node * escontext )
242
248
{
243
249
AclMode privs ,
244
250
goption ,
@@ -248,25 +254,30 @@ aclparse(const char *s, AclItem *aip)
248
254
249
255
Assert (s && aip );
250
256
251
- s = getid (s , name );
257
+ s = getid (s , name , escontext );
258
+ if (s == NULL )
259
+ return NULL ;
252
260
if (* s != '=' )
253
261
{
254
262
/* we just read a keyword, not a name */
255
263
if (strcmp (name , "group" ) != 0 && strcmp (name , "user" ) != 0 )
256
- ereport ( ERROR ,
264
+ ereturn ( escontext , NULL ,
257
265
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
258
266
errmsg ("unrecognized key word: \"%s\"" , name ),
259
267
errhint ("ACL key word must be \"group\" or \"user\"." )));
260
- s = getid (s , name ); /* move s to the name beyond the keyword */
268
+ /* move s to the name beyond the keyword */
269
+ s = getid (s , name , escontext );
270
+ if (s == NULL )
271
+ return NULL ;
261
272
if (name [0 ] == '\0' )
262
- ereport ( ERROR ,
273
+ ereturn ( escontext , NULL ,
263
274
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
264
275
errmsg ("missing name" ),
265
276
errhint ("A name must follow the \"group\" or \"user\" key word." )));
266
277
}
267
278
268
279
if (* s != '=' )
269
- ereport ( ERROR ,
280
+ ereturn ( escontext , NULL ,
270
281
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
271
282
errmsg ("missing \"=\" sign" )));
272
283
@@ -328,7 +339,7 @@ aclparse(const char *s, AclItem *aip)
328
339
read = 0 ;
329
340
break ;
330
341
default :
331
- ereport ( ERROR ,
342
+ ereturn ( escontext , NULL ,
332
343
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
333
344
errmsg ("invalid mode character: must be one of \"%s\"" ,
334
345
ACL_ALL_RIGHTS_STR )));
@@ -340,20 +351,32 @@ aclparse(const char *s, AclItem *aip)
340
351
if (name [0 ] == '\0' )
341
352
aip -> ai_grantee = ACL_ID_PUBLIC ;
342
353
else
343
- aip -> ai_grantee = get_role_oid (name , false);
354
+ {
355
+ aip -> ai_grantee = get_role_oid (name , true);
356
+ if (!OidIsValid (aip -> ai_grantee ))
357
+ ereturn (escontext , NULL ,
358
+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
359
+ errmsg ("role \"%s\" does not exist" , name )));
360
+ }
344
361
345
362
/*
346
363
* XXX Allow a degree of backward compatibility by defaulting the grantor
347
364
* to the superuser.
348
365
*/
349
366
if (* s == '/' )
350
367
{
351
- s = getid (s + 1 , name2 );
368
+ s = getid (s + 1 , name2 , escontext );
369
+ if (s == NULL )
370
+ return NULL ;
352
371
if (name2 [0 ] == '\0' )
353
- ereport ( ERROR ,
372
+ ereturn ( escontext , NULL ,
354
373
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
355
374
errmsg ("a name must follow the \"/\" sign" )));
356
- aip -> ai_grantor = get_role_oid (name2 , false);
375
+ aip -> ai_grantor = get_role_oid (name2 , true);
376
+ if (!OidIsValid (aip -> ai_grantor ))
377
+ ereturn (escontext , NULL ,
378
+ (errcode (ERRCODE_UNDEFINED_OBJECT ),
379
+ errmsg ("role \"%s\" does not exist" , name2 )));
357
380
}
358
381
else
359
382
{
@@ -569,14 +592,19 @@ Datum
569
592
aclitemin (PG_FUNCTION_ARGS )
570
593
{
571
594
const char * s = PG_GETARG_CSTRING (0 );
595
+ Node * escontext = fcinfo -> context ;
572
596
AclItem * aip ;
573
597
574
598
aip = (AclItem * ) palloc (sizeof (AclItem ));
575
- s = aclparse (s , aip );
599
+
600
+ s = aclparse (s , aip , escontext );
601
+ if (s == NULL )
602
+ PG_RETURN_NULL ();
603
+
576
604
while (isspace ((unsigned char ) * s ))
577
605
++ s ;
578
606
if (* s )
579
- ereport ( ERROR ,
607
+ ereturn ( escontext , ( Datum ) 0 ,
580
608
(errcode (ERRCODE_INVALID_TEXT_REPRESENTATION ),
581
609
errmsg ("extra garbage at the end of the ACL specification" )));
582
610
0 commit comments