1 /* 2 * Copyright (c) 1998-2000 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * By using this file, you agree to the terms and conditions set 9 * forth in the LICENSE file which can be found at the top level of 10 * the sendmail distribution. 11 * 12 */ 13 14 #ifndef lint 15 static char id[] = "@(#)$Id: safefile.c,v 8.81.4.7 2000/09/01 21:09:23 ca Exp $"; 16 #endif /* ! lint */ 17 18 #include <sendmail.h> 19 20 21 /* 22 ** SAFEFILE -- return 0 if a file exists and is safe for a user. 23 ** 24 ** Parameters: 25 ** fn -- filename to check. 26 ** uid -- user id to compare against. 27 ** gid -- group id to compare against. 28 ** user -- user name to compare against (used for group 29 ** sets). 30 ** flags -- modifiers: 31 ** SFF_MUSTOWN -- "uid" must own this file. 32 ** SFF_NOSLINK -- file cannot be a symbolic link. 33 ** mode -- mode bits that must match. 34 ** st -- if set, points to a stat structure that will 35 ** get the stat info for the file. 36 ** 37 ** Returns: 38 ** 0 if fn exists, is owned by uid, and matches mode. 39 ** An errno otherwise. The actual errno is cleared. 40 ** 41 ** Side Effects: 42 ** none. 43 */ 44 45 int 46 safefile(fn, uid, gid, user, flags, mode, st) 47 char *fn; 48 UID_T uid; 49 GID_T gid; 50 char *user; 51 long flags; 52 int mode; 53 struct stat *st; 54 { 55 register char *p; 56 register struct group *gr = NULL; 57 int file_errno = 0; 58 bool checkpath; 59 struct stat stbuf; 60 struct stat fstbuf; 61 char fbuf[MAXPATHLEN + 1]; 62 63 if (tTd(44, 4)) 64 dprintf("safefile(%s, uid=%d, gid=%d, flags=%lx, mode=%o):\n", 65 fn, (int) uid, (int) gid, flags, mode); 66 errno = 0; 67 if (st == NULL) 68 st = &fstbuf; 69 if (strlcpy(fbuf, fn, sizeof fbuf) >= sizeof fbuf) 70 { 71 if (tTd(44, 4)) 72 dprintf("\tpathname too long\n"); 73 return ENAMETOOLONG; 74 } 75 fn = fbuf; 76 77 /* ignore SFF_SAFEDIRPATH if we are debugging */ 78 if (RealUid != 0 && RunAsUid == RealUid) 79 flags &= ~SFF_SAFEDIRPATH; 80 81 /* first check to see if the file exists at all */ 82 # if HASLSTAT 83 if ((bitset(SFF_NOSLINK, flags) ? lstat(fn, st) 84 : stat(fn, st)) < 0) 85 # else /* HASLSTAT */ 86 if (stat(fn, st) < 0) 87 # endif /* HASLSTAT */ 88 { 89 file_errno = errno; 90 } 91 else if (bitset(SFF_SETUIDOK, flags) && 92 !bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode) && 93 S_ISREG(st->st_mode)) 94 { 95 /* 96 ** If final file is setuid, run as the owner of that 97 ** file. Gotta be careful not to reveal anything too 98 ** soon here! 99 */ 100 101 # ifdef SUID_ROOT_FILES_OK 102 if (bitset(S_ISUID, st->st_mode)) 103 # else /* SUID_ROOT_FILES_OK */ 104 if (bitset(S_ISUID, st->st_mode) && st->st_uid != 0 && 105 st->st_uid != TrustedUid) 106 # endif /* SUID_ROOT_FILES_OK */ 107 { 108 uid = st->st_uid; 109 user = NULL; 110 } 111 # ifdef SUID_ROOT_FILES_OK 112 if (bitset(S_ISGID, st->st_mode)) 113 # else /* SUID_ROOT_FILES_OK */ 114 if (bitset(S_ISGID, st->st_mode) && st->st_gid != 0) 115 # endif /* SUID_ROOT_FILES_OK */ 116 gid = st->st_gid; 117 } 118 119 checkpath = !bitset(SFF_NOPATHCHECK, flags) || 120 (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags)); 121 if (bitset(SFF_NOWLINK, flags) && !bitset(SFF_SAFEDIRPATH, flags)) 122 { 123 int ret; 124 125 /* check the directory */ 126 p = strrchr(fn, '/'); 127 if (p == NULL) 128 { 129 ret = safedirpath(".", uid, gid, user, 130 flags|SFF_SAFEDIRPATH, 0, 0); 131 } 132 else 133 { 134 *p = '\0'; 135 ret = safedirpath(fn, uid, gid, user, 136 flags|SFF_SAFEDIRPATH, 0, 0); 137 *p = '/'; 138 } 139 if (ret == 0) 140 { 141 /* directory is safe */ 142 checkpath = FALSE; 143 } 144 else 145 { 146 # if HASLSTAT 147 /* Need lstat() information if called stat() before */ 148 if (!bitset(SFF_NOSLINK, flags) && lstat(fn, st) < 0) 149 { 150 ret = errno; 151 if (tTd(44, 4)) 152 dprintf("\t%s\n", errstring(ret)); 153 return ret; 154 } 155 # endif /* HASLSTAT */ 156 /* directory is writable: disallow links */ 157 flags |= SFF_NOLINK; 158 } 159 } 160 161 if (checkpath) 162 { 163 int ret; 164 165 p = strrchr(fn, '/'); 166 if (p == NULL) 167 { 168 ret = safedirpath(".", uid, gid, user, flags, 0, 0); 169 } 170 else 171 { 172 *p = '\0'; 173 ret = safedirpath(fn, uid, gid, user, flags, 0, 0); 174 *p = '/'; 175 } 176 if (ret != 0) 177 return ret; 178 } 179 180 /* 181 ** If the target file doesn't exist, check the directory to 182 ** ensure that it is writable by this user. 183 */ 184 185 if (file_errno != 0) 186 { 187 int ret = file_errno; 188 char *dir = fn; 189 190 if (tTd(44, 4)) 191 dprintf("\t%s\n", errstring(ret)); 192 193 errno = 0; 194 if (!bitset(SFF_CREAT, flags) || file_errno != ENOENT) 195 return ret; 196 197 /* check to see if legal to create the file */ 198 p = strrchr(dir, '/'); 199 if (p == NULL) 200 dir = "."; 201 else if (p == dir) 202 dir = "/"; 203 else 204 *p = '\0'; 205 if (stat(dir, &stbuf) >= 0) 206 { 207 int md = S_IWRITE|S_IEXEC; 208 209 if (stbuf.st_uid == uid) 210 /* EMPTY */ 211 ; 212 else if (uid == 0 && stbuf.st_uid == TrustedUid) 213 /* EMPTY */ 214 ; 215 else 216 { 217 md >>= 3; 218 if (stbuf.st_gid == gid) 219 /* EMPTY */ 220 ; 221 # ifndef NO_GROUP_SET 222 else if (user != NULL && !DontInitGroups && 223 ((gr != NULL && 224 gr->gr_gid == stbuf.st_gid) || 225 (gr = getgrgid(stbuf.st_gid)) != NULL)) 226 { 227 register char **gp; 228 229 for (gp = gr->gr_mem; *gp != NULL; gp++) 230 if (strcmp(*gp, user) == 0) 231 break; 232 if (*gp == NULL) 233 md >>= 3; 234 } 235 # endif /* ! NO_GROUP_SET */ 236 else 237 md >>= 3; 238 } 239 if ((stbuf.st_mode & md) != md) 240 errno = EACCES; 241 } 242 ret = errno; 243 if (tTd(44, 4)) 244 dprintf("\t[final dir %s uid %d mode %lo] %s\n", 245 dir, (int) stbuf.st_uid, (u_long) stbuf.st_mode, 246 errstring(ret)); 247 if (p != NULL) 248 *p = '/'; 249 st->st_mode = ST_MODE_NOFILE; 250 return ret; 251 } 252 253 # ifdef S_ISLNK 254 if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) 255 { 256 if (tTd(44, 4)) 257 dprintf("\t[slink mode %lo]\tE_SM_NOSLINK\n", 258 (u_long) st->st_mode); 259 return E_SM_NOSLINK; 260 } 261 # endif /* S_ISLNK */ 262 if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) 263 { 264 if (tTd(44, 4)) 265 dprintf("\t[non-reg mode %lo]\tE_SM_REGONLY\n", 266 (u_long) st->st_mode); 267 return E_SM_REGONLY; 268 } 269 if (bitset(SFF_NOGWFILES, flags) && 270 bitset(S_IWGRP, st->st_mode)) 271 { 272 if (tTd(44, 4)) 273 dprintf("\t[write bits %lo]\tE_SM_GWFILE\n", 274 (u_long) st->st_mode); 275 return E_SM_GWFILE; 276 } 277 if (bitset(SFF_NOWWFILES, flags) && 278 bitset(S_IWOTH, st->st_mode)) 279 { 280 if (tTd(44, 4)) 281 dprintf("\t[write bits %lo]\tE_SM_WWFILE\n", 282 (u_long) st->st_mode); 283 return E_SM_WWFILE; 284 } 285 if (bitset(SFF_NOGRFILES, flags) && bitset(S_IRGRP, st->st_mode)) 286 { 287 if (tTd(44, 4)) 288 dprintf("\t[read bits %lo]\tE_SM_GRFILE\n", 289 (u_long) st->st_mode); 290 return E_SM_GRFILE; 291 } 292 if (bitset(SFF_NOWRFILES, flags) && bitset(S_IROTH, st->st_mode)) 293 { 294 if (tTd(44, 4)) 295 dprintf("\t[read bits %lo]\tE_SM_WRFILE\n", 296 (u_long) st->st_mode); 297 return E_SM_WRFILE; 298 } 299 if (!bitset(SFF_EXECOK, flags) && 300 bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && 301 bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode)) 302 { 303 if (tTd(44, 4)) 304 dprintf("\t[exec bits %lo]\tE_SM_ISEXEC]\n", 305 (u_long) st->st_mode); 306 return E_SM_ISEXEC; 307 } 308 if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1) 309 { 310 if (tTd(44, 4)) 311 dprintf("\t[link count %d]\tE_SM_NOHLINK\n", 312 (int) st->st_nlink); 313 return E_SM_NOHLINK; 314 } 315 316 if (uid == 0 && bitset(SFF_OPENASROOT, flags)) 317 /* EMPTY */ 318 ; 319 else if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 320 mode >>= 6; 321 else if (st->st_uid == uid) 322 /* EMPTY */ 323 ; 324 else if (uid == 0 && st->st_uid == TrustedUid) 325 /* EMPTY */ 326 ; 327 else 328 { 329 mode >>= 3; 330 if (st->st_gid == gid) 331 /* EMPTY */ 332 ; 333 # ifndef NO_GROUP_SET 334 else if (user != NULL && !DontInitGroups && 335 ((gr != NULL && gr->gr_gid == st->st_gid) || 336 (gr = getgrgid(st->st_gid)) != NULL)) 337 { 338 register char **gp; 339 340 for (gp = gr->gr_mem; *gp != NULL; gp++) 341 if (strcmp(*gp, user) == 0) 342 break; 343 if (*gp == NULL) 344 mode >>= 3; 345 } 346 # endif /* ! NO_GROUP_SET */ 347 else 348 mode >>= 3; 349 } 350 if (tTd(44, 4)) 351 dprintf("\t[uid %d, nlink %d, stat %lo, mode %lo] ", 352 (int) st->st_uid, (int) st->st_nlink, 353 (u_long) st->st_mode, (u_long) mode); 354 if ((st->st_uid == uid || st->st_uid == 0 || 355 st->st_uid == TrustedUid || 356 !bitset(SFF_MUSTOWN, flags)) && 357 (st->st_mode & mode) == mode) 358 { 359 if (tTd(44, 4)) 360 dprintf("\tOK\n"); 361 return 0; 362 } 363 if (tTd(44, 4)) 364 dprintf("\tEACCES\n"); 365 return EACCES; 366 } 367 /* 368 ** SAFEDIRPATH -- check to make sure a path to a directory is safe 369 ** 370 ** Safe means not writable and owned by the right folks. 371 ** 372 ** Parameters: 373 ** fn -- filename to check. 374 ** uid -- user id to compare against. 375 ** gid -- group id to compare against. 376 ** user -- user name to compare against (used for group 377 ** sets). 378 ** flags -- modifiers: 379 ** SFF_ROOTOK -- ok to use root permissions to open. 380 ** SFF_SAFEDIRPATH -- writable directories are considered 381 ** to be fatal errors. 382 ** level -- symlink recursive level. 383 ** offset -- offset into fn to start checking from. 384 ** 385 ** Returns: 386 ** 0 -- if the directory path is "safe". 387 ** else -- an error number associated with the path. 388 */ 389 390 int 391 safedirpath(fn, uid, gid, user, flags, level, offset) 392 char *fn; 393 UID_T uid; 394 GID_T gid; 395 char *user; 396 long flags; 397 int level; 398 int offset; 399 { 400 int ret = 0; 401 int mode = S_IWOTH; 402 char save = '\0'; 403 char *saveptr = NULL; 404 char *p, *enddir; 405 register struct group *gr = NULL; 406 char s[MAXLINKPATHLEN + 1]; 407 struct stat stbuf; 408 409 /* make sure we aren't in a symlink loop */ 410 if (level > MAXSYMLINKS) 411 return ELOOP; 412 413 /* special case root directory */ 414 if (*fn == '\0') 415 fn = "/"; 416 417 if (tTd(44, 4)) 418 dprintf("safedirpath(%s, uid=%ld, gid=%ld, flags=%lx, level=%d, offset=%d):\n", 419 fn, (long) uid, (long) gid, flags, level, offset); 420 421 if (!bitnset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail)) 422 mode |= S_IWGRP; 423 424 /* Make a modifiable copy of the filename */ 425 if (strlcpy(s, fn, sizeof s) >= sizeof s) 426 return EINVAL; 427 428 p = s + offset; 429 while (p != NULL) 430 { 431 /* put back character */ 432 if (saveptr != NULL) 433 { 434 *saveptr = save; 435 saveptr = NULL; 436 p++; 437 } 438 439 if (*p == '\0') 440 break; 441 442 p = strchr(p, '/'); 443 444 /* Special case for root directory */ 445 if (p == s) 446 { 447 save = *(p + 1); 448 saveptr = p + 1; 449 *(p + 1) = '\0'; 450 } 451 else if (p != NULL) 452 { 453 save = *p; 454 saveptr = p; 455 *p = '\0'; 456 } 457 458 /* Heuristic: . and .. have already been checked */ 459 enddir = strrchr(s, '/'); 460 if (enddir != NULL && 461 (strcmp(enddir, "/..") == 0 || 462 strcmp(enddir, "/.") == 0)) 463 continue; 464 465 if (tTd(44, 20)) 466 dprintf("\t[dir %s]\n", s); 467 468 # if HASLSTAT 469 ret = lstat(s, &stbuf); 470 # else /* HASLSTAT */ 471 ret = stat(s, &stbuf); 472 # endif /* HASLSTAT */ 473 if (ret < 0) 474 { 475 ret = errno; 476 break; 477 } 478 479 # ifdef S_ISLNK 480 /* Follow symlinks */ 481 if (S_ISLNK(stbuf.st_mode)) 482 { 483 char *target; 484 char buf[MAXPATHLEN + 1]; 485 486 memset(buf, '\0', sizeof buf); 487 if (readlink(s, buf, sizeof buf) < 0) 488 { 489 ret = errno; 490 break; 491 } 492 493 offset = 0; 494 if (*buf == '/') 495 { 496 target = buf; 497 498 /* If path is the same, avoid rechecks */ 499 while (s[offset] == buf[offset] && 500 s[offset] != '\0') 501 offset++; 502 503 if (s[offset] == '\0' && buf[offset] == '\0') 504 { 505 /* strings match, symlink loop */ 506 return ELOOP; 507 } 508 509 /* back off from the mismatch */ 510 if (offset > 0) 511 offset--; 512 513 /* Make sure we are at a directory break */ 514 if (offset > 0 && 515 s[offset] != '/' && 516 s[offset] != '\0') 517 { 518 while (buf[offset] != '/' && 519 offset > 0) 520 offset--; 521 } 522 if (offset > 0 && 523 s[offset] == '/' && 524 buf[offset] == '/') 525 { 526 /* Include the trailing slash */ 527 offset++; 528 } 529 } 530 else 531 { 532 char *sptr; 533 char fullbuf[MAXLINKPATHLEN + 1]; 534 535 sptr = strrchr(s, '/'); 536 if (sptr != NULL) 537 { 538 *sptr = '\0'; 539 offset = sptr + 1 - s; 540 if ((strlen(s) + 1 + 541 strlen(buf) + 1) > sizeof fullbuf) 542 { 543 ret = EINVAL; 544 break; 545 } 546 snprintf(fullbuf, sizeof fullbuf, 547 "%s/%s", s, buf); 548 *sptr = '/'; 549 } 550 else 551 { 552 if (strlen(buf) + 1 > sizeof fullbuf) 553 { 554 ret = EINVAL; 555 break; 556 } 557 (void) strlcpy(fullbuf, buf, 558 sizeof fullbuf); 559 } 560 target = fullbuf; 561 } 562 ret = safedirpath(target, uid, gid, user, flags, 563 level + 1, offset); 564 if (ret != 0) 565 break; 566 567 /* Don't check permissions on the link file itself */ 568 continue; 569 } 570 #endif /* S_ISLNK */ 571 572 if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) && 573 #ifdef S_ISVTX 574 !(bitnset(DBS_TRUSTSTICKYBIT, DontBlameSendmail) && 575 bitset(S_ISVTX, stbuf.st_mode)) && 576 #endif /* S_ISVTX */ 577 bitset(mode, stbuf.st_mode)) 578 { 579 if (tTd(44, 4)) 580 dprintf("\t[dir %s] mode %lo ", 581 s, (u_long) stbuf.st_mode); 582 if (bitset(SFF_SAFEDIRPATH, flags)) 583 { 584 if (bitset(S_IWOTH, stbuf.st_mode)) 585 ret = E_SM_WWDIR; 586 else 587 ret = E_SM_GWDIR; 588 if (tTd(44, 4)) 589 dprintf("FATAL\n"); 590 break; 591 } 592 if (tTd(44, 4)) 593 dprintf("WARNING\n"); 594 if (Verbose > 1) 595 message("051 WARNING: %s writable directory %s", 596 bitset(S_IWOTH, stbuf.st_mode) 597 ? "World" 598 : "Group", 599 s); 600 } 601 if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags)) 602 { 603 if (bitset(S_IXOTH, stbuf.st_mode)) 604 continue; 605 ret = EACCES; 606 break; 607 } 608 609 /* 610 ** Let OS determine access to file if we are not 611 ** running as a privileged user. This allows ACLs 612 ** to work. Also, if opening as root, assume we can 613 ** scan the directory. 614 */ 615 if (geteuid() != 0 || bitset(SFF_OPENASROOT, flags)) 616 continue; 617 618 if (stbuf.st_uid == uid && 619 bitset(S_IXUSR, stbuf.st_mode)) 620 continue; 621 if (stbuf.st_gid == gid && 622 bitset(S_IXGRP, stbuf.st_mode)) 623 continue; 624 # ifndef NO_GROUP_SET 625 if (user != NULL && !DontInitGroups && 626 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 627 (gr = getgrgid(stbuf.st_gid)) != NULL)) 628 { 629 register char **gp; 630 631 for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) 632 if (strcmp(*gp, user) == 0) 633 break; 634 if (gp != NULL && *gp != NULL && 635 bitset(S_IXGRP, stbuf.st_mode)) 636 continue; 637 } 638 # endif /* ! NO_GROUP_SET */ 639 if (!bitset(S_IXOTH, stbuf.st_mode)) 640 { 641 ret = EACCES; 642 break; 643 } 644 } 645 if (tTd(44, 4)) 646 dprintf("\t[dir %s] %s\n", fn, 647 ret == 0 ? "OK" : errstring(ret)); 648 return ret; 649 } 650 /* 651 ** SAFEOPEN -- do a file open with extra checking 652 ** 653 ** Parameters: 654 ** fn -- the file name to open. 655 ** omode -- the open-style mode flags. 656 ** cmode -- the create-style mode flags. 657 ** sff -- safefile flags. 658 ** 659 ** Returns: 660 ** Same as open. 661 */ 662 663 #ifndef O_ACCMODE 664 # define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) 665 #endif /* ! O_ACCMODE */ 666 667 int 668 safeopen(fn, omode, cmode, sff) 669 char *fn; 670 int omode; 671 int cmode; 672 long sff; 673 { 674 int rval; 675 int fd; 676 int smode; 677 struct stat stb; 678 679 if (tTd(44, 10)) 680 printf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n", 681 fn, omode, cmode, sff); 682 683 if (bitset(O_CREAT, omode)) 684 sff |= SFF_CREAT; 685 omode &= ~O_CREAT; 686 smode = 0; 687 switch (omode & O_ACCMODE) 688 { 689 case O_RDONLY: 690 smode = S_IREAD; 691 break; 692 693 case O_WRONLY: 694 smode = S_IWRITE; 695 break; 696 697 case O_RDWR: 698 smode = S_IREAD|S_IWRITE; 699 break; 700 701 default: 702 smode = 0; 703 break; 704 } 705 if (bitset(SFF_OPENASROOT, sff)) 706 rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName, 707 sff, smode, &stb); 708 else 709 rval = safefile(fn, RealUid, RealGid, RealUserName, 710 sff, smode, &stb); 711 if (rval != 0) 712 { 713 errno = rval; 714 return -1; 715 } 716 if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff)) 717 omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL); 718 else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode)) 719 { 720 /* The file exists so an exclusive create would fail */ 721 errno = EEXIST; 722 return -1; 723 } 724 725 fd = dfopen(fn, omode, cmode, sff); 726 if (fd < 0) 727 return fd; 728 if (filechanged(fn, fd, &stb)) 729 { 730 syserr("554 5.3.0 cannot open: file %s changed after open", fn); 731 (void) close(fd); 732 errno = E_SM_FILECHANGE; 733 return -1; 734 } 735 return fd; 736 } 737 /* 738 ** SAFEFOPEN -- do a file open with extra checking 739 ** 740 ** Parameters: 741 ** fn -- the file name to open. 742 ** omode -- the open-style mode flags. 743 ** cmode -- the create-style mode flags. 744 ** sff -- safefile flags. 745 ** 746 ** Returns: 747 ** Same as fopen. 748 */ 749 750 FILE * 751 safefopen(fn, omode, cmode, sff) 752 char *fn; 753 int omode; 754 int cmode; 755 long sff; 756 { 757 int fd; 758 int save_errno; 759 FILE *fp; 760 char *fmode; 761 762 switch (omode & O_ACCMODE) 763 { 764 case O_RDONLY: 765 fmode = "r"; 766 break; 767 768 case O_WRONLY: 769 if (bitset(O_APPEND, omode)) 770 fmode = "a"; 771 else 772 fmode = "w"; 773 break; 774 775 case O_RDWR: 776 if (bitset(O_TRUNC, omode)) 777 fmode = "w+"; 778 else if (bitset(O_APPEND, omode)) 779 fmode = "a+"; 780 else 781 fmode = "r+"; 782 break; 783 784 default: 785 syserr("554 5.3.5 safefopen: unknown omode %o", omode); 786 fmode = "x"; 787 } 788 fd = safeopen(fn, omode, cmode, sff); 789 if (fd < 0) 790 { 791 save_errno = errno; 792 if (tTd(44, 10)) 793 dprintf("safefopen: safeopen failed: %s\n", 794 errstring(errno)); 795 errno = save_errno; 796 return NULL; 797 } 798 fp = fdopen(fd, fmode); 799 if (fp != NULL) 800 return fp; 801 802 save_errno = errno; 803 if (tTd(44, 10)) 804 { 805 dprintf("safefopen: fdopen(%s, %s) failed: omode=%x, sff=%lx, err=%s\n", 806 fn, fmode, omode, sff, errstring(errno)); 807 } 808 (void) close(fd); 809 errno = save_errno; 810 return NULL; 811 } 812 /* 813 ** FILECHANGED -- check to see if file changed after being opened 814 ** 815 ** Parameters: 816 ** fn -- pathname of file to check. 817 ** fd -- file descriptor to check. 818 ** stb -- stat structure from before open. 819 ** 820 ** Returns: 821 ** TRUE -- if a problem was detected. 822 ** FALSE -- if this file is still the same. 823 */ 824 825 bool 826 filechanged(fn, fd, stb) 827 char *fn; 828 int fd; 829 struct stat *stb; 830 { 831 struct stat sta; 832 833 if (stb->st_mode == ST_MODE_NOFILE) 834 { 835 # if HASLSTAT && BOGUS_O_EXCL 836 /* only necessary if exclusive open follows symbolic links */ 837 if (lstat(fn, stb) < 0 || stb->st_nlink != 1) 838 return TRUE; 839 # else /* HASLSTAT && BOGUS_O_EXCL */ 840 return FALSE; 841 # endif /* HASLSTAT && BOGUS_O_EXCL */ 842 } 843 if (fstat(fd, &sta) < 0) 844 return TRUE; 845 846 if (sta.st_nlink != stb->st_nlink || 847 sta.st_dev != stb->st_dev || 848 sta.st_ino != stb->st_ino || 849 # if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 850 sta.st_gen != stb->st_gen || 851 # endif /* HAS_ST_GEN && 0 */ 852 sta.st_uid != stb->st_uid || 853 sta.st_gid != stb->st_gid) 854 { 855 if (tTd(44, 8)) 856 { 857 dprintf("File changed after opening:\n"); 858 dprintf(" nlink = %ld/%ld\n", 859 (long) stb->st_nlink, (long) sta.st_nlink); 860 dprintf(" dev = %ld/%ld\n", 861 (long) stb->st_dev, (long) sta.st_dev); 862 if (sizeof sta.st_ino > sizeof (long)) 863 { 864 dprintf(" ino = %s/", 865 quad_to_string(stb->st_ino)); 866 dprintf("%s\n", 867 quad_to_string(sta.st_ino)); 868 } 869 else 870 dprintf(" ino = %lu/%lu\n", 871 (unsigned long) stb->st_ino, 872 (unsigned long) sta.st_ino); 873 # if HAS_ST_GEN 874 dprintf(" gen = %ld/%ld\n", 875 (long) stb->st_gen, (long) sta.st_gen); 876 # endif /* HAS_ST_GEN */ 877 dprintf(" uid = %ld/%ld\n", 878 (long) stb->st_uid, (long) sta.st_uid); 879 dprintf(" gid = %ld/%ld\n", 880 (long) stb->st_gid, (long) sta.st_gid); 881 } 882 return TRUE; 883 } 884 885 return FALSE; 886 } 887 /* 888 ** DFOPEN -- determined file open 889 ** 890 ** This routine has the semantics of open, except that it will 891 ** keep trying a few times to make this happen. The idea is that 892 ** on very loaded systems, we may run out of resources (inodes, 893 ** whatever), so this tries to get around it. 894 */ 895 896 int 897 dfopen(filename, omode, cmode, sff) 898 char *filename; 899 int omode; 900 int cmode; 901 long sff; 902 { 903 register int tries; 904 int fd = -1; 905 struct stat st; 906 907 for (tries = 0; tries < 10; tries++) 908 { 909 (void) sleep((unsigned) (10 * tries)); 910 errno = 0; 911 fd = open(filename, omode, cmode); 912 if (fd >= 0) 913 break; 914 switch (errno) 915 { 916 case ENFILE: /* system file table full */ 917 case EINTR: /* interrupted syscall */ 918 #ifdef ETXTBSY 919 case ETXTBSY: /* Apollo: net file locked */ 920 #endif /* ETXTBSY */ 921 continue; 922 } 923 break; 924 } 925 if (!bitset(SFF_NOLOCK, sff) && 926 fd >= 0 && 927 fstat(fd, &st) >= 0 && 928 S_ISREG(st.st_mode)) 929 { 930 int locktype; 931 932 /* lock the file to avoid accidental conflicts */ 933 if ((omode & O_ACCMODE) != O_RDONLY) 934 locktype = LOCK_EX; 935 else 936 locktype = LOCK_SH; 937 if (!lockfile(fd, filename, NULL, locktype)) 938 { 939 int save_errno = errno; 940 941 (void) close(fd); 942 fd = -1; 943 errno = save_errno; 944 } 945 else 946 errno = 0; 947 } 948 return fd; 949 } 950