|
24 | 24 | #include "miscadmin.h"
|
25 | 25 | #include "nodes/nodeFuncs.h"
|
26 | 26 | #include "pgstat.h"
|
| 27 | +#include "utils/acl.h" |
27 | 28 | #include "utils/builtins.h"
|
28 | 29 | #include "utils/fmgrtab.h"
|
29 | 30 | #include "utils/guc.h"
|
@@ -2468,3 +2469,86 @@ get_fn_expr_variadic(FmgrInfo *flinfo)
|
2468 | 2469 | else
|
2469 | 2470 | return false;
|
2470 | 2471 | }
|
| 2472 | + |
| 2473 | +/*------------------------------------------------------------------------- |
| 2474 | + * Support routines for procedural language implementations |
| 2475 | + *------------------------------------------------------------------------- |
| 2476 | + */ |
| 2477 | + |
| 2478 | +/* |
| 2479 | + * Verify that a validator is actually associated with the language of a |
| 2480 | + * particular function and that the user has access to both the language and |
| 2481 | + * the function. All validators should call this before doing anything |
| 2482 | + * substantial. Doing so ensures a user cannot achieve anything with explicit |
| 2483 | + * calls to validators that he could not achieve with CREATE FUNCTION or by |
| 2484 | + * simply calling an existing function. |
| 2485 | + * |
| 2486 | + * When this function returns false, callers should skip all validation work |
| 2487 | + * and call PG_RETURN_VOID(). This never happens at present; it is reserved |
| 2488 | + * for future expansion. |
| 2489 | + * |
| 2490 | + * In particular, checking that the validator corresponds to the function's |
| 2491 | + * language allows untrusted language validators to assume they process only |
| 2492 | + * superuser-chosen source code. (Untrusted language call handlers, by |
| 2493 | + * definition, do assume that.) A user lacking the USAGE language privilege |
| 2494 | + * would be unable to reach the validator through CREATE FUNCTION, so we check |
| 2495 | + * that to block explicit calls as well. Checking the EXECUTE privilege on |
| 2496 | + * the function is often superfluous, because most users can clone the |
| 2497 | + * function to get an executable copy. It is meaningful against users with no |
| 2498 | + * database TEMP right and no permanent schema CREATE right, thereby unable to |
| 2499 | + * create any function. Also, if the function tracks persistent state by |
| 2500 | + * function OID or name, validating the original function might permit more |
| 2501 | + * mischief than creating and validating a clone thereof. |
| 2502 | + */ |
| 2503 | +bool |
| 2504 | +CheckFunctionValidatorAccess(Oid validatorOid, Oid functionOid) |
| 2505 | +{ |
| 2506 | + HeapTuple procTup; |
| 2507 | + HeapTuple langTup; |
| 2508 | + Form_pg_proc procStruct; |
| 2509 | + Form_pg_language langStruct; |
| 2510 | + AclResult aclresult; |
| 2511 | + |
| 2512 | + /* Get the function's pg_proc entry */ |
| 2513 | + procTup = SearchSysCache1(PROCOID, ObjectIdGetDatum(functionOid)); |
| 2514 | + if (!HeapTupleIsValid(procTup)) |
| 2515 | + elog(ERROR, "cache lookup failed for function %u", functionOid); |
| 2516 | + procStruct = (Form_pg_proc) GETSTRUCT(procTup); |
| 2517 | + |
| 2518 | + /* |
| 2519 | + * Fetch pg_language entry to know if this is the correct validation |
| 2520 | + * function for that pg_proc entry. |
| 2521 | + */ |
| 2522 | + langTup = SearchSysCache1(LANGOID, ObjectIdGetDatum(procStruct->prolang)); |
| 2523 | + if (!HeapTupleIsValid(langTup)) |
| 2524 | + elog(ERROR, "cache lookup failed for language %u", procStruct->prolang); |
| 2525 | + langStruct = (Form_pg_language) GETSTRUCT(langTup); |
| 2526 | + |
| 2527 | + if (langStruct->lanvalidator != validatorOid) |
| 2528 | + ereport(ERROR, |
| 2529 | + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), |
| 2530 | + errmsg("language validation function %u called for language %u instead of %u", |
| 2531 | + validatorOid, procStruct->prolang, |
| 2532 | + langStruct->lanvalidator))); |
| 2533 | + |
| 2534 | + /* first validate that we have permissions to use the language */ |
| 2535 | + aclresult = pg_language_aclcheck(procStruct->prolang, GetUserId(), |
| 2536 | + ACL_USAGE); |
| 2537 | + if (aclresult != ACLCHECK_OK) |
| 2538 | + aclcheck_error(aclresult, ACL_KIND_LANGUAGE, |
| 2539 | + NameStr(langStruct->lanname)); |
| 2540 | + |
| 2541 | + /* |
| 2542 | + * Check whether we are allowed to execute the function itself. If we can |
| 2543 | + * execute it, there should be no possible side-effect of |
| 2544 | + * compiling/validation that execution can't have. |
| 2545 | + */ |
| 2546 | + aclresult = pg_proc_aclcheck(functionOid, GetUserId(), ACL_EXECUTE); |
| 2547 | + if (aclresult != ACLCHECK_OK) |
| 2548 | + aclcheck_error(aclresult, ACL_KIND_PROC, NameStr(procStruct->proname)); |
| 2549 | + |
| 2550 | + ReleaseSysCache(procTup); |
| 2551 | + ReleaseSysCache(langTup); |
| 2552 | + |
| 2553 | + return true; |
| 2554 | +} |
0 commit comments