00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef FRONTEND
00018 #include "postgres.h"
00019 #else
00020 #include "postgres_fe.h"
00021 #endif
00022
00023 #include <signal.h>
00024 #include <sys/stat.h>
00025 #include <sys/wait.h>
00026 #include <unistd.h>
00027
00028 #ifndef FRONTEND
00029
00030
00031 #define log_error(str, param) elog(LOG, str, param)
00032 #define log_error4(str, param, arg1) elog(LOG, str, param, arg1)
00033 #else
00034 #define log_error(str, param) (fprintf(stderr, str, param), fputc('\n', stderr))
00035 #define log_error4(str, param, arg1) (fprintf(stderr, str, param, arg1), fputc('\n', stderr))
00036 #endif
00037
00038 #ifdef WIN32_ONLY_COMPILER
00039 #define getcwd(cwd,len) GetCurrentDirectory(len, cwd)
00040 #endif
00041
00042 static int validate_exec(const char *path);
00043 static int resolve_symlinks(char *path);
00044 static char *pipe_read_line(char *cmd, char *line, int maxsize);
00045
00046 #ifdef WIN32
00047 static BOOL GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser);
00048 #endif
00049
00050
00051
00052
00053
00054
00055
00056
00057 static int
00058 validate_exec(const char *path)
00059 {
00060 struct stat buf;
00061 int is_r;
00062 int is_x;
00063
00064 #ifdef WIN32
00065 char path_exe[MAXPGPATH + sizeof(".exe") - 1];
00066
00067
00068 if (strlen(path) >= strlen(".exe") &&
00069 pg_strcasecmp(path + strlen(path) - strlen(".exe"), ".exe") != 0)
00070 {
00071 strcpy(path_exe, path);
00072 strcat(path_exe, ".exe");
00073 path = path_exe;
00074 }
00075 #endif
00076
00077
00078
00079
00080
00081
00082
00083 if (stat(path, &buf) < 0)
00084 return -1;
00085
00086 if (!S_ISREG(buf.st_mode))
00087 return -1;
00088
00089
00090
00091
00092
00093 #ifndef WIN32
00094 is_r = (access(path, R_OK) == 0);
00095 is_x = (access(path, X_OK) == 0);
00096 #else
00097 is_r = buf.st_mode & S_IRUSR;
00098 is_x = buf.st_mode & S_IXUSR;
00099 #endif
00100 return is_x ? (is_r ? 0 : -2) : -1;
00101 }
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 int
00119 find_my_exec(const char *argv0, char *retpath)
00120 {
00121 char cwd[MAXPGPATH],
00122 test_path[MAXPGPATH];
00123 char *path;
00124
00125 if (!getcwd(cwd, MAXPGPATH))
00126 {
00127 log_error(_("could not identify current directory: %s"),
00128 strerror(errno));
00129 return -1;
00130 }
00131
00132
00133
00134
00135 if (first_dir_separator(argv0) != NULL)
00136 {
00137 if (is_absolute_path(argv0))
00138 StrNCpy(retpath, argv0, MAXPGPATH);
00139 else
00140 join_path_components(retpath, cwd, argv0);
00141 canonicalize_path(retpath);
00142
00143 if (validate_exec(retpath) == 0)
00144 return resolve_symlinks(retpath);
00145
00146 log_error(_("invalid binary \"%s\""), retpath);
00147 return -1;
00148 }
00149
00150 #ifdef WIN32
00151
00152 join_path_components(retpath, cwd, argv0);
00153 if (validate_exec(retpath) == 0)
00154 return resolve_symlinks(retpath);
00155 #endif
00156
00157
00158
00159
00160
00161 if ((path = getenv("PATH")) && *path)
00162 {
00163 char *startp = NULL,
00164 *endp = NULL;
00165
00166 do
00167 {
00168 if (!startp)
00169 startp = path;
00170 else
00171 startp = endp + 1;
00172
00173 endp = first_path_var_separator(startp);
00174 if (!endp)
00175 endp = startp + strlen(startp);
00176
00177 StrNCpy(test_path, startp, Min(endp - startp + 1, MAXPGPATH));
00178
00179 if (is_absolute_path(test_path))
00180 join_path_components(retpath, test_path, argv0);
00181 else
00182 {
00183 join_path_components(retpath, cwd, test_path);
00184 join_path_components(retpath, retpath, argv0);
00185 }
00186 canonicalize_path(retpath);
00187
00188 switch (validate_exec(retpath))
00189 {
00190 case 0:
00191 return resolve_symlinks(retpath);
00192 case -1:
00193 break;
00194 case -2:
00195 log_error(_("could not read binary \"%s\""),
00196 retpath);
00197 break;
00198 }
00199 } while (*endp);
00200 }
00201
00202 log_error(_("could not find a \"%s\" to execute"), argv0);
00203 return -1;
00204 }
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 static int
00219 resolve_symlinks(char *path)
00220 {
00221 #ifdef HAVE_READLINK
00222 struct stat buf;
00223 char orig_wd[MAXPGPATH],
00224 link_buf[MAXPGPATH];
00225 char *fname;
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239 if (!getcwd(orig_wd, MAXPGPATH))
00240 {
00241 log_error(_("could not identify current directory: %s"),
00242 strerror(errno));
00243 return -1;
00244 }
00245
00246 for (;;)
00247 {
00248 char *lsep;
00249 int rllen;
00250
00251 lsep = last_dir_separator(path);
00252 if (lsep)
00253 {
00254 *lsep = '\0';
00255 if (chdir(path) == -1)
00256 {
00257 log_error4(_("could not change directory to \"%s\": %s"), path, strerror(errno));
00258 return -1;
00259 }
00260 fname = lsep + 1;
00261 }
00262 else
00263 fname = path;
00264
00265 if (lstat(fname, &buf) < 0 ||
00266 !S_ISLNK(buf.st_mode))
00267 break;
00268
00269 rllen = readlink(fname, link_buf, sizeof(link_buf));
00270 if (rllen < 0 || rllen >= sizeof(link_buf))
00271 {
00272 log_error(_("could not read symbolic link \"%s\""), fname);
00273 return -1;
00274 }
00275 link_buf[rllen] = '\0';
00276 strcpy(path, link_buf);
00277 }
00278
00279
00280 strcpy(link_buf, fname);
00281
00282 if (!getcwd(path, MAXPGPATH))
00283 {
00284 log_error(_("could not identify current directory: %s"),
00285 strerror(errno));
00286 return -1;
00287 }
00288 join_path_components(path, path, link_buf);
00289 canonicalize_path(path);
00290
00291 if (chdir(orig_wd) == -1)
00292 {
00293 log_error4(_("could not change directory to \"%s\": %s"), orig_wd, strerror(errno));
00294 return -1;
00295 }
00296 #endif
00297
00298 return 0;
00299 }
00300
00301
00302
00303
00304
00305
00306 int
00307 find_other_exec(const char *argv0, const char *target,
00308 const char *versionstr, char *retpath)
00309 {
00310 char cmd[MAXPGPATH];
00311 char line[100];
00312
00313 if (find_my_exec(argv0, retpath) < 0)
00314 return -1;
00315
00316
00317 *last_dir_separator(retpath) = '\0';
00318 canonicalize_path(retpath);
00319
00320
00321 snprintf(retpath + strlen(retpath), MAXPGPATH - strlen(retpath),
00322 "/%s%s", target, EXE);
00323
00324 if (validate_exec(retpath) != 0)
00325 return -1;
00326
00327 snprintf(cmd, sizeof(cmd), "\"%s\" -V", retpath);
00328
00329 if (!pipe_read_line(cmd, line, sizeof(line)))
00330 return -1;
00331
00332 if (strcmp(line, versionstr) != 0)
00333 return -2;
00334
00335 return 0;
00336 }
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347 static char *
00348 pipe_read_line(char *cmd, char *line, int maxsize)
00349 {
00350 #ifndef WIN32
00351 FILE *pgver;
00352
00353
00354 fflush(stdout);
00355 fflush(stderr);
00356
00357 errno = 0;
00358 if ((pgver = popen(cmd, "r")) == NULL)
00359 {
00360 perror("popen failure");
00361 return NULL;
00362 }
00363
00364 errno = 0;
00365 if (fgets(line, maxsize, pgver) == NULL)
00366 {
00367 if (feof(pgver))
00368 fprintf(stderr, "no data was returned by command \"%s\"\n", cmd);
00369 else
00370 perror("fgets failure");
00371 pclose(pgver);
00372 return NULL;
00373 }
00374
00375 if (pclose_check(pgver))
00376 return NULL;
00377
00378 return line;
00379 #else
00380
00381 SECURITY_ATTRIBUTES sattr;
00382 HANDLE childstdoutrd,
00383 childstdoutwr,
00384 childstdoutrddup;
00385 PROCESS_INFORMATION pi;
00386 STARTUPINFO si;
00387 char *retval = NULL;
00388
00389 sattr.nLength = sizeof(SECURITY_ATTRIBUTES);
00390 sattr.bInheritHandle = TRUE;
00391 sattr.lpSecurityDescriptor = NULL;
00392
00393 if (!CreatePipe(&childstdoutrd, &childstdoutwr, &sattr, 0))
00394 return NULL;
00395
00396 if (!DuplicateHandle(GetCurrentProcess(),
00397 childstdoutrd,
00398 GetCurrentProcess(),
00399 &childstdoutrddup,
00400 0,
00401 FALSE,
00402 DUPLICATE_SAME_ACCESS))
00403 {
00404 CloseHandle(childstdoutrd);
00405 CloseHandle(childstdoutwr);
00406 return NULL;
00407 }
00408
00409 CloseHandle(childstdoutrd);
00410
00411 ZeroMemory(&pi, sizeof(pi));
00412 ZeroMemory(&si, sizeof(si));
00413 si.cb = sizeof(si);
00414 si.dwFlags = STARTF_USESTDHANDLES;
00415 si.hStdError = childstdoutwr;
00416 si.hStdOutput = childstdoutwr;
00417 si.hStdInput = INVALID_HANDLE_VALUE;
00418
00419 if (CreateProcess(NULL,
00420 cmd,
00421 NULL,
00422 NULL,
00423 TRUE,
00424 0,
00425 NULL,
00426 NULL,
00427 &si,
00428 &pi))
00429 {
00430
00431 char *lineptr;
00432
00433 ZeroMemory(line, maxsize);
00434
00435
00436
00437 for (lineptr = line; lineptr < line + maxsize - 1;)
00438 {
00439 DWORD bytesread = 0;
00440
00441
00442 if (WaitForSingleObject(childstdoutrddup, 10000) != WAIT_OBJECT_0)
00443 break;
00444
00445 if (!ReadFile(childstdoutrddup, lineptr, maxsize - (lineptr - line),
00446 &bytesread, NULL))
00447 break;
00448
00449 lineptr += strlen(lineptr);
00450
00451 if (!bytesread)
00452 break;
00453
00454 if (strchr(line, '\n'))
00455 break;
00456 }
00457
00458 if (lineptr != line)
00459 {
00460
00461 int len;
00462
00463
00464 lineptr = strchr(line, '\n');
00465 if (lineptr)
00466 *(lineptr + 1) = '\0';
00467
00468 len = strlen(line);
00469
00470
00471
00472
00473
00474
00475
00476
00477 if (len >= 2 && line[len - 2] == '\r' && line[len - 1] == '\n')
00478 {
00479 line[len - 2] = '\n';
00480 line[len - 1] = '\0';
00481 len--;
00482 }
00483
00484
00485
00486
00487
00488 if (len == 0 || line[len - 1] != '\n')
00489 strcat(line, "\n");
00490
00491 retval = line;
00492 }
00493
00494 CloseHandle(pi.hProcess);
00495 CloseHandle(pi.hThread);
00496 }
00497
00498 CloseHandle(childstdoutwr);
00499 CloseHandle(childstdoutrddup);
00500
00501 return retval;
00502 #endif
00503 }
00504
00505
00506
00507
00508
00509 int
00510 pclose_check(FILE *stream)
00511 {
00512 int exitstatus;
00513 char *reason;
00514
00515 exitstatus = pclose(stream);
00516
00517 if (exitstatus == 0)
00518 return 0;
00519
00520 if (exitstatus == -1)
00521 {
00522
00523 log_error(_("pclose failed: %s"), strerror(errno));
00524 }
00525 else
00526 {
00527 reason = wait_result_to_str(exitstatus);
00528 log_error("%s", reason);
00529 #ifdef FRONTEND
00530 free(reason);
00531 #else
00532 pfree(reason);
00533 #endif
00534 }
00535 return exitstatus;
00536 }
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549 void
00550 set_pglocale_pgservice(const char *argv0, const char *app)
00551 {
00552 char path[MAXPGPATH];
00553 char my_exec_path[MAXPGPATH];
00554 char env_path[MAXPGPATH + sizeof("PGSYSCONFDIR=")];
00555
00556
00557
00558 if (strcmp(app, PG_TEXTDOMAIN("postgres")) != 0)
00559 setlocale(LC_ALL, "");
00560
00561 if (find_my_exec(argv0, my_exec_path) < 0)
00562 return;
00563
00564 #ifdef ENABLE_NLS
00565 get_locale_path(my_exec_path, path);
00566 bindtextdomain(app, path);
00567 textdomain(app);
00568
00569 if (getenv("PGLOCALEDIR") == NULL)
00570 {
00571
00572 snprintf(env_path, sizeof(env_path), "PGLOCALEDIR=%s", path);
00573 canonicalize_path(env_path + 12);
00574 putenv(strdup(env_path));
00575 }
00576 #endif
00577
00578 if (getenv("PGSYSCONFDIR") == NULL)
00579 {
00580 get_etc_path(my_exec_path, path);
00581
00582
00583 snprintf(env_path, sizeof(env_path), "PGSYSCONFDIR=%s", path);
00584 canonicalize_path(env_path + 13);
00585 putenv(strdup(env_path));
00586 }
00587 }
00588
00589 #ifdef WIN32
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 BOOL
00614 AddUserToTokenDacl(HANDLE hToken)
00615 {
00616 int i;
00617 ACL_SIZE_INFORMATION asi;
00618 ACCESS_ALLOWED_ACE *pace;
00619 DWORD dwNewAclSize;
00620 DWORD dwSize = 0;
00621 DWORD dwTokenInfoLength = 0;
00622 PACL pacl = NULL;
00623 PTOKEN_USER pTokenUser = NULL;
00624 TOKEN_DEFAULT_DACL tddNew;
00625 TOKEN_DEFAULT_DACL *ptdd = NULL;
00626 TOKEN_INFORMATION_CLASS tic = TokenDefaultDacl;
00627 BOOL ret = FALSE;
00628
00629
00630 if (!GetTokenInformation(hToken, tic, (LPVOID) NULL, dwTokenInfoLength, &dwSize))
00631 {
00632 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
00633 {
00634 ptdd = (TOKEN_DEFAULT_DACL *) LocalAlloc(LPTR, dwSize);
00635 if (ptdd == NULL)
00636 {
00637 log_error("could not allocate %lu bytes of memory", dwSize);
00638 goto cleanup;
00639 }
00640
00641 if (!GetTokenInformation(hToken, tic, (LPVOID) ptdd, dwSize, &dwSize))
00642 {
00643 log_error("could not get token information: error code %lu", GetLastError());
00644 goto cleanup;
00645 }
00646 }
00647 else
00648 {
00649 log_error("could not get token information buffer size: error code %lu", GetLastError());
00650 goto cleanup;
00651 }
00652 }
00653
00654
00655 if (!GetAclInformation(ptdd->DefaultDacl, (LPVOID) &asi,
00656 (DWORD) sizeof(ACL_SIZE_INFORMATION),
00657 AclSizeInformation))
00658 {
00659 log_error("could not get ACL information: error code %lu", GetLastError());
00660 goto cleanup;
00661 }
00662
00663
00664
00665
00666
00667 if (!GetTokenUser(hToken, &pTokenUser))
00668 {
00669 log_error("could not get user token: error code %lu", GetLastError());
00670 goto cleanup;
00671 }
00672
00673
00674 dwNewAclSize = asi.AclBytesInUse + sizeof(ACCESS_ALLOWED_ACE) +
00675 GetLengthSid(pTokenUser->User.Sid) -sizeof(DWORD);
00676
00677
00678 pacl = (PACL) LocalAlloc(LPTR, dwNewAclSize);
00679 if (pacl == NULL)
00680 {
00681 log_error("could not allocate %lu bytes of memory", dwNewAclSize);
00682 goto cleanup;
00683 }
00684
00685 if (!InitializeAcl(pacl, dwNewAclSize, ACL_REVISION))
00686 {
00687 log_error("could not initialize ACL: error code %lu", GetLastError());
00688 goto cleanup;
00689 }
00690
00691
00692 for (i = 0; i < (int) asi.AceCount; i++)
00693 {
00694 if (!GetAce(ptdd->DefaultDacl, i, (LPVOID *) &pace))
00695 {
00696 log_error("could not get ACE: error code %lu", GetLastError());
00697 goto cleanup;
00698 }
00699
00700 if (!AddAce(pacl, ACL_REVISION, MAXDWORD, pace, ((PACE_HEADER) pace)->AceSize))
00701 {
00702 log_error("could not add ACE: error code %lu", GetLastError());
00703 goto cleanup;
00704 }
00705 }
00706
00707
00708 if (!AddAccessAllowedAceEx(pacl, ACL_REVISION, OBJECT_INHERIT_ACE, GENERIC_ALL, pTokenUser->User.Sid))
00709 {
00710 log_error("could not add access allowed ACE: error code %lu", GetLastError());
00711 goto cleanup;
00712 }
00713
00714
00715 tddNew.DefaultDacl = pacl;
00716
00717 if (!SetTokenInformation(hToken, tic, (LPVOID) &tddNew, dwNewAclSize))
00718 {
00719 log_error("could not set token information: error code %lu", GetLastError());
00720 goto cleanup;
00721 }
00722
00723 ret = TRUE;
00724
00725 cleanup:
00726 if (pTokenUser)
00727 LocalFree((HLOCAL) pTokenUser);
00728
00729 if (pacl)
00730 LocalFree((HLOCAL) pacl);
00731
00732 if (ptdd)
00733 LocalFree((HLOCAL) ptdd);
00734
00735 return ret;
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746 static BOOL
00747 GetTokenUser(HANDLE hToken, PTOKEN_USER *ppTokenUser)
00748 {
00749 DWORD dwLength;
00750
00751 *ppTokenUser = NULL;
00752
00753 if (!GetTokenInformation(hToken,
00754 TokenUser,
00755 NULL,
00756 0,
00757 &dwLength))
00758 {
00759 if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
00760 {
00761 *ppTokenUser = (PTOKEN_USER) LocalAlloc(LPTR, dwLength);
00762
00763 if (*ppTokenUser == NULL)
00764 {
00765 log_error("could not allocate %lu bytes of memory", dwLength);
00766 return FALSE;
00767 }
00768 }
00769 else
00770 {
00771 log_error("could not get token information buffer size: error code %lu", GetLastError());
00772 return FALSE;
00773 }
00774 }
00775
00776 if (!GetTokenInformation(hToken,
00777 TokenUser,
00778 *ppTokenUser,
00779 dwLength,
00780 &dwLength))
00781 {
00782 LocalFree(*ppTokenUser);
00783 *ppTokenUser = NULL;
00784
00785 log_error("could not get token information: error code %lu", GetLastError());
00786 return FALSE;
00787 }
00788
00789
00790 return TRUE;
00791 }
00792
00793 #endif