Commit 33417507 authored by Bryan Henderson's avatar Bryan Henderson

Require superuser privilege to create C function.

parent b13f5c25
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* define.c-- * define.c--
* POSTGRES "define" utility code. *
* These routines execute some of the CREATE statements. In an earlier
* version of Postgres, these were "define" statements.
* *
* Copyright (c) 1994, Regents of the University of California * Copyright (c) 1994, Regents of the University of California
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.2 1996/10/23 07:40:01 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.3 1996/10/31 09:07:41 bryanh Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
* appropriate arguments/flags, passing the results to the * appropriate arguments/flags, passing the results to the
* corresponding "FooDefine" routines (in src/catalog) that do * corresponding "FooDefine" routines (in src/catalog) that do
* the actual catalog-munging. * the actual catalog-munging. These routines also verify permission
* of the user to execute the command.
* *
* NOTES * NOTES
* These things must be defined and committed in the following order: * These things must be defined and committed in the following order:
* "define function": * "create function":
* input/output, recv/send procedures * input/output, recv/send procedures
* "define type": * "create type":
* type * type
* "define operator": * "create operator":
* operators * operators
* *
* Most of the parse-tree manipulation routines are defined in * Most of the parse-tree manipulation routines are defined in
...@@ -33,186 +36,246 @@ ...@@ -33,186 +36,246 @@
#include <ctype.h> #include <ctype.h>
#include <math.h> #include <math.h>
#include "postgres.h" #include <postgres.h>
#include "access/heapam.h" #include <access/heapam.h>
#include "access/htup.h" #include <access/htup.h>
#include "utils/tqual.h" #include <utils/tqual.h>
#include "catalog/catname.h" #include <catalog/catname.h>
#include "catalog/pg_aggregate.h" #include <catalog/pg_aggregate.h>
#include "catalog/pg_proc.h" #include <catalog/pg_operator.h>
#include "catalog/pg_type.h" #include <catalog/pg_proc.h>
#include "catalog/pg_operator.h" #include <catalog/pg_type.h>
#include "utils/syscache.h" #include <catalog/pg_user.h> /* superuser() uses this */
#include "nodes/pg_list.h" #include <utils/syscache.h>
#include "nodes/parsenodes.h" #include <nodes/pg_list.h>
#include "fmgr.h" /* for fmgr */ #include <nodes/parsenodes.h>
#include <fmgr.h> /* for fmgr */
#include "utils/builtins.h" /* prototype for textin() */
#include <utils/builtins.h> /* prototype for textin() */
#include "utils/elog.h"
#include "utils/palloc.h" #include <utils/elog.h>
#include "commands/defrem.h" #include <utils/palloc.h>
#include "optimizer/xfunc.h" #include <commands/defrem.h>
#include "tcop/dest.h" #include <optimizer/xfunc.h>
#include <tcop/dest.h>
static char *defGetString(DefElem *def); static char *defGetString(DefElem *def);
static int defGetTypeLength(DefElem *def); static int defGetTypeLength(DefElem *def);
#define DEFAULT_TYPDELIM ',' #define DEFAULT_TYPDELIM ','
/*
* DefineFunction -- bool
* Registers a new function. superuser(void) {
* /*--------------------------------------------------------------------------
*/ The Postgres user running this command has Postgres superuser
privileges.
--------------------------------------------------------------------------*/
HeapTuple utup;
char *userName;
userName = GetPgUserName();
utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName),
0,0,0);
Assert(utup != NULL);
return ((Form_pg_user)GETSTRUCT(utup))->usesuper;
}
void void
DefineFunction(ProcedureStmt *stmt, CommandDest dest) case_translate_language_name(const char *input, char *output) {
{ /*-------------------------------------------------------------------------
List *parameters = stmt->withClause; Translate the input language name to lower case, except if it's C,
char *proname = stmt->funcname; translate to upper case.
char* probin_str; --------------------------------------------------------------------------*/
char* prosrc_str;
char *prorettype;
char *languageName;
bool canCache = FALSE;
List *argList;
int32 byte_pct = 100, perbyte_cpu, percall_cpu, outin_ratio = 100;
bool returnsSet;
int i; int i;
/* ---------------- for (i = 0; i < NAMEDATALEN && input[i] != '\0'; ++i)
* figure out the language and convert it to lowercase. output[i] = tolower(input[i]);
* ----------------
*/
languageName = stmt->language;
for (i = 0; i < NAMEDATALEN && languageName[i]; ++i) {
languageName[i] = tolower(languageName[i]);
}
/* ---------------- output[i] = '\0';
* handle "returntype = X". The function could return a singleton
* value or a set of values. Figure out which. if (strcmp(output, "c") == 0) output[0] = 'C';
* ---------------- }
*/
if (nodeTag(stmt->returnType)==T_TypeName) {
TypeName *setType = (TypeName *)stmt->returnType;
void
compute_return_type(const Node *returnType,
char **prorettype_p, bool *returnsSet_p) {
/*---------------------------------------------------------------------------
Examine the "returns" clause returnType of the CREATE FUNCTION statement
and return information about it as **prorettype_p and **returnsSet.
----------------------------------------------------------------------------*/
if (nodeTag(returnType) == T_TypeName) {
/* a set of values */ /* a set of values */
prorettype = setType->name, TypeName *setType = (TypeName *)returnType;
returnsSet = true; *prorettype_p = setType->name,
*returnsSet_p = true;
}else { }else {
/* singleton */ /* singleton */
prorettype = strVal(stmt->returnType); *prorettype_p = strVal(returnType);
returnsSet = false; *returnsSet_p = false;
} }
}
/* Next attributes are only defined for C functions */
if ( strcmp(languageName, "c") == 0 ||
strcmp(languageName, "internal") == 0 ) { void
compute_full_attributes(const List *parameters, int32 *byte_pct_p,
int32 *perbyte_cpu_p, int32 *percall_cpu_p,
int32 *outin_ratio_p, bool *canCache_p) {
/*--------------------------------------------------------------------------
Interpret the parameters *parameters and return their contents as
*byte_pct_p, etc.
These are the full parameters of a C or internal function.
---------------------------------------------------------------------------*/
List *pl; List *pl;
/* the defaults */ /* the defaults */
byte_pct = BYTE_PCT; *byte_pct_p = BYTE_PCT;
perbyte_cpu = PERBYTE_CPU; *perbyte_cpu_p = PERBYTE_CPU;
percall_cpu = PERCALL_CPU; *percall_cpu_p = PERCALL_CPU;
outin_ratio = OUTIN_RATIO; *outin_ratio_p = OUTIN_RATIO;
foreach(pl, parameters) { foreach(pl, (List *)parameters) {
int count; int count;
char *ptr; char *ptr;
ParamString *param = (ParamString*)lfirst(pl); ParamString *param = (ParamString*)lfirst(pl);
if (!strcasecmp(param->name, "isacachable")) { if (strcasecmp(param->name, "iscachable") == 0) {
/* ---------------- *canCache_p = true;
* handle "[ iscachable ]": figure out if Postquel functions } else if (strcasecmp(param->name, "trusted") == 0) {
* are cacheable automagically?
* ----------------
*/
canCache = TRUE;
}else if (!strcasecmp(param->name, "trusted")) {
/* /*
* we don't have untrusted functions any more. The 4.2 * we don't have untrusted functions any more. The 4.2
* implementation is lousy anyway so I took it out. * implementation is lousy anyway so I took it out.
* -ay 10/94 * -ay 10/94
*/ */
elog(WARN, "untrusted function has been decommissioned."); elog(WARN, "untrusted function has been decommissioned.");
}else if (!strcasecmp(param->name, "byte_pct")) { } else if (strcasecmp(param->name, "byte_pct") == 0) {
/* /*
** handle expensive function parameters ** handle expensive function parameters
*/ */
byte_pct = atoi(param->val); *byte_pct_p = atoi(param->val);
}else if (!strcasecmp(param->name, "perbyte_cpu")) { } else if (strcasecmp(param->name, "perbyte_cpu") == 0) {
if (!sscanf(param->val, "%d", &perbyte_cpu)) { if (sscanf(param->val, "%d", perbyte_cpu_p) == 0) {
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++) { for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
if (*ptr == '!') { if (*ptr == '!') count++;
count++;
}
}
perbyte_cpu = (int) pow(10.0, (double) count);
}
}else if (!strcasecmp(param->name, "percall_cpu")) {
if (!sscanf(param->val, "%d", &percall_cpu)) {
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++) {
if (*ptr == '!') {
count++;
} }
*perbyte_cpu_p = (int) pow(10.0, (double) count);
} else if (strcasecmp(param->name, "percall_cpu") == 0) {
if (sscanf(param->val, "%d", percall_cpu_p) == 0) {
for (count = 0, ptr = param->val; *ptr != '\0'; ptr++)
if (*ptr == '!') count++;
*percall_cpu_p = (int) pow(10.0, (double) count);
} }
percall_cpu = (int) pow(10.0, (double) count); } else if (strcasecmp(param->name, "outin_ratio") == 0) {
*outin_ratio_p = atoi(param->val);
} }
}else if (!strcasecmp(param->name, "outin_ratio")) {
outin_ratio = atoi(param->val);
} }
} }
} else if (!strcmp(languageName, "sql")) {
/* query optimizer groks sql, these are meaningless */
perbyte_cpu = percall_cpu = 0;
void
interpret_AS_clause(const char languageName[], const char as[],
char **prosrc_str_p, char **probin_str_p) {
if ( strcmp(languageName, "C") == 0 ||
strcmp(languageName, "internal") == 0 ) {
*prosrc_str_p = "-";
*probin_str_p = (char *)as;
} else { } else {
elog(WARN, "DefineFunction: language '%s' is not supported", *prosrc_str_p = (char *)as;
languageName); *probin_str_p = "-";
} }
}
/* ----------------
* handle "[ arg is (...) ]"
* XXX fix optional arg handling below /*
* ---------------- * CreateFunction --
* Execute a CREATE FUNCTION utility statement.
*
*/
void
CreateFunction(ProcedureStmt *stmt, CommandDest dest)
{
char *probin_str;
/* pathname of executable file that executes this function, if any */
char *prosrc_str;
/* SQL that executes this function, if any */
char *prorettype;
/* Type of return value (or member of set of values) from function */
char languageName[NAMEDATALEN+1];
/* name of language of function, with case adjusted:
"C", "internal", or "SQL"
*/ */
argList = stmt->defArgs; /* The following are attributes of the function, as expressed in the
CREATE FUNCTION statement, where applicable.
*/
int32 byte_pct, perbyte_cpu, percall_cpu, outin_ratio;
bool canCache;
bool returnsSet;
/* The function returns a set of values, as opposed to a singleton. */
if ( strcmp(languageName, "c") == 0 ||
case_translate_language_name(stmt->language, languageName);
compute_return_type(stmt->returnType, &prorettype, &returnsSet);
if ( strcmp(languageName, "C") == 0 ||
strcmp(languageName, "internal") == 0 ) { strcmp(languageName, "internal") == 0 ) {
prosrc_str = "-"; compute_full_attributes(stmt->withClause,
probin_str = stmt->as; &byte_pct, &perbyte_cpu, &percall_cpu,
&outin_ratio, &canCache);
} else if (strcmp(languageName, "sql") == 0) {
/* query optimizer groks sql, these are meaningless */
perbyte_cpu = percall_cpu = 0;
byte_pct = outin_ratio = 100;
canCache = false;
} else { } else {
prosrc_str = stmt->as; elog(WARN,
probin_str = "-"; "Unrecognized language specified in a CREATE FUNCTION: "
"'%s'. Recognized languages are sql, C, and internal.",
languageName);
} }
/* C is stored uppercase in pg_language */ interpret_AS_clause(languageName, stmt->as, &prosrc_str, &probin_str);
if (!strcmp(languageName, "c")) {
languageName[0] = 'C';
}
/* ---------------- if (strcmp(languageName, "sql") != 0 && !superuser())
* now have ProcedureDefine do all the work.. elog(WARN,
* ---------------- "Only users with Postgres superuser privilege are permitted "
"to create a function "
"in the '%s' language. Others may use the 'sql' language.",
languageName);
/* Above does not return. */
else {
/* And now that we have all the parameters, and know we're permitted
to do so, go ahead and create the function.
*/ */
ProcedureCreate(proname, ProcedureCreate(stmt->funcname,
returnsSet, returnsSet,
prorettype, prorettype,
languageName, languageName,
prosrc_str, /* converted to text later */ prosrc_str, /* converted to text later */
probin_str, /* converted to text later */ probin_str, /* converted to text later */
canCache, canCache,
TRUE, true, /* (obsolete "trusted") */
byte_pct, byte_pct,
perbyte_cpu, perbyte_cpu,
percall_cpu, percall_cpu,
outin_ratio, outin_ratio,
argList, stmt->defArgs,
dest); dest);
}
} }
/* -------------------------------- /* --------------------------------
* DefineOperator-- * DefineOperator--
* *
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.2 1996/08/24 20:49:03 scrappy Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.3 1996/10/31 09:08:10 bryanh Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -367,7 +367,7 @@ ProcessUtility(Node *parsetree, ...@@ -367,7 +367,7 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_ViewStmt: /* VIEW */ case T_ViewStmt: /* CREATE VIEW */
{ {
ViewStmt *stmt = (ViewStmt *)parsetree; ViewStmt *stmt = (ViewStmt *)parsetree;
...@@ -377,13 +377,13 @@ ProcessUtility(Node *parsetree, ...@@ -377,13 +377,13 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_ProcedureStmt: /* FUNCTION */ case T_ProcedureStmt: /* CREATE FUNCTION */
commandTag = "CREATE"; commandTag = "CREATE";
CHECK_IF_ABORTED(); CHECK_IF_ABORTED();
DefineFunction((ProcedureStmt *)parsetree, dest); /* everything */ CreateFunction((ProcedureStmt *)parsetree, dest); /* everything */
break; break;
case T_IndexStmt: case T_IndexStmt: /* CREATE INDEX */
{ {
IndexStmt *stmt = (IndexStmt *)parsetree; IndexStmt *stmt = (IndexStmt *)parsetree;
...@@ -400,7 +400,7 @@ ProcessUtility(Node *parsetree, ...@@ -400,7 +400,7 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_RuleStmt: case T_RuleStmt: /* CREATE RULE */
{ {
RuleStmt *stmt = (RuleStmt *)parsetree; RuleStmt *stmt = (RuleStmt *)parsetree;
#ifndef NO_SECURITY #ifndef NO_SECURITY
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment