PostgreSQL Source Code  git master
adminpack.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * adminpack.c
4  *
5  *
6  * Copyright (c) 2002-2018, PostgreSQL Global Development Group
7  *
8  * Author: Andreas Pflug <pgadmin@pse-consulting.de>
9  *
10  * IDENTIFICATION
11  * contrib/adminpack/adminpack.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <sys/file.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 
21 #include "catalog/pg_authid.h"
22 #include "catalog/pg_type.h"
23 #include "funcapi.h"
24 #include "miscadmin.h"
25 #include "postmaster/syslogger.h"
26 #include "storage/fd.h"
27 #include "utils/builtins.h"
28 #include "utils/datetime.h"
29 
30 
31 #ifdef WIN32
32 
33 #ifdef rename
34 #undef rename
35 #endif
36 
37 #ifdef unlink
38 #undef unlink
39 #endif
40 #endif
41 
43 
52 
53 static int64 pg_file_write_internal(text *file, text *data, bool replace);
54 static bool pg_file_rename_internal(text *file1, text *file2, text *file3);
56 
57 typedef struct
58 {
59  char *location;
62 
63 /*-----------------------
64  * some helper functions
65  */
66 
67 /*
68  * Convert a "text" filename argument to C string, and check it's allowable.
69  *
70  * Filename may be absolute or relative to the DataDir, but we only allow
71  * absolute paths that match DataDir or Log_directory.
72  */
73 static char *
75 {
76  char *filename = text_to_cstring(arg);
77 
78  canonicalize_path(filename); /* filename can change length here */
79 
80  /*
81  * Members of the 'pg_write_server_files' role are allowed to access any
82  * files on the server as the PG user, so no need to do any further checks
83  * here.
84  */
85  if (is_member_of_role(GetUserId(), DEFAULT_ROLE_WRITE_SERVER_FILES))
86  return filename;
87 
88  /* User isn't a member of the default role, so check if it's allowable */
89  if (is_absolute_path(filename))
90  {
91  /* Disallow '/a/b/data/..' */
92  if (path_contains_parent_reference(filename))
93  ereport(ERROR,
94  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
95  (errmsg("reference to parent directory (\"..\") not allowed"))));
96 
97  /*
98  * Allow absolute paths if within DataDir or Log_directory, even
99  * though Log_directory might be outside DataDir.
100  */
101  if (!path_is_prefix_of_path(DataDir, filename) &&
102  (!logAllowed || !is_absolute_path(Log_directory) ||
104  ereport(ERROR,
105  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
106  (errmsg("absolute path not allowed"))));
107  }
108  else if (!path_is_relative_and_below_cwd(filename))
109  ereport(ERROR,
110  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
111  (errmsg("path must be in or below the current directory"))));
112 
113  return filename;
114 }
115 
116 
117 /*
118  * check for superuser, bark if not.
119  */
120 static void
122 {
123  if (!superuser())
124  ereport(ERROR,
125  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
126  (errmsg("only superuser may access generic file functions"))));
127 }
128 
129 
130 
131 /* ------------------------------------
132  * pg_file_write - old version
133  *
134  * The superuser() check here must be kept as the library might be upgraded
135  * without the extension being upgraded, meaning that in pre-1.1 installations
136  * these functions could be called by any user.
137  */
138 Datum
140 {
141  text *file = PG_GETARG_TEXT_PP(0);
142  text *data = PG_GETARG_TEXT_PP(1);
143  bool replace = PG_GETARG_BOOL(2);
144  int64 count = 0;
145 
147 
148  count = pg_file_write_internal(file, data, replace);
149 
150  PG_RETURN_INT64(count);
151 }
152 
153 /* ------------------------------------
154  * pg_file_write_v1_1 - Version 1.1
155  *
156  * As of adminpack version 1.1, we no longer need to check if the user
157  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
158  * Users can then grant access to it based on their policies.
159  *
160  * Otherwise identical to pg_file_write (above).
161  */
162 Datum
164 {
165  text *file = PG_GETARG_TEXT_PP(0);
166  text *data = PG_GETARG_TEXT_PP(1);
167  bool replace = PG_GETARG_BOOL(2);
168  int64 count = 0;
169 
170  count = pg_file_write_internal(file, data, replace);
171 
172  PG_RETURN_INT64(count);
173 }
174 
175 /* ------------------------------------
176  * pg_file_write_internal - Workhorse for pg_file_write functions.
177  *
178  * This handles the actual work for pg_file_write.
179  */
180 static int64
181 pg_file_write_internal(text *file, text *data, bool replace)
182 {
183  FILE *f;
184  char *filename;
185  int64 count = 0;
186 
187  filename = convert_and_check_filename(file, false);
188 
189  if (!replace)
190  {
191  struct stat fst;
192 
193  if (stat(filename, &fst) >= 0)
194  ereport(ERROR,
195  (ERRCODE_DUPLICATE_FILE,
196  errmsg("file \"%s\" exists", filename)));
197 
198  f = AllocateFile(filename, "wb");
199  }
200  else
201  f = AllocateFile(filename, "ab");
202 
203  if (!f)
204  ereport(ERROR,
206  errmsg("could not open file \"%s\" for writing: %m",
207  filename)));
208 
209  count = fwrite(VARDATA_ANY(data), 1, VARSIZE_ANY_EXHDR(data), f);
210  if (count != VARSIZE_ANY_EXHDR(data) || FreeFile(f))
211  ereport(ERROR,
213  errmsg("could not write file \"%s\": %m", filename)));
214 
215  return (count);
216 }
217 
218 /* ------------------------------------
219  * pg_file_rename - old version
220  *
221  * The superuser() check here must be kept as the library might be upgraded
222  * without the extension being upgraded, meaning that in pre-1.1 installations
223  * these functions could be called by any user.
224  */
225 Datum
227 {
228  text *file1;
229  text *file2;
230  text *file3;
231  bool result;
232 
234 
235  if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
236  PG_RETURN_NULL();
237 
238  file1 = PG_GETARG_TEXT_PP(0);
239  file2 = PG_GETARG_TEXT_PP(1);
240 
241  if (PG_ARGISNULL(2))
242  file3 = NULL;
243  else
244  file3 = PG_GETARG_TEXT_PP(2);
245 
246  result = pg_file_rename_internal(file1, file2, file3);
247 
248  PG_RETURN_BOOL(result);
249 }
250 
251 /* ------------------------------------
252  * pg_file_rename_v1_1 - Version 1.1
253  *
254  * As of adminpack version 1.1, we no longer need to check if the user
255  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
256  * Users can then grant access to it based on their policies.
257  *
258  * Otherwise identical to pg_file_write (above).
259  */
260 Datum
262 {
263  text *file1;
264  text *file2;
265  text *file3;
266  bool result;
267 
268  if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
269  PG_RETURN_NULL();
270 
271  file1 = PG_GETARG_TEXT_PP(0);
272  file2 = PG_GETARG_TEXT_PP(1);
273 
274  if (PG_ARGISNULL(2))
275  file3 = NULL;
276  else
277  file3 = PG_GETARG_TEXT_PP(2);
278 
279  result = pg_file_rename_internal(file1, file2, file3);
280 
281  PG_RETURN_BOOL(result);
282 }
283 
284 /* ------------------------------------
285  * pg_file_rename_internal - Workhorse for pg_file_rename functions.
286  *
287  * This handles the actual work for pg_file_rename.
288  */
289 static bool
290 pg_file_rename_internal(text *file1, text *file2, text *file3)
291 {
292  char *fn1,
293  *fn2,
294  *fn3;
295  int rc;
296 
297  fn1 = convert_and_check_filename(file1, false);
298  fn2 = convert_and_check_filename(file2, false);
299 
300  if (file3 == NULL)
301  fn3 = NULL;
302  else
303  fn3 = convert_and_check_filename(file3, false);
304 
305  if (access(fn1, W_OK) < 0)
306  {
309  errmsg("file \"%s\" is not accessible: %m", fn1)));
310 
311  return false;
312  }
313 
314  if (fn3 && access(fn2, W_OK) < 0)
315  {
318  errmsg("file \"%s\" is not accessible: %m", fn2)));
319 
320  return false;
321  }
322 
323  rc = access(fn3 ? fn3 : fn2, W_OK);
324  if (rc >= 0 || errno != ENOENT)
325  {
326  ereport(ERROR,
327  (ERRCODE_DUPLICATE_FILE,
328  errmsg("cannot rename to target file \"%s\"",
329  fn3 ? fn3 : fn2)));
330  }
331 
332  if (fn3)
333  {
334  if (rename(fn2, fn3) != 0)
335  {
336  ereport(ERROR,
338  errmsg("could not rename \"%s\" to \"%s\": %m",
339  fn2, fn3)));
340  }
341  if (rename(fn1, fn2) != 0)
342  {
345  errmsg("could not rename \"%s\" to \"%s\": %m",
346  fn1, fn2)));
347 
348  if (rename(fn3, fn2) != 0)
349  {
350  ereport(ERROR,
352  errmsg("could not rename \"%s\" back to \"%s\": %m",
353  fn3, fn2)));
354  }
355  else
356  {
357  ereport(ERROR,
358  (ERRCODE_UNDEFINED_FILE,
359  errmsg("renaming \"%s\" to \"%s\" was reverted",
360  fn2, fn3)));
361  }
362  }
363  }
364  else if (rename(fn1, fn2) != 0)
365  {
366  ereport(ERROR,
368  errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
369  }
370 
371  return true;
372 }
373 
374 
375 /* ------------------------------------
376  * pg_file_unlink - old version
377  *
378  * The superuser() check here must be kept as the library might be upgraded
379  * without the extension being upgraded, meaning that in pre-1.1 installations
380  * these functions could be called by any user.
381  */
382 Datum
384 {
385  char *filename;
386 
388 
389  filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false);
390 
391  if (access(filename, W_OK) < 0)
392  {
393  if (errno == ENOENT)
394  PG_RETURN_BOOL(false);
395  else
396  ereport(ERROR,
398  errmsg("file \"%s\" is not accessible: %m", filename)));
399  }
400 
401  if (unlink(filename) < 0)
402  {
405  errmsg("could not unlink file \"%s\": %m", filename)));
406 
407  PG_RETURN_BOOL(false);
408  }
409  PG_RETURN_BOOL(true);
410 }
411 
412 
413 /* ------------------------------------
414  * pg_file_unlink_v1_1 - Version 1.1
415  *
416  * As of adminpack version 1.1, we no longer need to check if the user
417  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
418  * Users can then grant access to it based on their policies.
419  *
420  * Otherwise identical to pg_file_unlink (above).
421  */
422 Datum
424 {
425  char *filename;
426 
427  filename = convert_and_check_filename(PG_GETARG_TEXT_PP(0), false);
428 
429  if (access(filename, W_OK) < 0)
430  {
431  if (errno == ENOENT)
432  PG_RETURN_BOOL(false);
433  else
434  ereport(ERROR,
436  errmsg("file \"%s\" is not accessible: %m", filename)));
437  }
438 
439  if (unlink(filename) < 0)
440  {
443  errmsg("could not unlink file \"%s\": %m", filename)));
444 
445  PG_RETURN_BOOL(false);
446  }
447  PG_RETURN_BOOL(true);
448 }
449 
450 /* ------------------------------------
451  * pg_logdir_ls - Old version
452  *
453  * The superuser() check here must be kept as the library might be upgraded
454  * without the extension being upgraded, meaning that in pre-1.1 installations
455  * these functions could be called by any user.
456  */
457 Datum
459 {
460  if (!superuser())
461  ereport(ERROR,
462  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
463  (errmsg("only superuser can list the log directory"))));
464 
465  return (pg_logdir_ls_internal(fcinfo));
466 }
467 
468 /* ------------------------------------
469  * pg_logdir_ls_v1_1 - Version 1.1
470  *
471  * As of adminpack version 1.1, we no longer need to check if the user
472  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
473  * Users can then grant access to it based on their policies.
474  *
475  * Otherwise identical to pg_logdir_ls (above).
476  */
477 Datum
479 {
480  return (pg_logdir_ls_internal(fcinfo));
481 }
482 
483 static Datum
485 {
486  FuncCallContext *funcctx;
487  struct dirent *de;
488  directory_fctx *fctx;
489 
490  if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
491  ereport(ERROR,
492  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
493  (errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'"))));
494 
495  if (SRF_IS_FIRSTCALL())
496  {
497  MemoryContext oldcontext;
498  TupleDesc tupdesc;
499 
500  funcctx = SRF_FIRSTCALL_INIT();
501  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
502 
503  fctx = palloc(sizeof(directory_fctx));
504 
505  tupdesc = CreateTemplateTupleDesc(2, false);
506  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
507  TIMESTAMPOID, -1, 0);
508  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
509  TEXTOID, -1, 0);
510 
511  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
512 
513  fctx->location = pstrdup(Log_directory);
514  fctx->dirdesc = AllocateDir(fctx->location);
515 
516  if (!fctx->dirdesc)
517  ereport(ERROR,
519  errmsg("could not open directory \"%s\": %m",
520  fctx->location)));
521 
522  funcctx->user_fctx = fctx;
523  MemoryContextSwitchTo(oldcontext);
524  }
525 
526  funcctx = SRF_PERCALL_SETUP();
527  fctx = (directory_fctx *) funcctx->user_fctx;
528 
529  while ((de = ReadDir(fctx->dirdesc, fctx->location)) != NULL)
530  {
531  char *values[2];
532  HeapTuple tuple;
533  char timestampbuf[32];
534  char *field[MAXDATEFIELDS];
535  char lowstr[MAXDATELEN + 1];
536  int dtype;
537  int nf,
538  ftype[MAXDATEFIELDS];
539  fsec_t fsec;
540  int tz = 0;
541  struct pg_tm date;
542 
543  /*
544  * Default format: postgresql-YYYY-MM-DD_HHMMSS.log
545  */
546  if (strlen(de->d_name) != 32
547  || strncmp(de->d_name, "postgresql-", 11) != 0
548  || de->d_name[21] != '_'
549  || strcmp(de->d_name + 28, ".log") != 0)
550  continue;
551 
552  /* extract timestamp portion of filename */
553  strcpy(timestampbuf, de->d_name + 11);
554  timestampbuf[17] = '\0';
555 
556  /* parse and decode expected timestamp to verify it's OK format */
557  if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
558  continue;
559 
560  if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
561  continue;
562 
563  /* Seems the timestamp is OK; prepare and return tuple */
564 
565  values[0] = timestampbuf;
566  values[1] = psprintf("%s/%s", fctx->location, de->d_name);
567 
568  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
569 
570  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
571  }
572 
573  FreeDir(fctx->dirdesc);
574  SRF_RETURN_DONE(funcctx);
575 }
#define MAXDATELEN
Definition: datetime.h:203
Datum pg_file_write(PG_FUNCTION_ARGS)
Definition: adminpack.c:139
static bool pg_file_rename_internal(text *file1, text *file2, text *file3)
Definition: adminpack.c:290
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
char * Log_directory
Definition: syslogger.c:67
Oid GetUserId(void)
Definition: miscinit.c:379
Datum pg_file_write_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:163
Datum pg_logdir_ls_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:478
#define PG_RETURN_INT64(x)
Definition: fmgr.h:332
static char * convert_and_check_filename(text *arg, bool logAllowed)
Definition: adminpack.c:74
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:294
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:438
char * pstrdup(const char *in)
Definition: mcxt.c:1161
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
void canonicalize_path(char *path)
Definition: path.c:254
int errcode(int sqlerrcode)
Definition: elog.c:575
bool superuser(void)
Definition: superuser.c:47
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:244
Definition: pgtime.h:25
static Datum pg_logdir_ls_internal(FunctionCallInfo fcinfo)
Definition: adminpack.c:484
Definition: dirent.h:9
bool path_contains_parent_reference(const char *path)
Definition: path.c:376
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:298
Datum pg_file_unlink_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:423
static void requireSuperuser(void)
Definition: adminpack.c:121
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:1195
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:278
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:300
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp)
Definition: datetime.c:767
Definition: dirent.c:25
#define ERROR
Definition: elog.h:43
Datum pg_file_unlink(PG_FUNCTION_ARGS)
Definition: adminpack.c:383
DIR * dirdesc
Definition: adminpack.c:60
Datum pg_logdir_ls(PG_FUNCTION_ARGS)
Definition: adminpack.c:458
PG_FUNCTION_INFO_V1(pg_file_write)
AttInMetadata * attinmeta
Definition: funcapi.h:100
PG_MODULE_MAGIC
Definition: adminpack.c:42
int errcode_for_file_access(void)
Definition: elog.c:598
#define is_absolute_path(filename)
Definition: port.h:86
bool path_is_relative_and_below_cwd(const char *path)
Definition: path.c:405
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2336
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2590
int32 fsec_t
Definition: timestamp.h:41
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:600
#define ereport(elevel, rest)
Definition: elog.h:122
#define WARNING
Definition: elog.h:40
#define stat(a, b)
Definition: win32_port.h:266
Datum pg_file_rename(PG_FUNCTION_ARGS)
Definition: adminpack.c:226
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:324
uintptr_t Datum
Definition: postgres.h:367
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1146
bool is_member_of_role(Oid member, Oid role)
Definition: acl.c:4857
Datum pg_file_rename_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:261
#define PG_ARGISNULL(n)
Definition: fmgr.h:179
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2656
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:110
#define MAXDATEFIELDS
Definition: datetime.h:205
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:231
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:45
static int64 pg_file_write_internal(text *file, text *data, bool replace)
Definition: adminpack.c:181
char * Log_filename
Definition: syslogger.c:68
char * location
Definition: adminpack.c:59
int FreeFile(FILE *file)
Definition: fd.c:2528
static Datum values[MAXATTR]
Definition: bootstrap.c:164
char * text_to_cstring(const text *t)
Definition: varlena.c:182
static char * filename
Definition: pg_dumpall.c:87
void * user_fctx
Definition: funcapi.h:91
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:797
void * arg
char * DataDir
Definition: globals.c:63
Definition: c.h:516
#define PG_FUNCTION_ARGS
Definition: fmgr.h:163
char d_name[MAX_PATH]
Definition: dirent.h:14
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:546
int16 AttrNumber
Definition: attnum.h:21
#define PG_RETURN_NULL()
Definition: fmgr.h:310
int FreeDir(DIR *dir)
Definition: fd.c:2708
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:318
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:296