safefile.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:20k
源码类别:

Email客户端

开发平台:

Unix_Linux

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