1 /* 2 * Copyright (c) 1998-2001 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.10 2001/07/20 04:19:36 gshapiro 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 int 664 safeopen(fn, omode, cmode, sff) 665 char *fn; 666 int omode; 667 int cmode; 668 long sff; 669 { 670 int rval; 671 int fd; 672 int smode; 673 struct stat stb; 674 675 if (tTd(44, 10)) 676 printf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n", 677 fn, omode, cmode, sff); 678 679 if (bitset(O_CREAT, omode)) 680 sff |= SFF_CREAT; 681 omode &= ~O_CREAT; 682 smode = 0; 683 switch (omode & O_ACCMODE) 684 { 685 case O_RDONLY: 686 smode = S_IREAD; 687 break; 688 689 case O_WRONLY: 690 smode = S_IWRITE; 691 break; 692 693 case O_RDWR: 694 smode = S_IREAD|S_IWRITE; 695 break; 696 697 default: 698 smode = 0; 699 break; 700 } 701 if (bitset(SFF_OPENASROOT, sff)) 702 rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName, 703 sff, smode, &stb); 704 else 705 rval = safefile(fn, RealUid, RealGid, RealUserName, 706 sff, smode, &stb); 707 if (rval != 0) 708 { 709 errno = rval; 710 return -1; 711 } 712 if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff)) 713 omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL); 714 else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode)) 715 { 716 /* The file exists so an exclusive create would fail */ 717 errno = EEXIST; 718 return -1; 719 } 720 721 fd = dfopen(fn, omode, cmode, sff); 722 if (fd < 0) 723 return fd; 724 if (filechanged(fn, fd, &stb)) 725 { 726 syserr("554 5.3.0 cannot open: file %s changed after open", fn); 727 (void) close(fd); 728 errno = E_SM_FILECHANGE; 729 return -1; 730 } 731 return fd; 732 } 733 /* 734 ** FILECHANGED -- check to see if file changed after being opened 735 ** 736 ** Parameters: 737 ** fn -- pathname of file to check. 738 ** fd -- file descriptor to check. 739 ** stb -- stat structure from before open. 740 ** 741 ** Returns: 742 ** TRUE -- if a problem was detected. 743 ** FALSE -- if this file is still the same. 744 */ 745 746 bool 747 filechanged(fn, fd, stb) 748 char *fn; 749 int fd; 750 struct stat *stb; 751 { 752 struct stat sta; 753 754 if (stb->st_mode == ST_MODE_NOFILE) 755 { 756 # if HASLSTAT && BOGUS_O_EXCL 757 /* only necessary if exclusive open follows symbolic links */ 758 if (lstat(fn, stb) < 0 || stb->st_nlink != 1) 759 return TRUE; 760 # else /* HASLSTAT && BOGUS_O_EXCL */ 761 return FALSE; 762 # endif /* HASLSTAT && BOGUS_O_EXCL */ 763 } 764 if (fstat(fd, &sta) < 0) 765 return TRUE; 766 767 if (sta.st_nlink != stb->st_nlink || 768 sta.st_dev != stb->st_dev || 769 sta.st_ino != stb->st_ino || 770 # if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 771 sta.st_gen != stb->st_gen || 772 # endif /* HAS_ST_GEN && 0 */ 773 sta.st_uid != stb->st_uid || 774 sta.st_gid != stb->st_gid) 775 { 776 if (tTd(44, 8)) 777 { 778 dprintf("File changed after opening:\n"); 779 dprintf(" nlink = %ld/%ld\n", 780 (long) stb->st_nlink, (long) sta.st_nlink); 781 dprintf(" dev = %ld/%ld\n", 782 (long) stb->st_dev, (long) sta.st_dev); 783 if (sizeof sta.st_ino > sizeof (long)) 784 { 785 dprintf(" ino = %s/", 786 quad_to_string(stb->st_ino)); 787 dprintf("%s\n", 788 quad_to_string(sta.st_ino)); 789 } 790 else 791 dprintf(" ino = %lu/%lu\n", 792 (unsigned long) stb->st_ino, 793 (unsigned long) sta.st_ino); 794 # if HAS_ST_GEN 795 dprintf(" gen = %ld/%ld\n", 796 (long) stb->st_gen, (long) sta.st_gen); 797 # endif /* HAS_ST_GEN */ 798 dprintf(" uid = %ld/%ld\n", 799 (long) stb->st_uid, (long) sta.st_uid); 800 dprintf(" gid = %ld/%ld\n", 801 (long) stb->st_gid, (long) sta.st_gid); 802 } 803 return TRUE; 804 } 805 806 return FALSE; 807 } 808 /* 809 ** DFOPEN -- determined file open 810 ** 811 ** This routine has the semantics of open, except that it will 812 ** keep trying a few times to make this happen. The idea is that 813 ** on very loaded systems, we may run out of resources (inodes, 814 ** whatever), so this tries to get around it. 815 */ 816 817 int 818 dfopen(filename, omode, cmode, sff) 819 char *filename; 820 int omode; 821 int cmode; 822 long sff; 823 { 824 register int tries; 825 int fd = -1; 826 struct stat st; 827 828 for (tries = 0; tries < 10; tries++) 829 { 830 (void) sleep((unsigned) (10 * tries)); 831 errno = 0; 832 fd = open(filename, omode, cmode); 833 if (fd >= 0) 834 break; 835 switch (errno) 836 { 837 case ENFILE: /* system file table full */ 838 case EINTR: /* interrupted syscall */ 839 #ifdef ETXTBSY 840 case ETXTBSY: /* Apollo: net file locked */ 841 #endif /* ETXTBSY */ 842 continue; 843 } 844 break; 845 } 846 if (!bitset(SFF_NOLOCK, sff) && 847 fd >= 0 && 848 fstat(fd, &st) >= 0 && 849 S_ISREG(st.st_mode)) 850 { 851 int locktype; 852 853 /* lock the file to avoid accidental conflicts */ 854 if ((omode & O_ACCMODE) != O_RDONLY) 855 locktype = LOCK_EX; 856 else 857 locktype = LOCK_SH; 858 if (!lockfile(fd, filename, NULL, locktype)) 859 { 860 int save_errno = errno; 861 862 (void) close(fd); 863 fd = -1; 864 errno = save_errno; 865 } 866 else 867 errno = 0; 868 } 869 return fd; 870 } 871