1 /* 2 * Copyright (c) 1998-2004 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.129 2008/08/04 18:07:04 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 char fullbuf[MAXLINKPATHLEN]; 493 494 memset(buf, '\0', sizeof buf); 495 linklen = readlink(s, buf, sizeof buf); 496 if (linklen < 0) 497 { 498 ret = errno; 499 break; 500 } 501 if (linklen >= sizeof buf) 502 { 503 /* file name too long for buffer */ 504 ret = errno = EINVAL; 505 break; 506 } 507 508 offset = 0; 509 if (*buf == '/') 510 { 511 target = buf; 512 513 /* If path is the same, avoid rechecks */ 514 while (s[offset] == buf[offset] && 515 s[offset] != '\0') 516 offset++; 517 518 if (s[offset] == '\0' && buf[offset] == '\0') 519 { 520 /* strings match, symlink loop */ 521 return ELOOP; 522 } 523 524 /* back off from the mismatch */ 525 if (offset > 0) 526 offset--; 527 528 /* Make sure we are at a directory break */ 529 if (offset > 0 && 530 s[offset] != '/' && 531 s[offset] != '\0') 532 { 533 while (buf[offset] != '/' && 534 offset > 0) 535 offset--; 536 } 537 if (offset > 0 && 538 s[offset] == '/' && 539 buf[offset] == '/') 540 { 541 /* Include the trailing slash */ 542 offset++; 543 } 544 } 545 else 546 { 547 char *sptr; 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 #if !NOFTRUNCATE 688 bool truncate; 689 #endif /* !NOFTRUNCATE */ 690 int rval; 691 int fd; 692 int smode; 693 struct stat stb; 694 695 if (tTd(44, 10)) 696 sm_dprintf("safeopen: fn=%s, omode=%x, cmode=%x, sff=%lx\n", 697 fn, omode, cmode, sff); 698 699 if (bitset(O_CREAT, omode)) 700 sff |= SFF_CREAT; 701 omode &= ~O_CREAT; 702 switch (omode & O_ACCMODE) 703 { 704 case O_RDONLY: 705 smode = S_IREAD; 706 break; 707 708 case O_WRONLY: 709 smode = S_IWRITE; 710 break; 711 712 case O_RDWR: 713 smode = S_IREAD|S_IWRITE; 714 break; 715 716 default: 717 smode = 0; 718 break; 719 } 720 if (bitset(SFF_OPENASROOT, sff)) 721 rval = safefile(fn, RunAsUid, RunAsGid, RunAsUserName, 722 sff, smode, &stb); 723 else 724 rval = safefile(fn, RealUid, RealGid, RealUserName, 725 sff, smode, &stb); 726 if (rval != 0) 727 { 728 errno = rval; 729 return -1; 730 } 731 if (stb.st_mode == ST_MODE_NOFILE && bitset(SFF_CREAT, sff)) 732 omode |= O_CREAT | (bitset(SFF_NOTEXCL, sff) ? 0 : O_EXCL); 733 else if (bitset(SFF_CREAT, sff) && bitset(O_EXCL, omode)) 734 { 735 /* The file exists so an exclusive create would fail */ 736 errno = EEXIST; 737 return -1; 738 } 739 740 #if !NOFTRUNCATE 741 truncate = bitset(O_TRUNC, omode); 742 if (truncate) 743 omode &= ~O_TRUNC; 744 #endif /* !NOFTRUNCATE */ 745 746 fd = dfopen(fn, omode, cmode, sff); 747 if (fd < 0) 748 return fd; 749 if (filechanged(fn, fd, &stb)) 750 { 751 syserr("554 5.3.0 cannot open: file %s changed after open", fn); 752 (void) close(fd); 753 errno = E_SM_FILECHANGE; 754 return -1; 755 } 756 757 #if !NOFTRUNCATE 758 if (truncate && 759 ftruncate(fd, (off_t) 0) < 0) 760 { 761 int save_errno; 762 763 save_errno = errno; 764 syserr("554 5.3.0 cannot open: file %s could not be truncated", 765 fn); 766 (void) close(fd); 767 errno = save_errno; 768 return -1; 769 } 770 #endif /* !NOFTRUNCATE */ 771 772 return fd; 773 } 774 /* 775 ** SAFEFOPEN -- do a file open with extra checking 776 ** 777 ** Parameters: 778 ** fn -- the file name to open. 779 ** omode -- the open-style mode flags. 780 ** cmode -- the create-style mode flags. 781 ** sff -- safefile flags. 782 ** 783 ** Returns: 784 ** Same as fopen. 785 */ 786 787 SM_FILE_T * 788 safefopen(fn, omode, cmode, sff) 789 char *fn; 790 int omode; 791 int cmode; 792 long sff; 793 { 794 int fd; 795 int save_errno; 796 SM_FILE_T *fp; 797 int fmode; 798 799 switch (omode & O_ACCMODE) 800 { 801 case O_RDONLY: 802 fmode = SM_IO_RDONLY; 803 break; 804 805 case O_WRONLY: 806 if (bitset(O_APPEND, omode)) 807 fmode = SM_IO_APPEND; 808 else 809 fmode = SM_IO_WRONLY; 810 break; 811 812 case O_RDWR: 813 if (bitset(O_TRUNC, omode)) 814 fmode = SM_IO_RDWRTR; 815 else if (bitset(O_APPEND, omode)) 816 fmode = SM_IO_APPENDRW; 817 else 818 fmode = SM_IO_RDWR; 819 break; 820 821 default: 822 syserr("554 5.3.5 safefopen: unknown omode %o", omode); 823 fmode = 0; 824 } 825 fd = safeopen(fn, omode, cmode, sff); 826 if (fd < 0) 827 { 828 save_errno = errno; 829 if (tTd(44, 10)) 830 sm_dprintf("safefopen: safeopen failed: %s\n", 831 sm_errstring(errno)); 832 errno = save_errno; 833 return NULL; 834 } 835 fp = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT, 836 (void *) &fd, fmode, NULL); 837 if (fp != NULL) 838 return fp; 839 840 save_errno = errno; 841 if (tTd(44, 10)) 842 { 843 sm_dprintf("safefopen: fdopen(%s, %d) failed: omode=%x, sff=%lx, err=%s\n", 844 fn, fmode, omode, sff, sm_errstring(errno)); 845 } 846 (void) close(fd); 847 errno = save_errno; 848 return NULL; 849 } 850 /* 851 ** FILECHANGED -- check to see if file changed after being opened 852 ** 853 ** Parameters: 854 ** fn -- pathname of file to check. 855 ** fd -- file descriptor to check. 856 ** stb -- stat structure from before open. 857 ** 858 ** Returns: 859 ** true -- if a problem was detected. 860 ** false -- if this file is still the same. 861 */ 862 863 bool 864 filechanged(fn, fd, stb) 865 char *fn; 866 int fd; 867 struct stat *stb; 868 { 869 struct stat sta; 870 871 if (stb->st_mode == ST_MODE_NOFILE) 872 { 873 # if HASLSTAT && BOGUS_O_EXCL 874 /* only necessary if exclusive open follows symbolic links */ 875 if (lstat(fn, stb) < 0 || stb->st_nlink != 1) 876 return true; 877 # else /* HASLSTAT && BOGUS_O_EXCL */ 878 return false; 879 # endif /* HASLSTAT && BOGUS_O_EXCL */ 880 } 881 if (fstat(fd, &sta) < 0) 882 return true; 883 884 if (sta.st_nlink != stb->st_nlink || 885 sta.st_dev != stb->st_dev || 886 sta.st_ino != stb->st_ino || 887 # if HAS_ST_GEN && 0 /* AFS returns garbage in st_gen */ 888 sta.st_gen != stb->st_gen || 889 # endif /* HAS_ST_GEN && 0 */ 890 sta.st_uid != stb->st_uid || 891 sta.st_gid != stb->st_gid) 892 { 893 if (tTd(44, 8)) 894 { 895 sm_dprintf("File changed after opening:\n"); 896 sm_dprintf(" nlink = %ld/%ld\n", 897 (long) stb->st_nlink, (long) sta.st_nlink); 898 sm_dprintf(" dev = %ld/%ld\n", 899 (long) stb->st_dev, (long) sta.st_dev); 900 sm_dprintf(" ino = %llu/%llu\n", 901 (ULONGLONG_T) stb->st_ino, 902 (ULONGLONG_T) sta.st_ino); 903 # if HAS_ST_GEN 904 sm_dprintf(" gen = %ld/%ld\n", 905 (long) stb->st_gen, (long) sta.st_gen); 906 # endif /* HAS_ST_GEN */ 907 sm_dprintf(" uid = %ld/%ld\n", 908 (long) stb->st_uid, (long) sta.st_uid); 909 sm_dprintf(" gid = %ld/%ld\n", 910 (long) stb->st_gid, (long) sta.st_gid); 911 } 912 return true; 913 } 914 915 return false; 916 } 917 /* 918 ** DFOPEN -- determined file open 919 ** 920 ** This routine has the semantics of open, except that it will 921 ** keep trying a few times to make this happen. The idea is that 922 ** on very loaded systems, we may run out of resources (inodes, 923 ** whatever), so this tries to get around it. 924 */ 925 926 int 927 dfopen(filename, omode, cmode, sff) 928 char *filename; 929 int omode; 930 int cmode; 931 long sff; 932 { 933 register int tries; 934 int fd = -1; 935 struct stat st; 936 937 for (tries = 0; tries < 10; tries++) 938 { 939 (void) sleep((unsigned) (10 * tries)); 940 errno = 0; 941 fd = open(filename, omode, cmode); 942 if (fd >= 0) 943 break; 944 switch (errno) 945 { 946 case ENFILE: /* system file table full */ 947 case EINTR: /* interrupted syscall */ 948 #ifdef ETXTBSY 949 case ETXTBSY: /* Apollo: net file locked */ 950 #endif /* ETXTBSY */ 951 continue; 952 } 953 break; 954 } 955 if (!bitset(SFF_NOLOCK, sff) && 956 fd >= 0 && 957 fstat(fd, &st) >= 0 && 958 S_ISREG(st.st_mode)) 959 { 960 int locktype; 961 962 /* lock the file to avoid accidental conflicts */ 963 if ((omode & O_ACCMODE) != O_RDONLY) 964 locktype = LOCK_EX; 965 else 966 locktype = LOCK_SH; 967 if (bitset(SFF_NBLOCK, sff)) 968 locktype |= LOCK_NB; 969 970 if (!lockfile(fd, filename, NULL, locktype)) 971 { 972 int save_errno = errno; 973 974 (void) close(fd); 975 fd = -1; 976 errno = save_errno; 977 } 978 else 979 errno = 0; 980 } 981 return fd; 982 } 983