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 #include <sendmail.h> 15 #include <sm/io.h> 16 #include <sm/errstring.h> 17 18 SM_RCSID("@(#)$Id: safefile.c,v 1.1.1.4 2002/02/17 21:56:42 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 + 1]; 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 + 1]; 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 char *target; 490 char buf[MAXPATHLEN + 1]; 491 492 memset(buf, '\0', sizeof buf); 493 if (readlink(s, buf, sizeof buf) < 0) 494 { 495 ret = errno; 496 break; 497 } 498 499 offset = 0; 500 if (*buf == '/') 501 { 502 target = buf; 503 504 /* If path is the same, avoid rechecks */ 505 while (s[offset] == buf[offset] && 506 s[offset] != '\0') 507 offset++; 508 509 if (s[offset] == '\0' && buf[offset] == '\0') 510 { 511 /* strings match, symlink loop */ 512 return ELOOP; 513 } 514 515 /* back off from the mismatch */ 516 if (offset > 0) 517 offset--; 518 519 /* Make sure we are at a directory break */ 520 if (offset > 0 && 521 s[offset] != '/' && 522 s[offset] != '\0') 523 { 524 while (buf[offset] != '/' && 525 offset > 0) 526 offset--; 527 } 528 if (offset > 0 && 529 s[offset] == '/' && 530 buf[offset] == '/') 531 { 532 /* Include the trailing slash */ 533 offset++; 534 } 535 } 536 else 537 { 538 char *sptr; 539 char fullbuf[MAXLINKPATHLEN + 1]; 540 541 sptr = strrchr(s, '/'); 542 if (sptr != NULL) 543 { 544 *sptr = '\0'; 545 offset = sptr + 1 - s; 546 if (sm_strlcpyn(fullbuf, 547 sizeof fullbuf, 2, 548 s, "/") >= 549 sizeof fullbuf || 550 sm_strlcat(fullbuf, buf, 551 sizeof fullbuf) >= 552 sizeof fullbuf) 553 { 554 ret = EINVAL; 555 break; 556 } 557 *sptr = '/'; 558 } 559 else 560 { 561 if (sm_strlcpy(fullbuf, buf, 562 sizeof fullbuf) >= 563 sizeof fullbuf) 564 { 565 ret = EINVAL; 566 break; 567 } 568 } 569 target = fullbuf; 570 } 571 ret = safedirpath(target, uid, gid, user, flags, 572 level + 1, offset); 573 if (ret != 0) 574 break; 575 576 /* Don't check permissions on the link file itself */ 577 continue; 578 } 579 #endif /* S_ISLNK */ 580 581 if ((uid == 0 || bitset(SFF_SAFEDIRPATH, flags)) && 582 #ifdef S_ISVTX 583 !(bitnset(DBS_TRUSTSTICKYBIT, DontBlameSendmail) && 584 bitset(S_ISVTX, stbuf.st_mode)) && 585 #endif /* S_ISVTX */ 586 bitset(mode, stbuf.st_mode)) 587 { 588 if (tTd(44, 4)) 589 sm_dprintf("\t[dir %s] mode %lo ", 590 s, (unsigned long) stbuf.st_mode); 591 if (bitset(SFF_SAFEDIRPATH, flags)) 592 { 593 if (bitset(S_IWOTH, stbuf.st_mode)) 594 ret = E_SM_WWDIR; 595 else 596 ret = E_SM_GWDIR; 597 if (tTd(44, 4)) 598 sm_dprintf("FATAL\n"); 599 break; 600 } 601 if (tTd(44, 4)) 602 sm_dprintf("WARNING\n"); 603 if (Verbose > 1) 604 message("051 WARNING: %s writable directory %s", 605 bitset(S_IWOTH, stbuf.st_mode) 606 ? "World" 607 : "Group", 608 s); 609 } 610 if (uid == 0 && !bitset(SFF_ROOTOK|SFF_OPENASROOT, flags)) 611 { 612 if (bitset(S_IXOTH, stbuf.st_mode)) 613 continue; 614 ret = EACCES; 615 break; 616 } 617 618 /* 619 ** Let OS determine access to file if we are not 620 ** running as a privileged user. This allows ACLs 621 ** to work. Also, if opening as root, assume we can 622 ** scan the directory. 623 */ 624 if (geteuid() != 0 || bitset(SFF_OPENASROOT, flags)) 625 continue; 626 627 if (stbuf.st_uid == uid && 628 bitset(S_IXUSR, stbuf.st_mode)) 629 continue; 630 if (stbuf.st_gid == gid && 631 bitset(S_IXGRP, stbuf.st_mode)) 632 continue; 633 # ifndef NO_GROUP_SET 634 if (user != NULL && !DontInitGroups && 635 ((gr != NULL && gr->gr_gid == stbuf.st_gid) || 636 (gr = getgrgid(stbuf.st_gid)) != NULL)) 637 { 638 register char **gp; 639 640 for (gp = gr->gr_mem; gp != NULL && *gp != NULL; gp++) 641 if (strcmp(*gp, user) == 0) 642 break; 643 if (gp != NULL && *gp != NULL && 644 bitset(S_IXGRP, stbuf.st_mode)) 645 continue; 646 } 647 # endif /* ! NO_GROUP_SET */ 648 if (!bitset(S_IXOTH, stbuf.st_mode)) 649 { 650 ret = EACCES; 651 break; 652 } 653 } 654 if (tTd(44, 4)) 655 sm_dprintf("\t[dir %s] %s\n", fn, 656 ret == 0 ? "OK" : sm_errstring(ret)); 657 return ret; 658 } 659 /* 660 ** SAFEOPEN -- do a file open with extra checking 661 ** 662 ** Parameters: 663 ** fn -- the file name to open. 664 ** omode -- the open-style mode flags. 665 ** cmode -- the create-style mode flags. 666 ** sff -- safefile flags. 667 ** 668 ** Returns: 669 ** Same as open. 670 */ 671 672 int 673 safeopen(fn, omode, cmode, sff) 674 char *fn; 675 int omode; 676 int cmode; 677 long sff; 678 { 679 int rval; 680 int fd; 681 int smode; 682 struct stat stb; 683 684 if (tTd(44, 10)) 685 sm_dprintf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n", 686 fn, omode, cmode, sff); 687 688 if (bitset(O_CREAT, omode)) 689 sff |= SFF_CREAT; 690 omode &= ~O_CREAT; 691 smode = 0; 692 switch (omode & O_ACCMODE) 693 { 694 case O_RDONLY: 695 smode = S_IREAD; 696 break; 697 698 case O_WRONLY: 699 smode = S_IWRITE; 700 break; 701 702 case O_RDWR: 703 smode = S_IREAD|S_IWRITE; 704 break; 705 706 default: 707 smode = 0; 708 break; 709 } 710 if (bitset(SFF_OPENASROOT, sff)) 711 rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName, 712 sff, smode, &stb); 713 else 714 rval = safefile(fn, RealUid, RealGid, RealUserName, 715 sff, smode, &stb); 716 if (rval != 0) 717 { 718 errno = rval; 719 return -1; 720 } 721 if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff)) 722 omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL); 723 else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode)) 724 { 725 /* The file exists so an exclusive create would fail */ 726 errno = EEXIST; 727 return -1; 728 } 729 730 fd = dfopen(fn, omode, cmode, sff); 731 if (fd < 0) 732 return fd; 733 if (filechanged(fn, fd, &stb)) 734 { 735 syserr("554 5.3.0 cannot open: file %s changed after open", fn); 736 (void) close(fd); 737 errno = E_SM_FILECHANGE; 738 return -1; 739 } 740 return fd; 741 } 742 /* 743 ** SAFEFOPEN -- do a file open with extra checking 744 ** 745 ** Parameters: 746 ** fn -- the file name to open. 747 ** omode -- the open-style mode flags. 748 ** cmode -- the create-style mode flags. 749 ** sff -- safefile flags. 750 ** 751 ** Returns: 752 ** Same as fopen. 753 */ 754 755 SM_FILE_T * 756 safefopen(fn, omode, cmode, sff) 757 char *fn; 758 int omode; 759 int cmode; 760 long sff; 761 { 762 int fd; 763 int save_errno; 764 SM_FILE_T *fp; 765 int fmode; 766 767 switch (omode & O_ACCMODE) 768 { 769 case O_RDONLY: 770 fmode = SM_IO_RDONLY; 771 break; 772 773 case O_WRONLY: 774 if (bitset(O_APPEND, omode)) 775 fmode = SM_IO_APPEND; 776 else 777 fmode = SM_IO_WRONLY; 778 break; 779 780 case O_RDWR: 781 if (bitset(O_TRUNC, omode)) 782 fmode = SM_IO_RDWRTR; 783 else if (bitset(O_APPEND, omode)) 784 fmode = SM_IO_APPENDRW; 785 else 786 fmode = SM_IO_RDWR; 787 break; 788 789 default: 790 syserr("554 5.3.5 safefopen: unknown omode %o", omode); 791 fmode = 0; 792 } 793 fd = safeopen(fn, omode, cmode, sff); 794 if (fd < 0) 795 { 796 save_errno = errno; 797 if (tTd(44, 10)) 798 sm_dprintf("safefopen: safeopen failed: %s\n", 799 sm_errstring(errno)); 800 errno = save_errno; 801 return NULL; 802 } 803 fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 804 (void *) &fd, fmode, NULL); 805 if (fp != NULL) 806 return fp; 807 808 save_errno = errno; 809 if (tTd(44, 10)) 810 { 811 sm_dprintf("safefopen: fdopen(%s, %d) failed: omode=%x, sff=%lx, err=%s\n", 812 fn, fmode, omode, sff, sm_errstring(errno)); 813 } 814 (void) close(fd); 815 errno = save_errno; 816 return NULL; 817 } 818 /* 819 ** FILECHANGED -- check to see if file changed after being opened 820 ** 821 ** Parameters: 822 ** fn -- pathname of file to check. 823 ** fd -- file descriptor to check. 824 ** stb -- stat structure from before open. 825 ** 826 ** Returns: 827 ** true -- if a problem was detected. 828 ** false -- if this file is still the same. 829 */ 830 831 bool 832 filechanged(fn, fd, stb) 833 char *fn; 834 int fd; 835 struct stat *stb; 836 { 837 struct stat sta; 838 839 if (stb->st_mode == ST_MODE_NOFILE) 840 { 841 # if HASLSTAT && BOGUS_O_EXCL 842 /* only necessary if exclusive open follows symbolic links */ 843 if (lstat(fn, stb) < 0 || stb->st_nlink != 1) 844 return true; 845 # else /* HASLSTAT && BOGUS_O_EXCL */ 846 return false; 847 # endif /* HASLSTAT && BOGUS_O_EXCL */ 848 } 849 if (fstat(fd, &sta) < 0) 850 return true; 851 852 if (sta.st_nlink != stb->st_nlink || 853 sta.st_dev != stb->st_dev || 854 sta.st_ino != stb->st_ino || 855 # if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 856 sta.st_gen != stb->st_gen || 857 # endif /* HAS_ST_GEN && 0 */ 858 sta.st_uid != stb->st_uid || 859 sta.st_gid != stb->st_gid) 860 { 861 if (tTd(44, 8)) 862 { 863 sm_dprintf("File changed after opening:\n"); 864 sm_dprintf(" nlink = %ld/%ld\n", 865 (long) stb->st_nlink, (long) sta.st_nlink); 866 sm_dprintf(" dev = %ld/%ld\n", 867 (long) stb->st_dev, (long) sta.st_dev); 868 sm_dprintf(" ino = %llu/%llu\n", 869 (ULONGLONG_T) stb->st_ino, 870 (ULONGLONG_T) sta.st_ino); 871 # if HAS_ST_GEN 872 sm_dprintf(" gen = %ld/%ld\n", 873 (long) stb->st_gen, (long) sta.st_gen); 874 # endif /* HAS_ST_GEN */ 875 sm_dprintf(" uid = %ld/%ld\n", 876 (long) stb->st_uid, (long) sta.st_uid); 877 sm_dprintf(" gid = %ld/%ld\n", 878 (long) stb->st_gid, (long) sta.st_gid); 879 } 880 return true; 881 } 882 883 return false; 884 } 885 /* 886 ** DFOPEN -- determined file open 887 ** 888 ** This routine has the semantics of open, except that it will 889 ** keep trying a few times to make this happen. The idea is that 890 ** on very loaded systems, we may run out of resources (inodes, 891 ** whatever), so this tries to get around it. 892 */ 893 894 int 895 dfopen(filename, omode, cmode, sff) 896 char *filename; 897 int omode; 898 int cmode; 899 long sff; 900 { 901 register int tries; 902 int fd = -1; 903 struct stat st; 904 905 for (tries = 0; tries < 10; tries++) 906 { 907 (void) sleep((unsigned) (10 * tries)); 908 errno = 0; 909 fd = open(filename, omode, cmode); 910 if (fd >= 0) 911 break; 912 switch (errno) 913 { 914 case ENFILE: /* system file table full */ 915 case EINTR: /* interrupted syscall */ 916 #ifdef ETXTBSY 917 case ETXTBSY: /* Apollo: net file locked */ 918 #endif /* ETXTBSY */ 919 continue; 920 } 921 break; 922 } 923 if (!bitset(SFF_NOLOCK, sff) && 924 fd >= 0 && 925 fstat(fd, &st) >= 0 && 926 S_ISREG(st.st_mode)) 927 { 928 int locktype; 929 930 /* lock the file to avoid accidental conflicts */ 931 if ((omode & O_ACCMODE) != O_RDONLY) 932 locktype = LOCK_EX; 933 else 934 locktype = LOCK_SH; 935 if (!lockfile(fd, filename, NULL, locktype)) 936 { 937 int save_errno = errno; 938 939 (void) close(fd); 940 fd = -1; 941 errno = save_errno; 942 } 943 else 944 errno = 0; 945 } 946 return fd; 947 } 948