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