1 /* 2 * Copyright (c) 1998-2002 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 #include <sendmail.h> 15 #include <sm/io.h> 16 #include <sm/errstring.h> 17 18 SM_RCSID("@(#)$Id: safefile.c,v 8.124 2002/05/24 20:50:15 gshapiro Exp $") 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]; 62 63 if (tTd(44, 4)) 64 sm_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 (sm_strlcpy(fbuf, fn, sizeof fbuf) >= sizeof fbuf) 68 { 69 if (tTd(44, 4)) 70 sm_dprintf("\tpathname too long\n"); 71 return ENAMETOOLONG; 72 } 73 fn = fbuf; 74 if (st == NULL) 75 st = &fstbuf; 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 set-user-ID, 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 sm_dprintf("\t%s\n", sm_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 sm_dprintf("\t%s\n", sm_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 ret = 0; 210 if (stbuf.st_uid == uid) 211 /* EMPTY */ 212 ; 213 else if (uid == 0 && stbuf.st_uid == TrustedUid) 214 /* EMPTY */ 215 ; 216 else 217 { 218 md >>= 3; 219 if (stbuf.st_gid == gid) 220 /* EMPTY */ 221 ; 222 # ifndef NO_GROUP_SET 223 else if (user != NULL && !DontInitGroups && 224 ((gr != NULL && 225 gr->gr_gid == stbuf.st_gid) || 226 (gr = getgrgid(stbuf.st_gid)) != NULL)) 227 { 228 register char **gp; 229 230 for (gp = gr->gr_mem; *gp != NULL; gp++) 231 if (strcmp(*gp, user) == 0) 232 break; 233 if (*gp == NULL) 234 md >>= 3; 235 } 236 # endif /* ! NO_GROUP_SET */ 237 else 238 md >>= 3; 239 } 240 if ((stbuf.st_mode & md) != md) 241 ret = errno = EACCES; 242 } 243 else 244 ret = errno; 245 if (tTd(44, 4)) 246 sm_dprintf("\t[final dir %s uid %d mode %lo] %s\n", 247 dir, (int) stbuf.st_uid, 248 (unsigned long) stbuf.st_mode, 249 sm_errstring(ret)); 250 if (p != NULL) 251 *p = '/'; 252 st->st_mode = ST_MODE_NOFILE; 253 return ret; 254 } 255 256 # ifdef S_ISLNK 257 if (bitset(SFF_NOSLINK, flags) && S_ISLNK(st->st_mode)) 258 { 259 if (tTd(44, 4)) 260 sm_dprintf("\t[slink mode %lo]\tE_SM_NOSLINK\n", 261 (unsigned long) st->st_mode); 262 return E_SM_NOSLINK; 263 } 264 # endif /* S_ISLNK */ 265 if (bitset(SFF_REGONLY, flags) && !S_ISREG(st->st_mode)) 266 { 267 if (tTd(44, 4)) 268 sm_dprintf("\t[non-reg mode %lo]\tE_SM_REGONLY\n", 269 (unsigned long) st->st_mode); 270 return E_SM_REGONLY; 271 } 272 if (bitset(SFF_NOGWFILES, flags) && 273 bitset(S_IWGRP, st->st_mode)) 274 { 275 if (tTd(44, 4)) 276 sm_dprintf("\t[write bits %lo]\tE_SM_GWFILE\n", 277 (unsigned long) st->st_mode); 278 return E_SM_GWFILE; 279 } 280 if (bitset(SFF_NOWWFILES, flags) && 281 bitset(S_IWOTH, st->st_mode)) 282 { 283 if (tTd(44, 4)) 284 sm_dprintf("\t[write bits %lo]\tE_SM_WWFILE\n", 285 (unsigned long) st->st_mode); 286 return E_SM_WWFILE; 287 } 288 if (bitset(SFF_NOGRFILES, flags) && bitset(S_IRGRP, st->st_mode)) 289 { 290 if (tTd(44, 4)) 291 sm_dprintf("\t[read bits %lo]\tE_SM_GRFILE\n", 292 (unsigned long) st->st_mode); 293 return E_SM_GRFILE; 294 } 295 if (bitset(SFF_NOWRFILES, flags) && bitset(S_IROTH, st->st_mode)) 296 { 297 if (tTd(44, 4)) 298 sm_dprintf("\t[read bits %lo]\tE_SM_WRFILE\n", 299 (unsigned long) st->st_mode); 300 return E_SM_WRFILE; 301 } 302 if (!bitset(SFF_EXECOK, flags) && 303 bitset(S_IWUSR|S_IWGRP|S_IWOTH, mode) && 304 bitset(S_IXUSR|S_IXGRP|S_IXOTH, st->st_mode)) 305 { 306 if (tTd(44, 4)) 307 sm_dprintf("\t[exec bits %lo]\tE_SM_ISEXEC]\n", 308 (unsigned long) st->st_mode); 309 return E_SM_ISEXEC; 310 } 311 if (bitset(SFF_NOHLINK, flags) && st->st_nlink != 1) 312 { 313 if (tTd(44, 4)) 314 sm_dprintf("\t[link count %d]\tE_SM_NOHLINK\n", 315 (int) st->st_nlink); 316 return E_SM_NOHLINK; 317 } 318 319 if (uid == 0 && bitset(SFF_OPENASROOT, flags)) 320 /* EMPTY */ 321 ; 322 else if (uid == 0 && !bitset(SFF_ROOTOK, flags)) 323 mode >>= 6; 324 else if (st->st_uid == uid) 325 /* EMPTY */ 326 ; 327 else if (uid == 0 && st->st_uid == TrustedUid) 328 /* EMPTY */ 329 ; 330 else 331 { 332 mode >>= 3; 333 if (st->st_gid == gid) 334 /* EMPTY */ 335 ; 336 # ifndef NO_GROUP_SET 337 else if (user != NULL && !DontInitGroups && 338 ((gr != NULL && gr->gr_gid == st->st_gid) || 339 (gr = getgrgid(st->st_gid)) != NULL)) 340 { 341 register char **gp; 342 343 for (gp = gr->gr_mem; *gp != NULL; gp++) 344 if (strcmp(*gp, user) == 0) 345 break; 346 if (*gp == NULL) 347 mode >>= 3; 348 } 349 # endif /* ! NO_GROUP_SET */ 350 else 351 mode >>= 3; 352 } 353 if (tTd(44, 4)) 354 sm_dprintf("\t[uid %d, nlink %d, stat %lo, mode %lo] ", 355 (int) st->st_uid, (int) st->st_nlink, 356 (unsigned long) st->st_mode, (unsigned long) mode); 357 if ((st->st_uid == uid || st->st_uid == 0 || 358 st->st_uid == TrustedUid || 359 !bitset(SFF_MUSTOWN, flags)) && 360 (st->st_mode & mode) == mode) 361 { 362 if (tTd(44, 4)) 363 sm_dprintf("\tOK\n"); 364 return 0; 365 } 366 if (tTd(44, 4)) 367 sm_dprintf("\tEACCES\n"); 368 return EACCES; 369 } 370 /* 371 ** SAFEDIRPATH -- check to make sure a path to a directory is safe 372 ** 373 ** Safe means not writable and owned by the right folks. 374 ** 375 ** Parameters: 376 ** fn -- filename to check. 377 ** uid -- user id to compare against. 378 ** gid -- group id to compare against. 379 ** user -- user name to compare against (used for group 380 ** sets). 381 ** flags -- modifiers: 382 ** SFF_ROOTOK -- ok to use root permissions to open. 383 ** SFF_SAFEDIRPATH -- writable directories are considered 384 ** to be fatal errors. 385 ** level -- symlink recursive level. 386 ** offset -- offset into fn to start checking from. 387 ** 388 ** Returns: 389 ** 0 -- if the directory path is "safe". 390 ** else -- an error number associated with the path. 391 */ 392 393 int 394 safedirpath(fn, uid, gid, user, flags, level, offset) 395 char *fn; 396 UID_T uid; 397 GID_T gid; 398 char *user; 399 long flags; 400 int level; 401 int offset; 402 { 403 int ret = 0; 404 int mode = S_IWOTH; 405 char save = '\0'; 406 char *saveptr = NULL; 407 char *p, *enddir; 408 register struct group *gr = NULL; 409 char s[MAXLINKPATHLEN]; 410 struct stat stbuf; 411 412 /* make sure we aren't in a symlink loop */ 413 if (level > MAXSYMLINKS) 414 return ELOOP; 415 416 if (level < 0 || offset < 0 || offset > strlen(fn)) 417 return EINVAL; 418 419 /* special case root directory */ 420 if (*fn == '\0') 421 fn = "/"; 422 423 if (tTd(44, 4)) 424 sm_dprintf("safedirpath(%s, uid=%ld, gid=%ld, flags=%lx, level=%d, offset=%d):\n", 425 fn, (long) uid, (long) gid, flags, level, offset); 426 427 if (!bitnset(DBS_GROUPWRITABLEDIRPATHSAFE, DontBlameSendmail)) 428 mode |= S_IWGRP; 429 430 /* Make a modifiable copy of the filename */ 431 if (sm_strlcpy(s, fn, sizeof s) >= sizeof s) 432 return EINVAL; 433 434 p = s + offset; 435 while (p != NULL) 436 { 437 /* put back character */ 438 if (saveptr != NULL) 439 { 440 *saveptr = save; 441 saveptr = NULL; 442 p++; 443 } 444 445 if (*p == '\0') 446 break; 447 448 p = strchr(p, '/'); 449 450 /* Special case for root directory */ 451 if (p == s) 452 { 453 save = *(p + 1); 454 saveptr = p + 1; 455 *(p + 1) = '\0'; 456 } 457 else if (p != NULL) 458 { 459 save = *p; 460 saveptr = p; 461 *p = '\0'; 462 } 463 464 /* Heuristic: . and .. have already been checked */ 465 enddir = strrchr(s, '/'); 466 if (enddir != NULL && 467 (strcmp(enddir, "/..") == 0 || 468 strcmp(enddir, "/.") == 0)) 469 continue; 470 471 if (tTd(44, 20)) 472 sm_dprintf("\t[dir %s]\n", s); 473 474 # if HASLSTAT 475 ret = lstat(s, &stbuf); 476 # else /* HASLSTAT */ 477 ret = stat(s, &stbuf); 478 # endif /* HASLSTAT */ 479 if (ret < 0) 480 { 481 ret = errno; 482 break; 483 } 484 485 # ifdef S_ISLNK 486 /* Follow symlinks */ 487 if (S_ISLNK(stbuf.st_mode)) 488 { 489 int linklen; 490 char *target; 491 char buf[MAXPATHLEN]; 492 493 memset(buf, '\0', sizeof buf); 494 linklen = readlink(s, buf, sizeof buf); 495 if (linklen < 0) 496 { 497 ret = errno; 498 break; 499 } 500 if (linklen >= sizeof buf) 501 { 502 /* file name too long for buffer */ 503 ret = errno = EINVAL; 504 break; 505 } 506 507 offset = 0; 508 if (*buf == '/') 509 { 510 target = buf; 511 512 /* If path is the same, avoid rechecks */ 513 while (s[offset] == buf[offset] && 514 s[offset] != '\0') 515 offset++; 516 517 if (s[offset] == '\0' && buf[offset] == '\0') 518 { 519 /* strings match, symlink loop */ 520 return ELOOP; 521 } 522 523 /* back off from the mismatch */ 524 if (offset > 0) 525 offset--; 526 527 /* Make sure we are at a directory break */ 528 if (offset > 0 && 529 s[offset] != '/' && 530 s[offset] != '\0') 531 { 532 while (buf[offset] != '/' && 533 offset > 0) 534 offset--; 535 } 536 if (offset > 0 && 537 s[offset] == '/' && 538 buf[offset] == '/') 539 { 540 /* Include the trailing slash */ 541 offset++; 542 } 543 } 544 else 545 { 546 char *sptr; 547 char fullbuf[MAXLINKPATHLEN]; 548 549 sptr = strrchr(s, '/'); 550 if (sptr != NULL) 551 { 552 *sptr = '\0'; 553 offset = sptr + 1 - s; 554 if (sm_strlcpyn(fullbuf, 555 sizeof fullbuf, 2, 556 s, "/") >= 557 sizeof fullbuf || 558 sm_strlcat(fullbuf, buf, 559 sizeof fullbuf) >= 560 sizeof fullbuf) 561 { 562 ret = EINVAL; 563 break; 564 } 565 *sptr = '/'; 566 } 567 else 568 { 569 if (sm_strlcpy(fullbuf, buf, 570 sizeof fullbuf) >= 571 sizeof fullbuf) 572 { 573 ret = EINVAL; 574 break; 575 } 576 } 577 target = fullbuf; 578 } 579 ret = safedirpath(target, uid, gid, user, flags, 580 level + 1, offset); 581 if (ret != 0) 582 break; 583 584 /* Don't check permissions on the link file itself */ 585 continue; 586 } 587 #endif /* S_ISLNK */ 588 589 if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) && 590 #ifdef S_ISVTX 591 !(bitnset(DBS_TRUSTSTICKYBIT, DontBlameSendmail) && 592 bitset(S_ISVTX, stbuf.st_mode)) && 593 #endif /* S_ISVTX */ 594 bitset(mode, stbuf.st_mode)) 595 { 596 if (tTd(44, 4)) 597 sm_dprintf("\t[dir %s] mode %lo ", 598 s, (unsigned long) stbuf.st_mode); 599 if (bitset(SFF_SAFEDIRPATH, flags)) 600 { 601 if (bitset(S_IWOTH, stbuf.st_mode)) 602 ret = E_SM_WWDIR; 603 else 604 ret = E_SM_GWDIR; 605 if (tTd(44, 4)) 606 sm_dprintf("FATAL\n"); 607 break; 608 } 609 if (tTd(44, 4)) 610 sm_dprintf("WARNING\n"); 611 if (Verbose > 1) 612 message("051 WARNING: %s writable directory %s", 613 bitset(S_IWOTH, stbuf.st_mode) 614 ? "World" 615 : "Group", 616 s); 617 } 618 if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags)) 619 { 620 if (bitset(S_IXOTH, stbuf.st_mode)) 621 continue; 622 ret = EACCES; 623 break; 624 } 625 626 /* 627 ** Let OS determine access to file if we are not 628 ** running as a privileged user. This allows ACLs 629 ** to work. Also, if opening as root, assume we can 630 ** scan the directory. 631 */ 632 if (geteuid() != 0 || bitset(SFF_OPENASROOT, flags)) 633 continue; 634 635 if (stbuf.st_uid == uid && 636 bitset(S_IXUSR, stbuf.st_mode)) 637 continue; 638 if (stbuf.st_gid == gid && 639 bitset(S_IXGRP, stbuf.st_mode)) 640 continue; 641 # ifndef NO_GROUP_SET 642 if (user != NULL && !DontInitGroups && 643 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 644 (gr = getgrgid(stbuf.st_gid)) != NULL)) 645 { 646 register char **gp; 647 648 for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) 649 if (strcmp(*gp, user) == 0) 650 break; 651 if (gp != NULL && *gp != NULL && 652 bitset(S_IXGRP, stbuf.st_mode)) 653 continue; 654 } 655 # endif /* ! NO_GROUP_SET */ 656 if (!bitset(S_IXOTH, stbuf.st_mode)) 657 { 658 ret = EACCES; 659 break; 660 } 661 } 662 if (tTd(44, 4)) 663 sm_dprintf("\t[dir %s] %s\n", fn, 664 ret == 0 ? "OK" : sm_errstring(ret)); 665 return ret; 666 } 667 /* 668 ** SAFEOPEN -- do a file open with extra checking 669 ** 670 ** Parameters: 671 ** fn -- the file name to open. 672 ** omode -- the open-style mode flags. 673 ** cmode -- the create-style mode flags. 674 ** sff -- safefile flags. 675 ** 676 ** Returns: 677 ** Same as open. 678 */ 679 680 int 681 safeopen(fn, omode, cmode, sff) 682 char *fn; 683 int omode; 684 int cmode; 685 long sff; 686 { 687 int rval; 688 int fd; 689 int smode; 690 struct stat stb; 691 692 if (tTd(44, 10)) 693 sm_dprintf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n", 694 fn, omode, cmode, sff); 695 696 if (bitset(O_CREAT, omode)) 697 sff |= SFF_CREAT; 698 omode &= ~O_CREAT; 699 smode = 0; 700 switch (omode & O_ACCMODE) 701 { 702 case O_RDONLY: 703 smode = S_IREAD; 704 break; 705 706 case O_WRONLY: 707 smode = S_IWRITE; 708 break; 709 710 case O_RDWR: 711 smode = S_IREAD|S_IWRITE; 712 break; 713 714 default: 715 smode = 0; 716 break; 717 } 718 if (bitset(SFF_OPENASROOT, sff)) 719 rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName, 720 sff, smode, &stb); 721 else 722 rval = safefile(fn, RealUid, RealGid, RealUserName, 723 sff, smode, &stb); 724 if (rval != 0) 725 { 726 errno = rval; 727 return -1; 728 } 729 if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff)) 730 omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL); 731 else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode)) 732 { 733 /* The file exists so an exclusive create would fail */ 734 errno = EEXIST; 735 return -1; 736 } 737 738 fd = dfopen(fn, omode, cmode, sff); 739 if (fd < 0) 740 return fd; 741 if (filechanged(fn, fd, &stb)) 742 { 743 syserr("554 5.3.0 cannot open: file %s changed after open", fn); 744 (void) close(fd); 745 errno = E_SM_FILECHANGE; 746 return -1; 747 } 748 return fd; 749 } 750 /* 751 ** SAFEFOPEN -- do a file open with extra checking 752 ** 753 ** Parameters: 754 ** fn -- the file name to open. 755 ** omode -- the open-style mode flags. 756 ** cmode -- the create-style mode flags. 757 ** sff -- safefile flags. 758 ** 759 ** Returns: 760 ** Same as fopen. 761 */ 762 763 SM_FILE_T * 764 safefopen(fn, omode, cmode, sff) 765 char *fn; 766 int omode; 767 int cmode; 768 long sff; 769 { 770 int fd; 771 int save_errno; 772 SM_FILE_T *fp; 773 int fmode; 774 775 switch (omode & O_ACCMODE) 776 { 777 case O_RDONLY: 778 fmode = SM_IO_RDONLY; 779 break; 780 781 case O_WRONLY: 782 if (bitset(O_APPEND, omode)) 783 fmode = SM_IO_APPEND; 784 else 785 fmode = SM_IO_WRONLY; 786 break; 787 788 case O_RDWR: 789 if (bitset(O_TRUNC, omode)) 790 fmode = SM_IO_RDWRTR; 791 else if (bitset(O_APPEND, omode)) 792 fmode = SM_IO_APPENDRW; 793 else 794 fmode = SM_IO_RDWR; 795 break; 796 797 default: 798 syserr("554 5.3.5 safefopen: unknown omode %o", omode); 799 fmode = 0; 800 } 801 fd = safeopen(fn, omode, cmode, sff); 802 if (fd < 0) 803 { 804 save_errno = errno; 805 if (tTd(44, 10)) 806 sm_dprintf("safefopen: safeopen failed: %s\n", 807 sm_errstring(errno)); 808 errno = save_errno; 809 return NULL; 810 } 811 fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 812 (void *) &fd, fmode, NULL); 813 if (fp != NULL) 814 return fp; 815 816 save_errno = errno; 817 if (tTd(44, 10)) 818 { 819 sm_dprintf("safefopen: fdopen(%s, %d) failed: omode=%x, sff=%lx, err=%s\n", 820 fn, fmode, omode, sff, sm_errstring(errno)); 821 } 822 (void) close(fd); 823 errno = save_errno; 824 return NULL; 825 } 826 /* 827 ** FILECHANGED -- check to see if file changed after being opened 828 ** 829 ** Parameters: 830 ** fn -- pathname of file to check. 831 ** fd -- file descriptor to check. 832 ** stb -- stat structure from before open. 833 ** 834 ** Returns: 835 ** true -- if a problem was detected. 836 ** false -- if this file is still the same. 837 */ 838 839 bool 840 filechanged(fn, fd, stb) 841 char *fn; 842 int fd; 843 struct stat *stb; 844 { 845 struct stat sta; 846 847 if (stb->st_mode == ST_MODE_NOFILE) 848 { 849 # if HASLSTAT && BOGUS_O_EXCL 850 /* only necessary if exclusive open follows symbolic links */ 851 if (lstat(fn, stb) < 0 || stb->st_nlink != 1) 852 return true; 853 # else /* HASLSTAT && BOGUS_O_EXCL */ 854 return false; 855 # endif /* HASLSTAT && BOGUS_O_EXCL */ 856 } 857 if (fstat(fd, &sta) < 0) 858 return true; 859 860 if (sta.st_nlink != stb->st_nlink || 861 sta.st_dev != stb->st_dev || 862 sta.st_ino != stb->st_ino || 863 # if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 864 sta.st_gen != stb->st_gen || 865 # endif /* HAS_ST_GEN && 0 */ 866 sta.st_uid != stb->st_uid || 867 sta.st_gid != stb->st_gid) 868 { 869 if (tTd(44, 8)) 870 { 871 sm_dprintf("File changed after opening:\n"); 872 sm_dprintf(" nlink = %ld/%ld\n", 873 (long) stb->st_nlink, (long) sta.st_nlink); 874 sm_dprintf(" dev = %ld/%ld\n", 875 (long) stb->st_dev, (long) sta.st_dev); 876 sm_dprintf(" ino = %llu/%llu\n", 877 (ULONGLONG_T) stb->st_ino, 878 (ULONGLONG_T) sta.st_ino); 879 # if HAS_ST_GEN 880 sm_dprintf(" gen = %ld/%ld\n", 881 (long) stb->st_gen, (long) sta.st_gen); 882 # endif /* HAS_ST_GEN */ 883 sm_dprintf(" uid = %ld/%ld\n", 884 (long) stb->st_uid, (long) sta.st_uid); 885 sm_dprintf(" gid = %ld/%ld\n", 886 (long) stb->st_gid, (long) sta.st_gid); 887 } 888 return true; 889 } 890 891 return false; 892 } 893 /* 894 ** DFOPEN -- determined file open 895 ** 896 ** This routine has the semantics of open, except that it will 897 ** keep trying a few times to make this happen. The idea is that 898 ** on very loaded systems, we may run out of resources (inodes, 899 ** whatever), so this tries to get around it. 900 */ 901 902 int 903 dfopen(filename, omode, cmode, sff) 904 char *filename; 905 int omode; 906 int cmode; 907 long sff; 908 { 909 register int tries; 910 int fd = -1; 911 struct stat st; 912 913 for (tries = 0; tries < 10; tries++) 914 { 915 (void) sleep((unsigned) (10 * tries)); 916 errno = 0; 917 fd = open(filename, omode, cmode); 918 if (fd >= 0) 919 break; 920 switch (errno) 921 { 922 case ENFILE: /* system file table full */ 923 case EINTR: /* interrupted syscall */ 924 #ifdef ETXTBSY 925 case ETXTBSY: /* Apollo: net file locked */ 926 #endif /* ETXTBSY */ 927 continue; 928 } 929 break; 930 } 931 if (!bitset(SFF_NOLOCK, sff) && 932 fd >= 0 && 933 fstat(fd, &st) >= 0 && 934 S_ISREG(st.st_mode)) 935 { 936 int locktype; 937 938 /* lock the file to avoid accidental conflicts */ 939 if ((omode & O_ACCMODE) != O_RDONLY) 940 locktype = LOCK_EX; 941 else 942 locktype = LOCK_SH; 943 if (!lockfile(fd, filename, NULL, locktype)) 944 { 945 int save_errno = errno; 946 947 (void) close(fd); 948 fd = -1; 949 errno = save_errno; 950 } 951 else 952 errno = 0; 953 } 954 return fd; 955 } 956