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