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-2023, 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/acl.h"
28 #include "utils/builtins.h"
29 #include "utils/datetime.h"
30 
31 
32 #ifdef WIN32
33 
34 #ifdef rename
35 #undef rename
36 #endif
37 
38 #ifdef unlink
39 #undef unlink
40 #endif
41 #endif
42 
44 
54 
55 static int64 pg_file_write_internal(text *file, text *data, bool replace);
56 static bool pg_file_rename_internal(text *file1, text *file2, text *file3);
58 
59 
60 /*-----------------------
61  * some helper functions
62  */
63 
64 /*
65  * Convert a "text" filename argument to C string, and check it's allowable.
66  *
67  * Filename may be absolute or relative to the DataDir, but we only allow
68  * absolute paths that match DataDir.
69  */
70 static char *
72 {
73  char *filename = text_to_cstring(arg);
74 
75  canonicalize_path(filename); /* filename can change length here */
76 
77  /*
78  * Members of the 'pg_write_server_files' role are allowed to access any
79  * files on the server as the PG user, so no need to do any further checks
80  * here.
81  */
82  if (has_privs_of_role(GetUserId(), ROLE_PG_WRITE_SERVER_FILES))
83  return filename;
84 
85  /*
86  * User isn't a member of the pg_write_server_files role, so check if it's
87  * allowable
88  */
90  {
91  /* Allow absolute paths if within DataDir */
93  ereport(ERROR,
94  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
95  errmsg("absolute path not allowed")));
96  }
98  ereport(ERROR,
99  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
100  errmsg("path must be in or below the data directory")));
101 
102  return filename;
103 }
104 
105 
106 /*
107  * check for superuser, bark if not.
108  */
109 static void
111 {
112  if (!superuser())
113  ereport(ERROR,
114  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
115  errmsg("only superuser may access generic file functions")));
116 }
117 
118 
119 
120 /* ------------------------------------
121  * pg_file_write - old version
122  *
123  * The superuser() check here must be kept as the library might be upgraded
124  * without the extension being upgraded, meaning that in pre-1.1 installations
125  * these functions could be called by any user.
126  */
127 Datum
129 {
130  text *file = PG_GETARG_TEXT_PP(0);
132  bool replace = PG_GETARG_BOOL(2);
133  int64 count = 0;
134 
136 
137  count = pg_file_write_internal(file, data, replace);
138 
139  PG_RETURN_INT64(count);
140 }
141 
142 /* ------------------------------------
143  * pg_file_write_v1_1 - Version 1.1
144  *
145  * As of adminpack version 1.1, we no longer need to check if the user
146  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
147  * Users can then grant access to it based on their policies.
148  *
149  * Otherwise identical to pg_file_write (above).
150  */
151 Datum
153 {
154  text *file = PG_GETARG_TEXT_PP(0);
156  bool replace = PG_GETARG_BOOL(2);
157  int64 count = 0;
158 
159  count = pg_file_write_internal(file, data, replace);
160 
161  PG_RETURN_INT64(count);
162 }
163 
164 /* ------------------------------------
165  * pg_file_write_internal - Workhorse for pg_file_write functions.
166  *
167  * This handles the actual work for pg_file_write.
168  */
169 static int64
170 pg_file_write_internal(text *file, text *data, bool replace)
171 {
172  FILE *f;
173  char *filename;
174  int64 count = 0;
175 
177 
178  if (!replace)
179  {
180  struct stat fst;
181 
182  if (stat(filename, &fst) >= 0)
183  ereport(ERROR,
184  (errcode(ERRCODE_DUPLICATE_FILE),
185  errmsg("file \"%s\" exists", filename)));
186 
187  f = AllocateFile(filename, "wb");
188  }
189  else
190  f = AllocateFile(filename, "ab");
191 
192  if (!f)
193  ereport(ERROR,
195  errmsg("could not open file \"%s\" for writing: %m",
196  filename)));
197 
198  count = fwrite(VARDATA_ANY(data), 1, VARSIZE_ANY_EXHDR(data), f);
199  if (count != VARSIZE_ANY_EXHDR(data) || FreeFile(f))
200  ereport(ERROR,
202  errmsg("could not write file \"%s\": %m", filename)));
203 
204  return (count);
205 }
206 
207 /* ------------------------------------
208  * pg_file_sync
209  *
210  * We REVOKE EXECUTE on the function from PUBLIC.
211  * Users can then grant access to it based on their policies.
212  */
213 Datum
215 {
216  char *filename;
217  struct stat fst;
218 
220 
221  if (stat(filename, &fst) < 0)
222  ereport(ERROR,
224  errmsg("could not stat file \"%s\": %m", filename)));
225 
227 
228  PG_RETURN_VOID();
229 }
230 
231 /* ------------------------------------
232  * pg_file_rename - old version
233  *
234  * The superuser() check here must be kept as the library might be upgraded
235  * without the extension being upgraded, meaning that in pre-1.1 installations
236  * these functions could be called by any user.
237  */
238 Datum
240 {
241  text *file1;
242  text *file2;
243  text *file3;
244  bool result;
245 
247 
248  if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
249  PG_RETURN_NULL();
250 
251  file1 = PG_GETARG_TEXT_PP(0);
252  file2 = PG_GETARG_TEXT_PP(1);
253 
254  if (PG_ARGISNULL(2))
255  file3 = NULL;
256  else
257  file3 = PG_GETARG_TEXT_PP(2);
258 
259  result = pg_file_rename_internal(file1, file2, file3);
260 
261  PG_RETURN_BOOL(result);
262 }
263 
264 /* ------------------------------------
265  * pg_file_rename_v1_1 - Version 1.1
266  *
267  * As of adminpack version 1.1, we no longer need to check if the user
268  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
269  * Users can then grant access to it based on their policies.
270  *
271  * Otherwise identical to pg_file_write (above).
272  */
273 Datum
275 {
276  text *file1;
277  text *file2;
278  text *file3;
279  bool result;
280 
281  if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
282  PG_RETURN_NULL();
283 
284  file1 = PG_GETARG_TEXT_PP(0);
285  file2 = PG_GETARG_TEXT_PP(1);
286 
287  if (PG_ARGISNULL(2))
288  file3 = NULL;
289  else
290  file3 = PG_GETARG_TEXT_PP(2);
291 
292  result = pg_file_rename_internal(file1, file2, file3);
293 
294  PG_RETURN_BOOL(result);
295 }
296 
297 /* ------------------------------------
298  * pg_file_rename_internal - Workhorse for pg_file_rename functions.
299  *
300  * This handles the actual work for pg_file_rename.
301  */
302 static bool
303 pg_file_rename_internal(text *file1, text *file2, text *file3)
304 {
305  char *fn1,
306  *fn2,
307  *fn3;
308  int rc;
309 
310  fn1 = convert_and_check_filename(file1);
311  fn2 = convert_and_check_filename(file2);
312 
313  if (file3 == NULL)
314  fn3 = NULL;
315  else
316  fn3 = convert_and_check_filename(file3);
317 
318  if (access(fn1, W_OK) < 0)
319  {
322  errmsg("file \"%s\" is not accessible: %m", fn1)));
323 
324  return false;
325  }
326 
327  if (fn3 && access(fn2, W_OK) < 0)
328  {
331  errmsg("file \"%s\" is not accessible: %m", fn2)));
332 
333  return false;
334  }
335 
336  rc = access(fn3 ? fn3 : fn2, W_OK);
337  if (rc >= 0 || errno != ENOENT)
338  {
339  ereport(ERROR,
340  (errcode(ERRCODE_DUPLICATE_FILE),
341  errmsg("cannot rename to target file \"%s\"",
342  fn3 ? fn3 : fn2)));
343  }
344 
345  if (fn3)
346  {
347  if (rename(fn2, fn3) != 0)
348  {
349  ereport(ERROR,
351  errmsg("could not rename \"%s\" to \"%s\": %m",
352  fn2, fn3)));
353  }
354  if (rename(fn1, fn2) != 0)
355  {
358  errmsg("could not rename \"%s\" to \"%s\": %m",
359  fn1, fn2)));
360 
361  if (rename(fn3, fn2) != 0)
362  {
363  ereport(ERROR,
365  errmsg("could not rename \"%s\" back to \"%s\": %m",
366  fn3, fn2)));
367  }
368  else
369  {
370  ereport(ERROR,
371  (errcode(ERRCODE_UNDEFINED_FILE),
372  errmsg("renaming \"%s\" to \"%s\" was reverted",
373  fn2, fn3)));
374  }
375  }
376  }
377  else if (rename(fn1, fn2) != 0)
378  {
379  ereport(ERROR,
381  errmsg("could not rename \"%s\" to \"%s\": %m", fn1, fn2)));
382  }
383 
384  return true;
385 }
386 
387 
388 /* ------------------------------------
389  * pg_file_unlink - old version
390  *
391  * The superuser() check here must be kept as the library might be upgraded
392  * without the extension being upgraded, meaning that in pre-1.1 installations
393  * these functions could be called by any user.
394  */
395 Datum
397 {
398  char *filename;
399 
401 
403 
404  if (access(filename, W_OK) < 0)
405  {
406  if (errno == ENOENT)
407  PG_RETURN_BOOL(false);
408  else
409  ereport(ERROR,
411  errmsg("file \"%s\" is not accessible: %m", filename)));
412  }
413 
414  if (unlink(filename) < 0)
415  {
418  errmsg("could not unlink file \"%s\": %m", filename)));
419 
420  PG_RETURN_BOOL(false);
421  }
422  PG_RETURN_BOOL(true);
423 }
424 
425 
426 /* ------------------------------------
427  * pg_file_unlink_v1_1 - Version 1.1
428  *
429  * As of adminpack version 1.1, we no longer need to check if the user
430  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
431  * Users can then grant access to it based on their policies.
432  *
433  * Otherwise identical to pg_file_unlink (above).
434  */
435 Datum
437 {
438  char *filename;
439 
441 
442  if (access(filename, W_OK) < 0)
443  {
444  if (errno == ENOENT)
445  PG_RETURN_BOOL(false);
446  else
447  ereport(ERROR,
449  errmsg("file \"%s\" is not accessible: %m", filename)));
450  }
451 
452  if (unlink(filename) < 0)
453  {
456  errmsg("could not unlink file \"%s\": %m", filename)));
457 
458  PG_RETURN_BOOL(false);
459  }
460  PG_RETURN_BOOL(true);
461 }
462 
463 /* ------------------------------------
464  * pg_logdir_ls - Old version
465  *
466  * The superuser() check here must be kept as the library might be upgraded
467  * without the extension being upgraded, meaning that in pre-1.1 installations
468  * these functions could be called by any user.
469  */
470 Datum
472 {
473  if (!superuser())
474  ereport(ERROR,
475  (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
476  errmsg("only superuser can list the log directory")));
477 
478  return (pg_logdir_ls_internal(fcinfo));
479 }
480 
481 /* ------------------------------------
482  * pg_logdir_ls_v1_1 - Version 1.1
483  *
484  * As of adminpack version 1.1, we no longer need to check if the user
485  * is a superuser because we REVOKE EXECUTE on the function from PUBLIC.
486  * Users can then grant access to it based on their policies.
487  *
488  * Otherwise identical to pg_logdir_ls (above).
489  */
490 Datum
492 {
493  return (pg_logdir_ls_internal(fcinfo));
494 }
495 
496 static Datum
498 {
499  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
500  bool randomAccess;
501  TupleDesc tupdesc;
502  Tuplestorestate *tupstore;
503  AttInMetadata *attinmeta;
504  DIR *dirdesc;
505  struct dirent *de;
506  MemoryContext oldcontext;
507 
508  if (strcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log") != 0)
509  ereport(ERROR,
510  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
511  errmsg("the log_filename parameter must equal 'postgresql-%%Y-%%m-%%d_%%H%%M%%S.log'")));
512 
513  /* check to see if caller supports us returning a tuplestore */
514  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
515  ereport(ERROR,
516  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
517  errmsg("set-valued function called in context that cannot accept a set")));
518  if (!(rsinfo->allowedModes & SFRM_Materialize))
519  ereport(ERROR,
520  (errcode(ERRCODE_SYNTAX_ERROR),
521  errmsg("materialize mode required, but it is not allowed in this context")));
522 
523  /* The tupdesc and tuplestore must be created in ecxt_per_query_memory */
525 
526  tupdesc = CreateTemplateTupleDesc(2);
527  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "starttime",
528  TIMESTAMPOID, -1, 0);
529  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "filename",
530  TEXTOID, -1, 0);
531 
532  randomAccess = (rsinfo->allowedModes & SFRM_Materialize_Random) != 0;
533  tupstore = tuplestore_begin_heap(randomAccess, false, work_mem);
534  rsinfo->returnMode = SFRM_Materialize;
535  rsinfo->setResult = tupstore;
536  rsinfo->setDesc = tupdesc;
537 
538  MemoryContextSwitchTo(oldcontext);
539 
540  attinmeta = TupleDescGetAttInMetadata(tupdesc);
541 
542  dirdesc = AllocateDir(Log_directory);
543  while ((de = ReadDir(dirdesc, Log_directory)) != NULL)
544  {
545  char *values[2];
546  HeapTuple tuple;
547  char timestampbuf[32];
548  char *field[MAXDATEFIELDS];
549  char lowstr[MAXDATELEN + 1];
550  int dtype;
551  int nf,
552  ftype[MAXDATEFIELDS];
553  fsec_t fsec;
554  int tz = 0;
555  struct pg_tm date;
556  DateTimeErrorExtra extra;
557 
558  /*
559  * Default format: postgresql-YYYY-MM-DD_HHMMSS.log
560  */
561  if (strlen(de->d_name) != 32
562  || strncmp(de->d_name, "postgresql-", 11) != 0
563  || de->d_name[21] != '_'
564  || strcmp(de->d_name + 28, ".log") != 0)
565  continue;
566 
567  /* extract timestamp portion of filename */
568  strcpy(timestampbuf, de->d_name + 11);
569  timestampbuf[17] = '\0';
570 
571  /* parse and decode expected timestamp to verify it's OK format */
572  if (ParseDateTime(timestampbuf, lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
573  continue;
574 
575  if (DecodeDateTime(field, ftype, nf,
576  &dtype, &date, &fsec, &tz, &extra))
577  continue;
578 
579  /* Seems the timestamp is OK; prepare and return tuple */
580 
581  values[0] = timestampbuf;
582  values[1] = psprintf("%s/%s", Log_directory, de->d_name);
583 
584  tuple = BuildTupleFromCStrings(attinmeta, values);
585 
586  tuplestore_puttuple(tupstore, tuple);
587  }
588 
589  FreeDir(dirdesc);
590  return (Datum) 0;
591 }
bool has_privs_of_role(Oid member, Oid role)
Definition: acl.c:5060
Datum pg_file_sync(PG_FUNCTION_ARGS)
Definition: adminpack.c:214
static int64 pg_file_write_internal(text *file, text *data, bool replace)
Definition: adminpack.c:170
PG_MODULE_MAGIC
Definition: adminpack.c:43
Datum pg_file_rename(PG_FUNCTION_ARGS)
Definition: adminpack.c:239
Datum pg_file_write_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:152
Datum pg_file_unlink_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:436
PG_FUNCTION_INFO_V1(pg_file_write)
static char * convert_and_check_filename(text *arg)
Definition: adminpack.c:71
static void requireSuperuser(void)
Definition: adminpack.c:110
static Datum pg_logdir_ls_internal(FunctionCallInfo fcinfo)
Definition: adminpack.c:497
Datum pg_file_unlink(PG_FUNCTION_ARGS)
Definition: adminpack.c:396
Datum pg_file_write(PG_FUNCTION_ARGS)
Definition: adminpack.c:128
Datum pg_logdir_ls_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:491
Datum pg_file_rename_v1_1(PG_FUNCTION_ARGS)
Definition: adminpack.c:274
static bool pg_file_rename_internal(text *file1, text *file2, text *file3)
Definition: adminpack.c:303
Datum pg_logdir_ls(PG_FUNCTION_ARGS)
Definition: adminpack.c:471
int16 AttrNumber
Definition: attnum.h:21
int ParseDateTime(const char *timestr, char *workbuf, size_t buflen, char **field, int *ftype, int maxfields, int *numfields)
Definition: datetime.c:756
int DecodeDateTime(char **field, int *ftype, int nf, int *dtype, struct pg_tm *tm, fsec_t *fsec, int *tzp, DateTimeErrorExtra *extra)
Definition: datetime.c:980
static Datum values[MAXATTR]
Definition: bootstrap.c:156
int32 fsec_t
Definition: timestamp.h:41
int errcode_for_file_access(void)
Definition: elog.c:881
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define WARNING
Definition: elog.h:36
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2134
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2085
@ SFRM_Materialize_Random
Definition: execnodes.h:311
@ SFRM_Materialize
Definition: execnodes.h:310
struct dirent * ReadDir(DIR *dir, const char *dirname)
Definition: fd.c:2879
int FreeDir(DIR *dir)
Definition: fd.c:2931
FILE * AllocateFile(const char *name, const char *mode)
Definition: fd.c:2553
int fsync_fname_ext(const char *fname, bool isdir, bool ignore_perm, int elevel)
Definition: fd.c:3767
int FreeFile(FILE *file)
Definition: fd.c:2751
DIR * AllocateDir(const char *dirname)
Definition: fd.c:2813
#define PG_RETURN_VOID()
Definition: fmgr.h:349
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
char * DataDir
Definition: globals.c:66
int work_mem
Definition: globals.c:127
#define MAXDATEFIELDS
Definition: datetime.h:202
#define MAXDATELEN
Definition: datetime.h:200
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
Oid GetUserId(void)
Definition: miscinit.c:508
#define IsA(nodeptr, _type_)
Definition: nodes.h:179
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
void * arg
const void * data
static char * filename
Definition: pg_dumpall.c:121
long date
Definition: pgtypes_date.h:9
#define is_absolute_path(filename)
Definition: port.h:103
bool path_is_prefix_of_path(const char *path1, const char *path2)
Definition: path.c:559
bool path_is_relative_and_below_cwd(const char *path)
Definition: path.c:526
void canonicalize_path(char *path)
Definition: path.c:264
uintptr_t Datum
Definition: postgres.h:64
short access
Definition: preproc-type.c:36
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
Definition: dirent.c:26
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:255
fmNodePtr resultinfo
Definition: fmgr.h:89
SetFunctionReturnMode returnMode
Definition: execnodes.h:329
ExprContext * econtext
Definition: execnodes.h:325
TupleDesc setDesc
Definition: execnodes.h:333
Tuplestorestate * setResult
Definition: execnodes.h:332
int allowedModes
Definition: execnodes.h:327
Definition: dirent.h:10
Definition: pgtime.h:35
unsigned short st_mode
Definition: win32_port.h:268
Definition: c.h:676
bool superuser(void)
Definition: superuser.c:46
char * Log_directory
Definition: syslogger.c:74
char * Log_filename
Definition: syslogger.c:75
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:605
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
Definition: tuplestore.c:730
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
char * text_to_cstring(const text *t)
Definition: varlena.c:217
#define stat
Definition: win32_port.h:284
#define S_ISDIR(m)
Definition: win32_port.h:325