PostgreSQL Source Code: src/common/exec.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#define _DARWIN_BETTER_REALPATH
25
26#ifndef FRONTEND
28#else
30#endif
31
32#include <signal.h>
33#include <sys/stat.h>
36
37#ifdef EXEC_BACKEND
38#if defined(HAVE_SYS_PERSONALITY_H)
39#include <sys/personality.h>
40#elif defined(HAVE_SYS_PROCCTL_H)
41#include <sys/procctl.h>
42#endif
43#endif
44
46
47
48#if defined(WIN32) && !defined(_MSC_VER)
49extern int _CRT_glob = 0;
50#endif
51
52
53
54
55
56
57
58
59
60
61
62
63
64#ifndef FRONTEND
65#define log_error(errcodefn, ...) \
66 ereport(LOG, (errcodefn, errmsg_internal(__VA_ARGS__)))
67#else
68#define log_error(errcodefn, ...) \
69 (fprintf(stderr, __VA_ARGS__), fputc('\n', stderr))
70#endif
71
73static char *pg_realpath(const char *fname);
74
75#ifdef WIN32
76static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
77#endif
78
79
80
81
82
83
84
85
86
87int
89{
91 int is_r;
92 int is_x;
93
94#ifdef WIN32
95 char path_exe[MAXPGPATH + sizeof(".exe") - 1];
96
97
98 if (strlen(path) < strlen(".exe") ||
99 pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
100 {
101 strlcpy(path_exe, path, sizeof(path_exe) - 4);
102 strcat(path_exe, ".exe");
103 path = path_exe;
104 }
105#endif
106
107
108
109
110
111
112
114 return -1;
115
117 {
118
119
120
121
122
123
124 errno = S_ISDIR(buf.st_mode) ? EISDIR : EPERM;
125 return -1;
126 }
127
128
129
130
131
132#ifndef WIN32
133 is_r = (access(path, R_OK) == 0);
134 is_x = (access(path, X_OK) == 0);
135
136#else
139 errno = EACCES;
140#endif
141 return is_x ? (is_r ? 0 : -2) : -1;
142}
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159int
161{
162 char *path;
163
164
165
166
169 {
172
174 _("invalid binary \"%s\": %m"), retpath);
175 return -1;
176 }
177
178#ifdef WIN32
179
182#endif
183
184
185
186
187
188 if ((path = getenv("PATH")) && *path)
189 {
190 char *startp = NULL,
191 *endp = NULL;
192
193 do
194 {
195 if (!startp)
196 startp = path;
197 else
198 startp = endp + 1;
199
201 if (!endp)
202 endp = startp + strlen(startp);
203
205
208
210 {
211 case 0:
213 case -1:
214 break;
215 case -2:
217 _("could not read binary \"%s\": %m"),
218 retpath);
219 break;
220 }
221 } while (*endp);
222 }
223
225 _("could not find a \"%s\" to execute"), argv0);
226 return -1;
227}
228
229
230
231
232
233
234
235
236
237
238
239
240static int
242{
243
244
245
246
248
249 if (abspath == NULL)
250 {
252 _("could not resolve path \"%s\" to absolute form: %m"),
253 path);
254 return -1;
255 }
257 free(abspath);
258
259#ifdef WIN32
260
262#endif
263
264 return 0;
265}
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281static char *
283{
284 char *path;
285
286#ifndef WIN32
287 path = realpath(fname, NULL);
288#else
289
290
291
292
293
294
295
296
297 errno = 0;
298 path = _fullpath(NULL, fname, 0);
299#endif
300
301 return path;
302}
303
304
305
306
307
308
309int
311 const char *versionstr, char *retpath)
312{
314 char *line;
315
317 return -1;
318
319
322
323
325 "/%s%s", target, EXE);
326
328 return -1;
329
330 snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath);
331
333 return -1;
334
335 if (strcmp(line, versionstr) != 0)
336 {
338 return -2;
339 }
340
342 return 0;
343}
344
345
346
347
348
349
350
351char *
353{
354 FILE *pipe_cmd;
355 char *line;
356
357 fflush(NULL);
358
359 errno = 0;
360 if ((pipe_cmd = popen(cmd, "r")) == NULL)
361 {
363 _("could not execute command \"%s\": %m"), cmd);
364 return NULL;
365 }
366
367
368 errno = 0;
370
371 if (line == NULL)
372 {
373 if (ferror(pipe_cmd))
375 _("could not read from command \"%s\": %m"), cmd);
376 else
378 _("no data was returned by command \"%s\""), cmd);
379 }
380
382
383 return line;
384}
385
386
387
388
389
390int
392{
393 int exitstatus;
394 char *reason;
395
396 exitstatus = pclose(stream);
397
398 if (exitstatus == 0)
399 return 0;
400
401 if (exitstatus == -1)
402 {
403
405 _("%s() failed: %m"), "pclose");
406 }
407 else
408 {
411 "%s", reason);
413 }
414 return exitstatus;
415}
416
417
418
419
420
421
422
423
424
425
426
427
428void
430{
433
434
436 {
438
439
440
441
442
443
444
445
446
447
448 }
449
451 return;
452
453#ifdef ENABLE_NLS
455 bindtextdomain(app, path);
456 textdomain(app);
457
458 setenv("PGLOCALEDIR", path, 0);
459#endif
460
461 if (getenv("PGSYSCONFDIR") == NULL)
462 {
464
465 setenv("PGSYSCONFDIR", path, 0);
466 }
467}
468
469#ifdef EXEC_BACKEND
470
471
472
473
474
475
476
477
478int
479pg_disable_aslr(void)
480{
481#if defined(HAVE_SYS_PERSONALITY_H)
482 return personality(ADDR_NO_RANDOMIZE);
483#elif defined(HAVE_SYS_PROCCTL_H) && defined(PROC_ASLR_FORCE_DISABLE)
484 int data = PROC_ASLR_FORCE_DISABLE;
485
486 return procctl(P_PID, 0, PROC_ASLR_CTL, &data);
487#else
488 errno = ENOSYS;
489 return -1;
490#endif
491}
492#endif
493
494#ifdef WIN32
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518BOOL
520{
521 int i;
522 ACL_SIZE_INFORMATION asi;
523 ACCESS_ALLOWED_ACE *pace;
524 DWORD dwNewAclSize;
525 DWORD dwSize = 0;
526 DWORD dwTokenInfoLength = 0;
527 PACL pacl = NULL;
528 PTOKEN_USER pTokenUser = NULL;
529 TOKEN_DEFAULT_DACL tddNew;
530 TOKEN_DEFAULT_DACL *ptdd = NULL;
531 TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl;
532 BOOL ret = FALSE;
533
534
535 if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize))
536 {
537 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
538 {
539 ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize);
540 if (ptdd == NULL)
541 {
543 _("out of memory"));
545 }
546
547 if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize))
548 {
550 "could not get token information: error code %lu",
551 GetLastError());
553 }
554 }
555 else
556 {
558 "could not get token information buffer size: error code %lu",
559 GetLastError());
561 }
562 }
563
564
565 if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) &asi,
566 (DWORD) sizeof(ACL_SIZE_INFORMATION),
567 AclSizeInformation))
568 {
570 "could not get ACL information: error code %lu",
571 GetLastError());
573 }
574
575
576 if (!GetTokenUser(hToken, &pTokenUser))
577 goto cleanup;
578
579
580 dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
581 GetLengthSid(pTokenUser->User.Sid) - sizeof(DWORD);
582
583
584 pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
585 if (pacl == NULL)
586 {
588 _("out of memory"));
590 }
591
592 if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
593 {
595 "could not initialize ACL: error code %lu", GetLastError());
597 }
598
599
600 for (i = 0; i < (int) asi.AceCount; i++)
601 {
602 if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) &pace))
603 {
605 "could not get ACE: error code %lu", GetLastError());
607 }
608
609 if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize))
610 {
612 "could not add ACE: error code %lu", GetLastError());
614 }
615 }
616
617
618 if (!AddAccessAllowedAceEx(pacl, ACL_REVISION, OBJECT_INHERIT_ACE, GENERIC_ALL, pTokenUser->User.Sid))
619 {
621 "could not add access allowed ACE: error code %lu",
622 GetLastError());
624 }
625
626
627 tddNew.DefaultDacl = pacl;
628
629 if (!SetTokenInformation(hToken, tic, (LPVOID) &tddNew, dwNewAclSize))
630 {
632 "could not set token information: error code %lu",
633 GetLastError());
635 }
636
637 ret = TRUE;
638
640 if (pTokenUser)
641 LocalFree((HLOCAL) pTokenUser);
642
643 if (pacl)
644 LocalFree((HLOCAL) pacl);
645
646 if (ptdd)
647 LocalFree((HLOCAL) ptdd);
648
649 return ret;
650}
651
652
653
654
655
656
657
658
659
660static BOOL
661GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser)
662{
663 DWORD dwLength;
664
665 *ppTokenUser = NULL;
666
667 if (!GetTokenInformation(hToken,
668 TokenUser,
669 NULL,
670 0,
671 &dwLength))
672 {
673 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
674 {
675 *ppTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwLength);
676
677 if (*ppTokenUser == NULL)
678 {
680 _("out of memory"));
681 return FALSE;
682 }
683 }
684 else
685 {
687 "could not get token information buffer size: error code %lu",
688 GetLastError());
689 return FALSE;
690 }
691 }
692
693 if (!GetTokenInformation(hToken,
694 TokenUser,
695 *ppTokenUser,
696 dwLength,
697 &dwLength))
698 {
699 LocalFree(*ppTokenUser);
700 *ppTokenUser = NULL;
701
703 "could not get token information: error code %lu",
704 GetLastError());
705 return FALSE;
706 }
707
708
709 return TRUE;
710}
711
712#endif
static void cleanup(void)
#define PG_TEXTDOMAIN(domain)
int find_my_exec(const char *argv0, char *retpath)
#define log_error(errcodefn,...)
int validate_exec(const char *path)
char * pipe_read_line(char *cmd)
int pclose_check(FILE *stream)
void set_pglocale_pgservice(const char *argv0, const char *app)
static char * pg_realpath(const char *fname)
int find_other_exec(const char *argv0, const char *target, const char *versionstr, char *retpath)
static int normalize_exec_path(char *path)
int errcode_for_file_access(void)
int errcode(int sqlerrcode)
char my_exec_path[MAXPGPATH]
void pfree(void *pointer)
char * pg_get_line(FILE *stream, PromptInterruptContext *prompt_ctx)
void get_locale_path(const char *my_exec_path, char *ret_path)
void join_path_components(char *ret_path, const char *head, const char *tail)
char * last_dir_separator(const char *filename)
int pg_strcasecmp(const char *s1, const char *s2)
char * first_path_var_separator(const char *pathlist)
void canonicalize_path(char *path)
void get_etc_path(const char *my_exec_path, char *ret_path)
char * first_dir_separator(const char *filename)
size_t strlcpy(char *dst, const char *src, size_t siz)
char * wait_result_to_str(int exitstatus)
BOOL AddUserToTokenDacl(HANDLE hToken)