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

113 if (stat(path, &buf) < 0)

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)