86
/**********************************************************************
87
* Information associated with a Tcl interpreter. We have one interpreter
88
* that is used for all pltclu (untrusted) functions. For pltcl (trusted)
89
* functions, there is a separate interpreter for each effective SQL userid.
90
* (This is needed to ensure that an unprivileged user can't inject Tcl code
91
* that'll be executed with the privileges of some other SQL user.)
93
* The pltcl_interp_desc structs are kept in a Postgres hash table indexed
94
* by userid OID, with OID 0 used for the single untrusted interpreter.
95
**********************************************************************/
96
typedef struct pltcl_interp_desc
98
Oid user_id; /* Hash key (must be first!) */
99
Tcl_Interp *interp; /* The interpreter */
100
Tcl_HashTable query_hash; /* pltcl_query_desc structs */
86
104
/**********************************************************************
87
105
* The information we cache about loaded procedures
88
106
**********************************************************************/
119
138
/**********************************************************************
139
* For speedy lookup, we maintain a hash table mapping from
140
* function OID + trigger OID + user OID to pltcl_proc_desc pointers.
141
* The reason the pltcl_proc_desc struct isn't directly part of the hash
142
* entry is to simplify recovery from errors during compile_pltcl_function.
144
* Note: if the same function is called by multiple userIDs within a session,
145
* there will be a separate pltcl_proc_desc entry for each userID in the case
146
* of pltcl functions, but only one entry for pltclu functions, because we
147
* set user_id = 0 for that case.
148
**********************************************************************/
149
typedef struct pltcl_proc_key
151
Oid proc_id; /* Function OID */
152
Oid trig_id; /* Trigger OID, or 0 if not trigger */
153
Oid user_id; /* User calling the function, or 0 */
156
typedef struct pltcl_proc_ptr
158
pltcl_proc_key proc_key; /* Hash key (must be first!) */
159
pltcl_proc_desc *proc_ptr;
163
/**********************************************************************
121
165
**********************************************************************/
122
166
static bool pltcl_pm_init_done = false;
123
static bool pltcl_be_norm_init_done = false;
124
static bool pltcl_be_safe_init_done = false;
125
167
static Tcl_Interp *pltcl_hold_interp = NULL;
126
static Tcl_Interp *pltcl_norm_interp = NULL;
127
static Tcl_Interp *pltcl_safe_interp = NULL;
128
static Tcl_HashTable *pltcl_proc_hash = NULL;
129
static Tcl_HashTable *pltcl_norm_query_hash = NULL;
130
static Tcl_HashTable *pltcl_safe_query_hash = NULL;
168
static HTAB *pltcl_interp_htab = NULL;
169
static HTAB *pltcl_proc_htab = NULL;
132
/* these are saved and restored by pltcl_call_handler */
171
/* these are saved and restored by pltcl_handler */
133
172
static FunctionCallInfo pltcl_current_fcinfo = NULL;
134
173
static pltcl_proc_desc *pltcl_current_prodesc = NULL;
140
179
Datum pltclu_call_handler(PG_FUNCTION_ARGS);
141
180
void _PG_init(void);
143
static void pltcl_init_interp(Tcl_Interp *interp);
144
static Tcl_Interp *pltcl_fetch_interp(bool pltrusted);
182
static void pltcl_init_interp(pltcl_interp_desc *interp_desc, bool pltrusted);
183
static pltcl_interp_desc *pltcl_fetch_interp(bool pltrusted);
145
184
static void pltcl_init_load_unknown(Tcl_Interp *interp);
147
static Datum pltcl_func_handler(PG_FUNCTION_ARGS);
149
static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS);
186
static Datum pltcl_handler(PG_FUNCTION_ARGS, bool pltrusted);
188
static Datum pltcl_func_handler(PG_FUNCTION_ARGS, bool pltrusted);
190
static HeapTuple pltcl_trigger_handler(PG_FUNCTION_ARGS, bool pltrusted);
151
192
static void throw_tcl_error(Tcl_Interp *interp, const char *proname);
153
static pltcl_proc_desc *compile_pltcl_function(Oid fn_oid, Oid tgreloid);
194
static pltcl_proc_desc *compile_pltcl_function(Oid fn_oid, Oid tgreloid,
155
197
static int pltcl_elog(ClientData cdata, Tcl_Interp *interp,
156
198
int argc, CONST84 char *argv[]);
304
351
* stdout and stderr on DeleteInterp
305
352
************************************************************/
306
353
if ((pltcl_hold_interp = Tcl_CreateInterp()) == NULL)
307
elog(ERROR, "could not create \"hold\" interpreter");
354
elog(ERROR, "could not create master Tcl interpreter");
308
355
if (Tcl_Init(pltcl_hold_interp) == TCL_ERROR)
309
elog(ERROR, "could not initialize \"hold\" interpreter");
311
/************************************************************
312
* Create the two slave interpreters. Note: Tcl automatically does
313
* Tcl_Init on the normal slave, and it's not wanted for the safe slave.
314
************************************************************/
315
if ((pltcl_norm_interp =
316
Tcl_CreateSlave(pltcl_hold_interp, "norm", 0)) == NULL)
317
elog(ERROR, "could not create \"normal\" interpreter");
318
pltcl_init_interp(pltcl_norm_interp);
320
if ((pltcl_safe_interp =
321
Tcl_CreateSlave(pltcl_hold_interp, "safe", 1)) == NULL)
322
elog(ERROR, "could not create \"safe\" interpreter");
323
pltcl_init_interp(pltcl_safe_interp);
325
/************************************************************
326
* Initialize the proc and query hash tables
327
************************************************************/
328
pltcl_proc_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));
329
pltcl_norm_query_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));
330
pltcl_safe_query_hash = (Tcl_HashTable *) malloc(sizeof(Tcl_HashTable));
331
Tcl_InitHashTable(pltcl_proc_hash, TCL_STRING_KEYS);
332
Tcl_InitHashTable(pltcl_norm_query_hash, TCL_STRING_KEYS);
333
Tcl_InitHashTable(pltcl_safe_query_hash, TCL_STRING_KEYS);
356
elog(ERROR, "could not initialize master Tcl interpreter");
358
/************************************************************
359
* Create the hash table for working interpreters
360
************************************************************/
361
memset(&hash_ctl, 0, sizeof(hash_ctl));
362
hash_ctl.keysize = sizeof(Oid);
363
hash_ctl.entrysize = sizeof(pltcl_interp_desc);
364
hash_ctl.hash = oid_hash;
365
pltcl_interp_htab = hash_create("PL/Tcl interpreters",
368
HASH_ELEM | HASH_FUNCTION);
370
/************************************************************
371
* Create the hash table for function lookup
372
************************************************************/
373
memset(&hash_ctl, 0, sizeof(hash_ctl));
374
hash_ctl.keysize = sizeof(pltcl_proc_key);
375
hash_ctl.entrysize = sizeof(pltcl_proc_ptr);
376
hash_ctl.hash = tag_hash;
377
pltcl_proc_htab = hash_create("PL/Tcl functions",
380
HASH_ELEM | HASH_FUNCTION);
335
382
pltcl_pm_init_done = true;
338
385
/**********************************************************************
339
* pltcl_init_interp() - initialize a Tcl interpreter
341
* The work done here must be safe to do in the postmaster process,
342
* in case the pltcl library is preloaded in the postmaster. Note
343
* that this is applied separately to the "normal" and "safe" interpreters.
386
* pltcl_init_interp() - initialize a new Tcl interpreter
344
387
**********************************************************************/
346
pltcl_init_interp(Tcl_Interp *interp)
389
pltcl_init_interp(pltcl_interp_desc *interp_desc, bool pltrusted)
394
/************************************************************
395
* Create the Tcl interpreter as a slave of pltcl_hold_interp.
396
* Note: Tcl automatically does Tcl_Init in the untrusted case,
397
* and it's not wanted in the trusted case.
398
************************************************************/
399
snprintf(interpname, sizeof(interpname), "slave_%u", interp_desc->user_id);
400
if ((interp = Tcl_CreateSlave(pltcl_hold_interp, interpname,
401
pltrusted ? 1 : 0)) == NULL)
402
elog(ERROR, "could not create slave Tcl interpreter");
403
interp_desc->interp = interp;
405
/************************************************************
406
* Initialize the query hash table associated with interpreter
407
************************************************************/
408
Tcl_InitHashTable(&interp_desc->query_hash, TCL_STRING_KEYS);
348
410
/************************************************************
349
411
* Install the commands for SPI support in the interpreter
350
412
************************************************************/
365
427
pltcl_SPI_execute_plan, NULL, NULL);
366
428
Tcl_CreateCommand(interp, "spi_lastoid",
367
429
pltcl_SPI_lastoid, NULL, NULL);
431
/************************************************************
432
* Try to load the unknown procedure from pltcl_modules
433
************************************************************/
434
pltcl_init_load_unknown(interp);
370
437
/**********************************************************************
371
438
* pltcl_fetch_interp() - fetch the Tcl interpreter to use for a function
373
440
* This also takes care of any on-first-use initialization required.
374
* The initialization work done here can't be done in the postmaster, and
375
* hence is not safe to do at library load time, because it may invoke
376
* arbitrary user-defined code.
377
441
* Note: we assume caller has already connected to SPI.
378
442
**********************************************************************/
443
static pltcl_interp_desc *
380
444
pltcl_fetch_interp(bool pltrusted)
447
pltcl_interp_desc *interp_desc;
384
/* On first use, we try to load the unknown procedure from pltcl_modules */
450
/* Find or create the interpreter hashtable entry for this userid */
387
interp = pltcl_safe_interp;
388
if (!pltcl_be_safe_init_done)
390
pltcl_init_load_unknown(interp);
391
pltcl_be_safe_init_done = true;
452
user_id = GetUserId();
396
interp = pltcl_norm_interp;
397
if (!pltcl_be_norm_init_done)
399
pltcl_init_load_unknown(interp);
400
pltcl_be_norm_init_done = true;
454
user_id = InvalidOid;
456
interp_desc = hash_search(pltcl_interp_htab, &user_id,
460
pltcl_init_interp(interp_desc, pltrusted);
407
465
/**********************************************************************
1108
1171
elog(ERROR, "cache lookup failed for function %u", fn_oid);
1109
1172
procStruct = (Form_pg_proc) GETSTRUCT(procTup);
1111
/************************************************************
1112
* Build our internal proc name from the functions Oid
1113
************************************************************/
1115
snprintf(internal_proname, sizeof(internal_proname),
1116
"__PLTcl_proc_%u", fn_oid);
1118
snprintf(internal_proname, sizeof(internal_proname),
1119
"__PLTcl_proc_%u_trigger_%u", fn_oid, tgreloid);
1121
/************************************************************
1122
* Lookup the internal proc name in the hashtable
1123
************************************************************/
1124
hashent = Tcl_FindHashEntry(pltcl_proc_hash, internal_proname);
1174
/* Try to find function in pltcl_proc_htab */
1175
proc_key.proc_id = fn_oid;
1176
proc_key.trig_id = tgreloid;
1177
proc_key.user_id = pltrusted ? GetUserId() : InvalidOid;
1179
proc_ptr = hash_search(pltcl_proc_htab, &proc_key,
1183
proc_ptr->proc_ptr = NULL;
1185
prodesc = proc_ptr->proc_ptr;
1126
1187
/************************************************************
1127
1188
* If it's present, must check whether it's still up to date.
1128
1189
* This is needed because CREATE OR REPLACE FUNCTION can modify the
1129
1190
* function's pg_proc entry without changing its OID.
1130
1191
************************************************************/
1131
if (hashent != NULL)
1192
if (prodesc != NULL)
1135
prodesc = (pltcl_proc_desc *) Tcl_GetHashValue(hashent);
1137
1196
uptodate = (prodesc->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
1138
1197
ItemPointerEquals(&prodesc->fn_tid, &procTup->t_self));
1142
Tcl_DeleteHashEntry(hashent);
1201
proc_ptr->proc_ptr = NULL;
1177
1249
MemSet(prodesc, 0, sizeof(pltcl_proc_desc));
1178
1250
prodesc->user_proname = strdup(NameStr(procStruct->proname));
1179
1251
prodesc->internal_proname = strdup(internal_proname);
1252
if (prodesc->user_proname == NULL || prodesc->internal_proname == NULL)
1254
(errcode(ERRCODE_OUT_OF_MEMORY),
1255
errmsg("out of memory")));
1180
1256
prodesc->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
1181
1257
prodesc->fn_tid = procTup->t_self;
1183
1259
/* Remember if function is STABLE/IMMUTABLE */
1184
1260
prodesc->fn_readonly =
1185
1261
(procStruct->provolatile != PROVOLATILE_VOLATILE);
1262
/* And whether it is trusted */
1263
prodesc->lanpltrusted = pltrusted;
1187
1265
/************************************************************
1188
* Lookup the pg_language tuple by Oid
1266
* Identify the interpreter to use for the function
1189
1267
************************************************************/
1190
langTup = SearchSysCache(LANGOID,
1191
ObjectIdGetDatum(procStruct->prolang),
1193
if (!HeapTupleIsValid(langTup))
1195
free(prodesc->user_proname);
1196
free(prodesc->internal_proname);
1198
elog(ERROR, "cache lookup failed for language %u",
1199
procStruct->prolang);
1201
langStruct = (Form_pg_language) GETSTRUCT(langTup);
1202
prodesc->lanpltrusted = langStruct->lanpltrusted;
1203
ReleaseSysCache(langTup);
1205
interp = pltcl_fetch_interp(prodesc->lanpltrusted);
1268
prodesc->interp_desc = pltcl_fetch_interp(prodesc->lanpltrusted);
1269
interp = prodesc->interp_desc->interp;
1207
1271
/************************************************************
1208
1272
* Get the required information for input conversion of the