Re: [PATCH] Re: Setuid functions - Mailing list pgsql-hackers

From Bruce Momjian
Subject Re: [PATCH] Re: Setuid functions
Date
Msg-id 200106240246.f5O2k9N23233@candle.pha.pa.us
Whole thread Raw
In response to [PATCH] Re: Setuid functions  (Mark Volpe <volpe.mark@epa.gov>)
List pgsql-hackers
Removed from queue pending review.

> Sorry, I have decided not to follow the SQL standard ;-) PRIVILEGE is spelled
> correctly in my patch.
> 
> This patch will implement the "ENABLE PRIVILEGE" and "DISABLE PRIVILEGE"
> commands   in PL/pgSQL, which, respectively, change the effective uid to that
> of the function owner and back. It doesn't break security (I hope). The
> commands can be abbreviated as "ENABLE" and "DISABLE" for the poor saps that
> have trouble with "PRIVILEGE" :) Easier than adding a setuid bit to the
> catalog, no?
> 
> Apologies if the patch is not in the correct format.  Apply with
> 
> patch -p1 < enable_disable.patch
> 
> in the tippety-top of the 7.1.2 tree.
> 
> Regression example:
> 
> CREATE USER sample_user;
> CREATE TABLE test_log(stamp datetime);
> GRANT SELECT ON test_log TO PUBLIC;
> 
> DROP FUNCTION test_enable();
> CREATE FUNCTION test_enable() RETURNS boolean AS
> '
>     DECLARE
>         user name;
>     BEGIN
>         user:=current_user;
>         RAISE NOTICE ''Username: %'', user;
>         ENABLE PRIVILEGE;
>         user:=current_user;
>         RAISE NOTICE ''Username: %'', user;
>         INSERT INTO test_log VALUES(''now''::text);
>         DISABLE PRIVILEGE; -- Actually unnecessary at the end of the function
>         RETURN TRUE;
>     END;
> ' LANGUAGE 'plpgsql';
> 
> \c - sample_user
> SELECT test_enable();
> SELECT * FROM test_log;
> 
>          stamp          
> ------------------------
>  2001-06-21 11:17:29-04
> 
> (Note current time logged into a table where sample_user could not normally
> write)
> 
> Hope you will find this useful
> - Mark
> 
> "Ross J. Reedstrom" wrote:
> > 
> > Come on, Chris, you've never heard about SQL standard LEDGE? That's
> > the nomenclature they chose to describe a collection of permissions:
> > a SHELF or LEDGE. PUBLEDGE, USERLEDGE, PRIVLEDGE. So, the last is the
> > PRIVATE LEDGE, reserved for the owner of the object whose access is
> > being determined (or was that PRIVITHEDGE? now I'm confused)
> > 
> > ... or something. ;-) Actually, not too far from how some of the SQL92
> > standards docs actually seem to read, especially after falling asleep
> > face down on the keyboard will trying to understand them, and having
> > vivid dreams.
> > 
> > Ross (who's in the office much too late, working on budget justifications
> > for grants that are due tomorrow!)
> > 
> > ---------------------------(end of broadcast)---------------------------
> > TIP 2: you can get off all lists at once with the unregister command
> >     (send "unregister YourEmailAddressHere" to majordomo@postgresql.org)

> diff -ur postgresql-7.1.2/src/pl/plpgsql/src/gram.y postgresql-7.1.2-patch/src/pl/plpgsql/src/gram.y
> --- postgresql-7.1.2/src/pl/plpgsql/src/gram.y    Wed Jun 20 20:07:45 2001
> +++ postgresql-7.1.2-patch/src/pl/plpgsql/src/gram.y    Wed Jun 20 19:48:18 2001
> @@ -121,7 +121,7 @@
>  %type <stmts>    proc_sect, proc_stmts, stmt_else, loop_body
>  %type <stmt>    proc_stmt, pl_block
>  %type <stmt>    stmt_assign, stmt_if, stmt_loop, stmt_while, stmt_exit
> -%type <stmt>    stmt_return, stmt_raise, stmt_execsql, stmt_fori
> +%type <stmt>    stmt_return, stmt_raise, stmt_execsql, stmt_fori, stmt_enable, stmt_disable
>  %type <stmt>    stmt_fors, stmt_select, stmt_perform
>  %type <stmt>    stmt_dynexecute, stmt_dynfors, stmt_getdiag
>  
> @@ -164,6 +164,9 @@
>  %token    K_PERFORM
>  %token    K_ROW_COUNT
>  %token    K_RAISE
> +%token  K_ENABLE
> +%token  K_DISABLE
> +%token  K_PRIVILEGE
>  %token    K_RECORD
>  %token    K_RENAME
>  %token    K_RESULT_OID
> @@ -569,6 +572,10 @@
>                          { $$ = $1; }
>                  | stmt_raise
>                          { $$ = $1; }
> +                | stmt_enable
> +                        { $$ = $1; }
> +                | stmt_disable
> +                        { $$ = $1; }
>                  | stmt_execsql
>                          { $$ = $1; }
>                  | stmt_dynexecute
> @@ -1033,6 +1040,34 @@
>                          $$ = (PLpgSQL_stmt *)new;
>                      }
>                  ;
> +
> +stmt_enable        : K_ENABLE opt_privilege lno ';'
> +                {
> +                    PLpgSQL_stmt_privilege *new;
> +
> +                    new=malloc(sizeof(PLpgSQL_stmt_privilege));
> +
> +                    new->cmd_type = PLPGSQL_STMT_ENABLE;
> +                    new->lineno = $3;
> +
> +                    $$ = (PLpgSQL_stmt *)new;
> +                }
> +
> +stmt_disable        : K_DISABLE opt_privilege lno ';'
> +                {
> +                    PLpgSQL_stmt_privilege *new;
> +
> +                    new=malloc(sizeof(PLpgSQL_stmt_privilege));
> +
> +                    new->cmd_type = PLPGSQL_STMT_DISABLE;
> +                    new->lineno = $3;
> +
> +                    $$ = (PLpgSQL_stmt *)new;
> +                }
> +
> +opt_privilege :
> +    | K_PRIVILEGE
> +;
>  
>  stmt_raise        : K_RAISE lno raise_level raise_msg raise_params ';'
>                      {
> diff -ur postgresql-7.1.2/src/pl/plpgsql/src/pl_exec.c postgresql-7.1.2-patch/src/pl/plpgsql/src/pl_exec.c
> --- postgresql-7.1.2/src/pl/plpgsql/src/pl_exec.c    Wed Jun 20 20:07:45 2001
> +++ postgresql-7.1.2-patch/src/pl/plpgsql/src/pl_exec.c    Wed Jun 20 19:48:18 2001
> @@ -99,6 +99,8 @@
>                 PLpgSQL_stmt_exit * stmt);
>  static int exec_stmt_return(PLpgSQL_execstate * estate,
>                   PLpgSQL_stmt_return * stmt);
> +static int exec_stmt_privilege(PLpgSQL_execstate * estate,
> +                PLpgSQL_stmt_privilege * stmt);
>  static int exec_stmt_raise(PLpgSQL_execstate * estate,
>                  PLpgSQL_stmt_raise * stmt);
>  static int exec_stmt_execsql(PLpgSQL_execstate * estate,
> @@ -220,6 +222,12 @@
>                      case PLPGSQL_STMT_RETURN:
>                          stmttype = "return";
>                          break;
> +                    case PLPGSQL_STMT_ENABLE:
> +                        stmttype = "enable";
> +                        break;
> +                    case PLPGSQL_STMT_DISABLE:
> +                        stmttype = "disable";
> +                        break;
>                      case PLPGSQL_STMT_RAISE:
>                          stmttype = "raise";
>                          break;
> @@ -265,6 +273,8 @@
>      estate.retistuple = func->fn_retistuple;
>      estate.retisset = func->fn_retset;
>      estate.exitlabel = NULL;
> +    estate.save_uid = InvalidOid;
> +    estate.fn_oid = func->fn_oid;
>  
>      estate.found_varno = func->found_varno;
>      estate.ndatums = func->ndatums;
> @@ -385,6 +395,9 @@
>          elog(ERROR, "control reaches end of function without RETURN");
>      }
>  
> +    if (estate.save_uid!=InvalidOid)
> +        SetUserId(estate.save_uid);
> +
>      /*
>       * We got a return value - process it
>       */
> @@ -565,6 +578,8 @@
>      estate.retistuple = func->fn_retistuple;
>      estate.retisset = func->fn_retset;
>      estate.exitlabel = NULL;
> +    estate.save_uid = InvalidOid;
> +    estate.fn_oid = func->fn_oid;
>  
>      estate.found_varno = func->found_varno;
>      estate.ndatums = func->ndatums;
> @@ -742,6 +757,9 @@
>          elog(ERROR, "control reaches end of trigger procedure without RETURN");
>      }
>  
> +    if (estate.save_uid!=InvalidOid)
> +        SetUserId(estate.save_uid);
> +
>      /*
>       * Check that the returned tuple structure has the same attributes,
>       * the relation that fired the trigger has.
> @@ -986,6 +1004,11 @@
>              rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
>              break;
>  
> +        case PLPGSQL_STMT_ENABLE:
> +        case PLPGSQL_STMT_DISABLE:
> +            rc = exec_stmt_privilege(estate, (PLpgSQL_stmt_privilege *) stmt);
> +            break;
> +
>          case PLPGSQL_STMT_RAISE:
>              rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
>              break;
> @@ -1536,6 +1559,41 @@
>                                      &(estate->rettype));
>  
>      return PLPGSQL_RC_RETURN;
> +}
> +
> +/* ----------
> + * exec_stmt_privilege          Changes user ID to/from
> + *                              that of the function owner's
> + * ----------
> + */
> +
> +static int
> +exec_stmt_privilege(PLpgSQL_execstate * estate, PLpgSQL_stmt_privilege * stmt)
> +{
> +    HeapTuple procedureTuple;
> +    Form_pg_proc procedureStruct;
> +
> +    if (stmt->cmd_type==PLPGSQL_STMT_ENABLE)
> +    {
> +        if (estate->save_uid!=InvalidOid) return PLPGSQL_RC_OK; /* Already enabled */
> +        procedureTuple = SearchSysCache(PROCOID, ObjectIdGetDatum(estate->fn_oid), 0, 0, 0);
> +
> +        if (!HeapTupleIsValid(procedureTuple))
> +            elog(ERROR, "exec_stmt_privilege: cache lookup failed");
> +
> +        procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
> +
> +        estate->save_uid = GetUserId();
> +        SetUserId(procedureStruct->proowner);
> +        ReleaseSysCache(procedureTuple);
> +    } else
> +    {
> +        if (estate->save_uid==InvalidOid) return PLPGSQL_RC_OK; /* Already disabled */
> +        SetUserId(estate->save_uid);
> +        estate->save_uid = InvalidOid;
> +    }
> +
> +    return PLPGSQL_RC_OK;
>  }
>  
>  
> diff -ur postgresql-7.1.2/src/pl/plpgsql/src/pl_funcs.c postgresql-7.1.2-patch/src/pl/plpgsql/src/pl_funcs.c
> --- postgresql-7.1.2/src/pl/plpgsql/src/pl_funcs.c    Wed Jun 20 20:07:45 2001
> +++ postgresql-7.1.2-patch/src/pl/plpgsql/src/pl_funcs.c    Wed Jun 20 20:05:14 2001
> @@ -382,6 +382,7 @@
>  static void dump_select(PLpgSQL_stmt_select * stmt);
>  static void dump_exit(PLpgSQL_stmt_exit * stmt);
>  static void dump_return(PLpgSQL_stmt_return * stmt);
> +static void dump_privilege(PLpgSQL_stmt_privilege * stmt);
>  static void dump_raise(PLpgSQL_stmt_raise * stmt);
>  static void dump_execsql(PLpgSQL_stmt_execsql * stmt);
>  static void dump_dynexecute(PLpgSQL_stmt_dynexecute * stmt);
> @@ -435,6 +436,10 @@
>          case PLPGSQL_STMT_RETURN:
>              dump_return((PLpgSQL_stmt_return *) stmt);
>              break;
> +        case PLPGSQL_STMT_ENABLE:
> +        case PLPGSQL_STMT_DISABLE:
> +            dump_privilege((PLpgSQL_stmt_privilege *) stmt);
> +            break;
>          case PLPGSQL_STMT_RAISE:
>              dump_raise((PLpgSQL_stmt_raise *) stmt);
>              break;
> @@ -647,6 +652,16 @@
>              dump_expr(stmt->expr);
>      }
>      printf("\n");
> +}
> +
> +static void
> +dump_privilege(PLpgSQL_stmt_privilege * stmt)
> +{
> +    dump_ind();
> +    if (stmt->cmd_type==PLPGSQL_STMT_ENABLE)
> +        printf("ENABLE PRIVILEGE\n");
> +    else
> +        printf("DISABLE PRIVILEGE\n");
>  }
>  
>  static void
> diff -ur postgresql-7.1.2/src/pl/plpgsql/src/plpgsql.h postgresql-7.1.2-patch/src/pl/plpgsql/src/plpgsql.h
> --- postgresql-7.1.2/src/pl/plpgsql/src/plpgsql.h    Wed Jun 20 20:07:45 2001
> +++ postgresql-7.1.2-patch/src/pl/plpgsql/src/plpgsql.h    Wed Jun 20 20:08:57 2001
> @@ -94,7 +94,9 @@
>      PLPGSQL_STMT_EXECSQL,
>      PLPGSQL_STMT_DYNEXECUTE,
>      PLPGSQL_STMT_DYNFORS,
> -    PLPGSQL_STMT_GETDIAG
> +    PLPGSQL_STMT_GETDIAG,
> +    PLPGSQL_STMT_ENABLE,
> +    PLPGSQL_STMT_DISABLE
>  };
>  
>  
> @@ -387,6 +389,11 @@
>      int            retrecno;
>  }            PLpgSQL_stmt_return;
>  
> +typedef struct
> +{                               /* ENABLE/DISABLE statement */
> +    int         cmd_type;
> +    int         lineno;
> +}           PLpgSQL_stmt_privilege;
>  
>  typedef struct
>  {                                /* RAISE statement            */
> @@ -464,6 +471,8 @@
>      int            found_varno;
>      int            ndatums;
>      PLpgSQL_datum **datums;
> +    Oid        save_uid;
> +    Oid        fn_oid;
>  }            PLpgSQL_execstate;
>  
>  
> Only in postgresql-7.1.2/src/pl/plpgsql/src: plpgsql.h.orig
> Only in postgresql-7.1.2/src/pl/plpgsql/src: plpgsql.h.rej
> diff -ur postgresql-7.1.2/src/pl/plpgsql/src/scan.l postgresql-7.1.2-patch/src/pl/plpgsql/src/scan.l
> --- postgresql-7.1.2/src/pl/plpgsql/src/scan.l    Wed Jun 20 20:07:45 2001
> +++ postgresql-7.1.2-patch/src/pl/plpgsql/src/scan.l    Wed Jun 20 19:48:18 2001
> @@ -115,6 +115,9 @@
>  null            { return K_NULL;            }
>  perform            { return K_PERFORM;            }
>  raise            { return K_RAISE;            }
> +enable            { return K_ENABLE;            }
> +disable        { return K_DISABLE;            }
> +privilege        { return K_PRIVILEGE;            }
>  record            { return K_RECORD;            }
>  rename            { return K_RENAME;            }
>  result_oid        { return K_RESULT_OID;        }

> 
> ---------------------------(end of broadcast)---------------------------
> TIP 3: if posting/reading through Usenet, please send an appropriate
> subscribe-nomail command to majordomo@postgresql.org so that your
> message can get through to the mailing list cleanly

--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026
 


pgsql-hackers by date:

Previous
From: Bruce Momjian
Date:
Subject: Re: [PATCH] by request: base64 for bytea
Next
From: Tom Lane
Date:
Subject: Re: [PATCH] by request: base64 for bytea