]> granicus.if.org Git - postgresql/blob - src/backend/utils/fmgr/dfmgr.c
c3710c62115f8228b3966e0ae65be2e1c6220681
[postgresql] / src / backend / utils / fmgr / dfmgr.c
1 /*-------------------------------------------------------------------------
2  *
3  * dfmgr.c
4  *        Dynamic function manager code.
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.91 2006/10/04 00:30:01 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include <sys/stat.h>
18
19 #ifndef WIN32_ONLY_COMPILER
20 #include "dynloader.h"
21 #else
22 #include "port/dynloader/win32.h"
23 #endif
24 #include "miscadmin.h"
25 #include "utils/dynamic_loader.h"
26 #include "utils/hsearch.h"
27
28
29 /* signatures for PostgreSQL-specific library init/fini functions */
30 typedef void (*PG_init_t) (void);
31 typedef void (*PG_fini_t) (void);
32
33 /* hashtable entry for rendezvous variables */
34 typedef struct
35 {
36         char            varName[NAMEDATALEN];   /* hash key (must be first) */
37         void       *varValue;
38 } rendezvousHashEntry;
39
40 /*
41  * List of dynamically loaded files (kept in malloc'd memory).
42  */
43
44 typedef struct df_files
45 {
46         struct df_files *next;          /* List link */
47         dev_t           device;                 /* Device file is on */
48 #ifndef WIN32                                   /* ensures we never again depend on this under
49                                                                  * win32 */
50         ino_t           inode;                  /* Inode number of file */
51 #endif
52         void       *handle;                     /* a handle for pg_dl* functions */
53         char            filename[1];    /* Full pathname of file */
54
55         /*
56          * we allocate the block big enough for actual length of pathname.
57          * filename[] must be last item in struct!
58          */
59 } DynamicFileList;
60
61 static DynamicFileList *file_list = NULL;
62 static DynamicFileList *file_tail = NULL;
63
64 /* stat() call under Win32 returns an st_ino field, but it has no meaning */
65 #ifndef WIN32
66 #define SAME_INODE(A,B) ((A).st_ino == (B).inode && (A).st_dev == (B).device)
67 #else
68 #define SAME_INODE(A,B) false
69 #endif
70
71 char       *Dynamic_library_path;
72
73 static void *internal_load_library(const char *libname);
74 static void internal_unload_library(const char *libname);
75 static bool file_exists(const char *name);
76 static char *expand_dynamic_library_name(const char *name);
77 static void check_restricted_library_name(const char *name);
78 static char *substitute_libpath_macro(const char *name);
79 static char *find_in_dynamic_libpath(const char *basename);
80
81 /* Magic structure that module needs to match to be accepted */
82 static const Pg_magic_struct magic_data = PG_MODULE_MAGIC_DATA;
83
84
85 /*
86  * Load the specified dynamic-link library file, and look for a function
87  * named funcname in it.
88  *
89  * If the function is not found, we raise an error if signalNotFound is true,
90  * else return (PGFunction) NULL.  Note that errors in loading the library
91  * will provoke ereport() regardless of signalNotFound.
92  *
93  * If filehandle is not NULL, then *filehandle will be set to a handle
94  * identifying the library file.  The filehandle can be used with
95  * lookup_external_function to lookup additional functions in the same file
96  * at less cost than repeating load_external_function.
97  */
98 PGFunction
99 load_external_function(char *filename, char *funcname,
100                                            bool signalNotFound, void **filehandle)
101 {
102         char       *fullname;
103         void       *lib_handle;
104         PGFunction      retval;
105
106         /* Expand the possibly-abbreviated filename to an exact path name */
107         fullname = expand_dynamic_library_name(filename);
108
109         /* Load the shared library, unless we already did */
110         lib_handle = internal_load_library(fullname);
111
112         /* Return handle if caller wants it */
113         if (filehandle)
114                 *filehandle = lib_handle;
115
116         /* Look up the function within the library */
117         retval = pg_dlsym(lib_handle, funcname);
118
119         if (retval == NULL && signalNotFound)
120                 ereport(ERROR,
121                                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
122                                  errmsg("could not find function \"%s\" in file \"%s\"",
123                                                 funcname, fullname)));
124
125         pfree(fullname);
126         return retval;
127 }
128
129 /*
130  * This function loads a shlib file without looking up any particular
131  * function in it.      If the same shlib has previously been loaded,
132  * unload and reload it.
133  *
134  * When 'restricted' is true, only libraries in the presumed-secure
135  * directory $libdir/plugins may be referenced.
136  */
137 void
138 load_file(const char *filename, bool restricted)
139 {
140         char       *fullname;
141
142         /* Apply security restriction if requested */
143         if (restricted)
144                 check_restricted_library_name(filename);
145
146         /* Expand the possibly-abbreviated filename to an exact path name */
147         fullname = expand_dynamic_library_name(filename);
148
149         /* Unload the library if currently loaded */
150         internal_unload_library(fullname);
151
152         /* Load the shared library */
153         (void) internal_load_library(fullname);
154
155         pfree(fullname);
156 }
157
158 /*
159  * Lookup a function whose library file is already loaded.
160  * Return (PGFunction) NULL if not found.
161  */
162 PGFunction
163 lookup_external_function(void *filehandle, char *funcname)
164 {
165         return pg_dlsym(filehandle, funcname);
166 }
167
168
169 /*
170  * Load the specified dynamic-link library file, unless it already is
171  * loaded.      Return the pg_dl* handle for the file.
172  *
173  * Note: libname is expected to be an exact name for the library file.
174  */
175 static void *
176 internal_load_library(const char *libname)
177 {
178         DynamicFileList *file_scanner;
179         PGModuleMagicFunction magic_func;
180         char       *load_error;
181         struct stat stat_buf;
182         PG_init_t       PG_init;
183
184         /*
185          * Scan the list of loaded FILES to see if the file has been loaded.
186          */
187         for (file_scanner = file_list;
188                  file_scanner != NULL &&
189                  strcmp(libname, file_scanner->filename) != 0;
190                  file_scanner = file_scanner->next)
191                 ;
192
193         if (file_scanner == NULL)
194         {
195                 /*
196                  * Check for same files - different paths (ie, symlink or link)
197                  */
198                 if (stat(libname, &stat_buf) == -1)
199                         ereport(ERROR,
200                                         (errcode_for_file_access(),
201                                          errmsg("could not access file \"%s\": %m",
202                                                         libname)));
203
204                 for (file_scanner = file_list;
205                          file_scanner != NULL &&
206                          !SAME_INODE(stat_buf, *file_scanner);
207                          file_scanner = file_scanner->next)
208                         ;
209         }
210
211         if (file_scanner == NULL)
212         {
213                 /*
214                  * File not loaded yet.
215                  */
216                 file_scanner = (DynamicFileList *)
217                         malloc(sizeof(DynamicFileList) + strlen(libname));
218                 if (file_scanner == NULL)
219                         ereport(ERROR,
220                                         (errcode(ERRCODE_OUT_OF_MEMORY),
221                                          errmsg("out of memory")));
222
223                 MemSet(file_scanner, 0, sizeof(DynamicFileList));
224                 strcpy(file_scanner->filename, libname);
225                 file_scanner->device = stat_buf.st_dev;
226 #ifndef WIN32
227                 file_scanner->inode = stat_buf.st_ino;
228 #endif
229                 file_scanner->next = NULL;
230
231                 file_scanner->handle = pg_dlopen(file_scanner->filename);
232                 if (file_scanner->handle == NULL)
233                 {
234                         load_error = (char *) pg_dlerror();
235                         free((char *) file_scanner);
236                         /* errcode_for_file_access might not be appropriate here? */
237                         ereport(ERROR,
238                                         (errcode_for_file_access(),
239                                          errmsg("could not load library \"%s\": %s",
240                                                         libname, load_error)));
241                 }
242
243                 /* Check the magic function to determine compatibility */
244                 magic_func = (PGModuleMagicFunction)
245                         pg_dlsym(file_scanner->handle, PG_MAGIC_FUNCTION_NAME_STRING);
246                 if (magic_func)
247                 {
248                         const Pg_magic_struct *magic_data_ptr = (*magic_func) ();
249
250                         if (magic_data_ptr->len != magic_data.len ||
251                                 memcmp(magic_data_ptr, &magic_data, magic_data.len) != 0)
252                         {
253                                 /* copy data block before unlinking library */
254                                 Pg_magic_struct module_magic_data = *magic_data_ptr;
255
256                                 /* try to unlink library */
257                                 pg_dlclose(file_scanner->handle);
258                                 free((char *) file_scanner);
259
260                                 /*
261                                  * Report suitable error.  It's probably not worth writing a
262                                  * separate error message for each field; only the most common
263                                  * case of wrong major version gets its own message.
264                                  */
265                                 if (module_magic_data.version != magic_data.version)
266                                         ereport(ERROR,
267                                          (errmsg("incompatible library \"%s\": version mismatch",
268                                                          libname),
269                                           errdetail("Server is version %d.%d, library is version %d.%d.",
270                                                                 magic_data.version / 100,
271                                                                 magic_data.version % 100,
272                                                                 module_magic_data.version / 100,
273                                                                 module_magic_data.version % 100)));
274                                 ereport(ERROR,
275                                  (errmsg("incompatible library \"%s\": magic block mismatch",
276                                                  libname)));
277                         }
278                 }
279                 else
280                 {
281                         /* try to unlink library */
282                         pg_dlclose(file_scanner->handle);
283                         free((char *) file_scanner);
284                         /* complain */
285                         ereport(ERROR,
286                                   (errmsg("incompatible library \"%s\": missing magic block",
287                                                   libname),
288                                    errhint("Extension libraries are now required to use the PG_MODULE_MAGIC macro.")));
289                 }
290
291                 /*
292                  * If the library has a _PG_init() function, call it.
293                  */
294                 PG_init = (PG_init_t) pg_dlsym(file_scanner->handle, "_PG_init");
295                 if (PG_init)
296                         (*PG_init) ();
297
298                 /* OK to link it into list */
299                 if (file_list == NULL)
300                         file_list = file_scanner;
301                 else
302                         file_tail->next = file_scanner;
303                 file_tail = file_scanner;
304         }
305
306         return file_scanner->handle;
307 }
308
309 /*
310  * Unload the specified dynamic-link library file, if it is loaded.
311  *
312  * Note: libname is expected to be an exact name for the library file.
313  */
314 static void
315 internal_unload_library(const char *libname)
316 {
317         DynamicFileList *file_scanner,
318                            *prv,
319                            *nxt;
320         struct stat stat_buf;
321         PG_fini_t       PG_fini;
322
323         /*
324          * We need to do stat() in order to determine whether this is the same
325          * file as a previously loaded file; it's also handy so as to give a good
326          * error message if bogus file name given.
327          */
328         if (stat(libname, &stat_buf) == -1)
329                 ereport(ERROR,
330                                 (errcode_for_file_access(),
331                                  errmsg("could not access file \"%s\": %m", libname)));
332
333         /*
334          * We have to zap all entries in the list that match on either filename or
335          * inode, else internal_load_library() will still think it's present.
336          */
337         prv = NULL;
338         for (file_scanner = file_list; file_scanner != NULL; file_scanner = nxt)
339         {
340                 nxt = file_scanner->next;
341                 if (strcmp(libname, file_scanner->filename) == 0 ||
342                         SAME_INODE(stat_buf, *file_scanner))
343                 {
344                         if (prv)
345                                 prv->next = nxt;
346                         else
347                                 file_list = nxt;
348
349                         /*
350                          * If the library has a _PG_fini() function, call it.
351                          */
352                         PG_fini = (PG_fini_t) pg_dlsym(file_scanner->handle, "_PG_fini");
353                         if (PG_fini)
354                                 (*PG_fini) ();
355
356                         clear_external_function_hash(file_scanner->handle);
357                         pg_dlclose(file_scanner->handle);
358                         free((char *) file_scanner);
359                         /* prv does not change */
360                 }
361                 else
362                         prv = file_scanner;
363         }
364 }
365
366 static bool
367 file_exists(const char *name)
368 {
369         struct stat st;
370
371         AssertArg(name != NULL);
372
373         if (stat(name, &st) == 0)
374                 return S_ISDIR(st.st_mode) ? false : true;
375         else if (!(errno == ENOENT || errno == ENOTDIR || errno == EACCES))
376                 ereport(ERROR,
377                                 (errcode_for_file_access(),
378                                  errmsg("could not access file \"%s\": %m", name)));
379
380         return false;
381 }
382
383
384 /* Example format: ".so" */
385 #ifndef DLSUFFIX
386 #error "DLSUFFIX must be defined to compile this file."
387 #endif
388
389 /*
390  * If name contains a slash, check if the file exists, if so return
391  * the name.  Else (no slash) try to expand using search path (see
392  * find_in_dynamic_libpath below); if that works, return the fully
393  * expanded file name.  If the previous failed, append DLSUFFIX and
394  * try again.  If all fails, just return the original name.
395  *
396  * The result will always be freshly palloc'd.
397  */
398 static char *
399 expand_dynamic_library_name(const char *name)
400 {
401         bool            have_slash;
402         char       *new;
403         char       *full;
404
405         AssertArg(name);
406
407         have_slash = (first_dir_separator(name) != NULL);
408
409         if (!have_slash)
410         {
411                 full = find_in_dynamic_libpath(name);
412                 if (full)
413                         return full;
414         }
415         else
416         {
417                 full = substitute_libpath_macro(name);
418                 if (file_exists(full))
419                         return full;
420                 pfree(full);
421         }
422
423         new = palloc(strlen(name) + strlen(DLSUFFIX) + 1);
424         strcpy(new, name);
425         strcat(new, DLSUFFIX);
426
427         if (!have_slash)
428         {
429                 full = find_in_dynamic_libpath(new);
430                 pfree(new);
431                 if (full)
432                         return full;
433         }
434         else
435         {
436                 full = substitute_libpath_macro(new);
437                 pfree(new);
438                 if (file_exists(full))
439                         return full;
440                 pfree(full);
441         }
442
443         /*
444          * If we can't find the file, just return the string as-is. The ensuing
445          * load attempt will fail and report a suitable message.
446          */
447         return pstrdup(name);
448 }
449
450 /*
451  * Check a restricted library name.  It must begin with "$libdir/plugins/"
452  * and there must not be any directory separators after that (this is
453  * sufficient to prevent ".." style attacks).
454  */
455 static void
456 check_restricted_library_name(const char *name)
457 {
458         if (strncmp(name, "$libdir/plugins/", 16) != 0 ||
459                 first_dir_separator(name + 16) != NULL)
460                 ereport(ERROR,
461                                 (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
462                                  errmsg("access to library \"%s\" is not allowed",
463                                                 name)));
464 }
465
466 /*
467  * Substitute for any macros appearing in the given string.
468  * Result is always freshly palloc'd.
469  */
470 static char *
471 substitute_libpath_macro(const char *name)
472 {
473         const char *sep_ptr;
474         char       *ret;
475
476         AssertArg(name != NULL);
477
478         /* Currently, we only recognize $libdir at the start of the string */
479         if (name[0] != '$')
480                 return pstrdup(name);
481
482         if ((sep_ptr = first_dir_separator(name)) == NULL)
483                 sep_ptr = name + strlen(name);
484
485         if (strlen("$libdir") != sep_ptr - name ||
486                 strncmp(name, "$libdir", strlen("$libdir")) != 0)
487                 ereport(ERROR,
488                                 (errcode(ERRCODE_INVALID_NAME),
489                                  errmsg("invalid macro name in dynamic library path: %s",
490                                                 name)));
491
492         ret = palloc(strlen(pkglib_path) + strlen(sep_ptr) + 1);
493
494         strcpy(ret, pkglib_path);
495         strcat(ret, sep_ptr);
496
497         return ret;
498 }
499
500
501 /*
502  * Search for a file called 'basename' in the colon-separated search
503  * path Dynamic_library_path.  If the file is found, the full file name
504  * is returned in freshly palloc'd memory.  If the file is not found,
505  * return NULL.
506  */
507 static char *
508 find_in_dynamic_libpath(const char *basename)
509 {
510         const char *p;
511         size_t          baselen;
512
513         AssertArg(basename != NULL);
514         AssertArg(first_dir_separator(basename) == NULL);
515         AssertState(Dynamic_library_path != NULL);
516
517         p = Dynamic_library_path;
518         if (strlen(p) == 0)
519                 return NULL;
520
521         baselen = strlen(basename);
522
523         for (;;)
524         {
525                 size_t          len;
526                 char       *piece;
527                 char       *mangled;
528                 char       *full;
529
530                 piece = first_path_separator(p);
531                 if (piece == p)
532                         ereport(ERROR,
533                                         (errcode(ERRCODE_INVALID_NAME),
534                                          errmsg("zero-length component in parameter \"dynamic_library_path\"")));
535
536                 if (piece == 0)
537                         len = strlen(p);
538                 else
539                         len = piece - p;
540
541                 piece = palloc(len + 1);
542                 strncpy(piece, p, len);
543                 piece[len] = '\0';
544
545                 mangled = substitute_libpath_macro(piece);
546                 pfree(piece);
547
548                 canonicalize_path(mangled);
549
550                 /* only absolute paths */
551                 if (!is_absolute_path(mangled))
552                         ereport(ERROR,
553                                         (errcode(ERRCODE_INVALID_NAME),
554                                          errmsg("component in parameter \"dynamic_library_path\" is not an absolute path")));
555
556                 full = palloc(strlen(mangled) + 1 + baselen + 1);
557                 sprintf(full, "%s/%s", mangled, basename);
558                 pfree(mangled);
559
560                 elog(DEBUG3, "find_in_dynamic_libpath: trying \"%s\"", full);
561
562                 if (file_exists(full))
563                         return full;
564
565                 pfree(full);
566
567                 if (p[len] == '\0')
568                         break;
569                 else
570                         p += len + 1;
571         }
572
573         return NULL;
574 }
575
576
577 /*
578  * Find (or create) a rendezvous variable that one dynamically
579  * loaded library can use to meet up with another.
580  *
581  * On the first call of this function for a particular varName,
582  * a "rendezvous variable" is created with the given name.
583  * The value of the variable is a void pointer (initially set to NULL).
584  * Subsequent calls with the same varName just return the address of
585  * the existing variable.  Once created, a rendezvous variable lasts
586  * for the life of the process.
587  *
588  * Dynamically loaded libraries can use rendezvous variables
589  * to find each other and share information: they just need to agree
590  * on the variable name and the data it will point to.
591  */
592 void      **
593 find_rendezvous_variable(const char *varName)
594 {
595         static HTAB *rendezvousHash = NULL;
596
597         rendezvousHashEntry *hentry;
598         bool            found;
599
600         /* Create a hashtable if we haven't already done so in this process */
601         if (rendezvousHash == NULL)
602         {
603                 HASHCTL         ctl;
604
605                 MemSet(&ctl, 0, sizeof(ctl));
606                 ctl.keysize = NAMEDATALEN;
607                 ctl.entrysize = sizeof(rendezvousHashEntry);
608                 rendezvousHash = hash_create("Rendezvous variable hash",
609                                                                          16,
610                                                                          &ctl,
611                                                                          HASH_ELEM);
612         }
613
614         /* Find or create the hashtable entry for this varName */
615         hentry = (rendezvousHashEntry *) hash_search(rendezvousHash,
616                                                                                                  varName,
617                                                                                                  HASH_ENTER,
618                                                                                                  &found);
619
620         /* Initialize to NULL if first time */
621         if (!found)
622                 hentry->varValue = NULL;
623
624         return &hentry->varValue;
625 }