1: /* Copyright 1988,1990,1993,1994 by Paul Vixie
   2:  * All rights reserved
   3:  *
   4:  * Distribute freely, except: don't remove my name from the source or
   5:  * documentation (don't take credit for my work), mark your changes (don't
   6:  * get me blamed for your possible bugs), don't alter or remove this
   7:  * notice.  May be sold if buildable source is provided to buyer.  No
   8:  * warrantee of any kind, express or implied, is included with this
   9:  * software; use at your own risk, responsibility for damages (if any) to
  10:  * anyone resulting from the use of this software rests entirely with the
  11:  * user.
  12:  *
  13:  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  14:  * I'll try to keep a version up to date.  I can be reached as follows:
  15:  * Paul Vixie          <paul@vix.com>          uunet!decwrl!vixie!paul
  16:  */
  17: 
  18: #if !defined(lint) && !defined(LINT)
  19: static char rcsid[] = "$Id: misc.c,v 2.9 1994/01/15 20:43:43 vixie Exp $";
  20: #endif
  21: 
  22: /* vix 26jan87 [RCS has the rest of the log]
  23:  * vix 30dec86 [written]
  24:  */
  25: 
  26: 
  27: #include "cron.h"
  28: #include <sys/time.h>
  29: #include <sys/file.h>
  30: #include <sys/stat.h>
  31: #include <errno.h>
  32: #include <string.h>
  33: #include <fcntl.h>
  34: #if defined(SYSLOG)
  35: # include <syslog.h>
  36: #endif
  37: 
  38: 
  39: #if defined(LOG_DAEMON) && !defined(LOG_CRON)
  40: #define LOG_CRON LOG_DAEMON
  41: #endif
  42: 
  43: static int      LogFD = ERR;
  44: 
  45: int
  46: strcmp_until(left, right, until)
  47:     register char   *left;
  48:     register char   *right;
  49:     int until;
  50: {
  51:     register int    diff;
  52: 
  53:     while (*left && *left != until && *left == *right) {
  54:         left++;
  55:         right++;
  56:     }
  57: 
  58:     if ((*left=='\0' || *left == until) &&
  59:         (*right=='\0' || *right == until)) {
  60:         diff = 0;
  61:     } else {
  62:         diff = *left - *right;
  63:     }
  64: 
  65:     return diff;
  66: }
  67: 
  68: 
  69: /* strdtb(s) - delete trailing blanks in string 's' and return new length
  70:  */
  71: int
  72: strdtb(s)
  73:     register char   *s;
  74: {
  75:     register char   *x = s;
  76: 
  77:     /* scan forward to the null
  78: 	 */
  79:     while (*x)
  80:         x++;
  81: 
  82:     /* scan backward to either the first character before the string,
  83: 	 * or the last non-blank in the string, whichever comes first.
  84: 	 */
  85:     do  {x--;}
  86:     while (x >= s && isspace(*x));
  87: 
  88:     /* one character beyond where we stopped above is where the null
  89: 	 * goes.
  90: 	 */
  91:     *++x = '\0';
  92: 
  93:     /* the difference between the position of the null character and
  94: 	 * the position of the first character of the string is the length.
  95: 	 */
  96:     return x - s;
  97: }
  98: 
  99: 
 100: int
 101: set_debug_flags(flags)
 102:     char    *flags;
 103: {
 104:     /* debug flags are of the form    flag[,flag ...]
 105: 	 *
 106: 	 * if an error occurs, print a message to stdout and return FALSE.
 107: 	 * otherwise return TRUE after setting ERROR_FLAGS.
 108: 	 */
 109: 
 110: #if !DEBUGGING
 111: 
 112:     printf("this program was compiled without debugging enabled\n");
 113:     return FALSE;
 114: 
 115: #else /* DEBUGGING */
 116: 
 117:     register char   *pc = flags;
 118: 
 119:     DebugFlags = 0;
 120: 
 121:     while (*pc) {
 122:         char    **test;
 123:         int mask;
 124: 
 125:         /* try to find debug flag name in our list.
 126: 		 */
 127:         for (   test = DebugFlagNames, mask = 1;
 128:             *test && strcmp_until(*test, pc, ',');
 129:             test++, mask <<= 1
 130:             )
 131:             ;
 132: 
 133:         if (!*test) {
 134:             fprintf(stderr,
 135:                 "unrecognized debug flag <%s> <%s>\n",
 136:                 flags, pc);
 137:             return FALSE;
 138:         }
 139: 
 140:         DebugFlags |= mask;
 141: 
 142:         /* skip to the next flag
 143: 		 */
 144:         while (*pc && *pc != ',')
 145:             pc++;
 146:         if (*pc == ',')
 147:             pc++;
 148:     }
 149: 
 150:     if (DebugFlags) {
 151:         int flag;
 152: 
 153:         fprintf(stderr, "debug flags enabled:");
 154: 
 155:         for (flag = 0;  DebugFlagNames[flag];  flag++)
 156:             if (DebugFlags & (1 << flag))
 157:                 fprintf(stderr, " %s", DebugFlagNames[flag]);
 158:         fprintf(stderr, "\n");
 159:     }
 160: 
 161:     return TRUE;
 162: 
 163: #endif /* DEBUGGING */
 164: }
 165: 
 166: 
 167: void
 168: set_cron_uid()
 169: {
 170:     if (seteuid(ROOT_UID) < OK) {
 171:         perror("seteuid");
 172:         exit(ERROR_EXIT);
 173:     }
 174: }
 175: 
 176: 
 177: void
 178: set_cron_cwd()
 179: {
 180:     struct stat sb;
 181: 
 182:     /* first check for CRONDIR ("/var/cron" or some such)
 183: 	 */
 184:     if (stat(CRONDIR, &sb) < OK && errno == ENOENT) {
 185:         perror(CRONDIR);
 186:         if (OK == mkdir(CRONDIR, 0700)) {
 187:             fprintf(stderr, "%s: created\n", CRONDIR);
 188:             stat(CRONDIR, &sb);
 189:         } else {
 190:             fprintf(stderr, "%s: ", CRONDIR);
 191:             perror("mkdir");
 192:             exit(ERROR_EXIT);
 193:         }
 194:     }
 195:     if (!(sb.st_mode & S_IFDIR)) {
 196:         fprintf(stderr, "'%s' is not a directory, bailing out.\n",
 197:             CRONDIR);
 198:         exit(ERROR_EXIT);
 199:     }
 200:     if (chdir(CRONDIR) < OK) {
 201:         fprintf(stderr, "cannot chdir(%s), bailing out.\n", CRONDIR);
 202:         perror(CRONDIR);
 203:         exit(ERROR_EXIT);
 204:     }
 205: 
 206:     /* CRONDIR okay (now==CWD), now look at SPOOL_DIR ("tabs" or some such)
 207: 	 */
 208:     if (stat(SPOOL_DIR, &sb) < OK && errno == ENOENT) {
 209:         perror(SPOOL_DIR);
 210:         if (OK == mkdir(SPOOL_DIR, 0700)) {
 211:             fprintf(stderr, "%s: created\n", SPOOL_DIR);
 212:             stat(SPOOL_DIR, &sb);
 213:         } else {
 214:             fprintf(stderr, "%s: ", SPOOL_DIR);
 215:             perror("mkdir");
 216:             exit(ERROR_EXIT);
 217:         }
 218:     }
 219:     if (!(sb.st_mode & S_IFDIR)) {
 220:         fprintf(stderr, "'%s' is not a directory, bailing out.\n",
 221:             SPOOL_DIR);
 222:         exit(ERROR_EXIT);
 223:     }
 224: }
 225: 
 226: 
 227: /* acquire_daemonlock() - write our PID into /etc/cron.pid, unless
 228:  *	another daemon is already running, which we detect here.
 229:  *
 230:  * note: main() calls us twice; once before forking, once after.
 231:  *	we maintain static storage of the file pointer so that we
 232:  *	can rewrite our PID into the PIDFILE after the fork.
 233:  *
 234:  * it would be great if fflush() disassociated the file buffer.
 235:  */
 236: void
 237: acquire_daemonlock(closeflag)
 238:     int closeflag;
 239: {
 240:     static  FILE    *fp = NULL;
 241: 
 242:     if (closeflag && fp) {
 243:         fclose(fp);
 244:         fp = NULL;
 245:         return;
 246:     }
 247: 
 248:     if (!fp) {
 249:         char    pidfile[MAX_FNAME];
 250:         char    buf[MAX_TEMPSTR];
 251:         int fd, otherpid;
 252: 
 253:         (void) sprintf(pidfile, PIDFILE, PIDDIR);
 254:         if ((-1 == (fd = open(pidfile, O_RDWR|O_CREAT, 0644)))
 255:             || (NULL == (fp = fdopen(fd, "r+")))
 256:             ) {
 257:             sprintf(buf, "can't open or create %s: %s",
 258:                 pidfile, strerror(errno));
 259:             fprintf(stderr, "%s: %s\n", ProgramName, buf);
 260:             log_it("CRON", getpid(), "DEATH", buf);
 261:             exit(ERROR_EXIT);
 262:         }
 263: 
 264:         if (flock(fd, LOCK_EX|LOCK_NB) < OK) {
 265:             int save_errno = errno;
 266: 
 267:             fscanf(fp, "%d", &otherpid);
 268:             sprintf(buf, "can't lock %s, otherpid may be %d: %s",
 269:                 pidfile, otherpid, strerror(save_errno));
 270:             fprintf(stderr, "%s: %s\n", ProgramName, buf);
 271:             log_it("CRON", getpid(), "DEATH", buf);
 272:             exit(ERROR_EXIT);
 273:         }
 274: 
 275:         (void) fcntl(fd, F_SETFD, 1);
 276:     }
 277: 
 278:     rewind(fp);
 279:     fprintf(fp, "%d\n", getpid());
 280:     fflush(fp);
 281:     (void) ftruncate(fileno(fp), ftell(fp));
 282: 
 283:     /* abandon fd and fp even though the file is open. we need to
 284: 	 * keep it open and locked, but we don't need the handles elsewhere.
 285: 	 */
 286: }
 287: 
 288: /* get_char(file) : like getc() but increment LineNumber on newlines
 289:  */
 290: int
 291: get_char(file)
 292:     register FILE   *file;
 293: {
 294:     register int    ch;
 295: 
 296:     ch = getc(file);
 297:     if (ch == '\n')
 298:         Set_LineNum(LineNumber + 1)
 299:     return ch;
 300: }
 301: 
 302: 
 303: /* unget_char(ch, file) : like ungetc but do LineNumber processing
 304:  */
 305: void
 306: unget_char(ch, file)
 307:     register int    ch;
 308:     register FILE   *file;
 309: {
 310:     ungetc(ch, file);
 311:     if (ch == '\n')
 312:         Set_LineNum(LineNumber - 1)
 313: }
 314: 
 315: 
 316: /* get_string(str, max, file, termstr) : like fgets() but
 317:  *		(1) has terminator string which should include \n
 318:  *		(2) will always leave room for the null
 319:  *		(3) uses get_char() so LineNumber will be accurate
 320:  *		(4) returns EOF or terminating character, whichever
 321:  */
 322: int
 323: get_string(string, size, file, terms)
 324:     register char   *string;
 325:     int size;
 326:     FILE    *file;
 327:     char    *terms;
 328: {
 329:     register int    ch;
 330: 
 331:     while (EOF != (ch = get_char(file)) && !strchr(terms, ch)) {
 332:         if (size > 1) {
 333:             *string++ = (char) ch;
 334:             size--;
 335:         }
 336:     }
 337: 
 338:     if (size > 0)
 339:         *string = '\0';
 340: 
 341:     return ch;
 342: }
 343: 
 344: 
 345: /* skip_comments(file) : read past comment (if any)
 346:  */
 347: void
 348: skip_comments(file)
 349:     register FILE   *file;
 350: {
 351:     register int    ch;
 352: 
 353:     while (EOF != (ch = get_char(file))) {
 354:         /* ch is now the first character of a line.
 355: 		 */
 356: 
 357:         while (ch == ' ' || ch == '\t')
 358:             ch = get_char(file);
 359: 
 360:         if (ch == EOF)
 361:             break;
 362: 
 363:         /* ch is now the first non-blank character of a line.
 364: 		 */
 365: 
 366:         if (ch != '\n' && ch != '#')
 367:             break;
 368: 
 369:         /* ch must be a newline or comment as first non-blank
 370: 		 * character on a line.
 371: 		 */
 372: 
 373:         while (ch != '\n' && ch != EOF)
 374:             ch = get_char(file);
 375: 
 376:         /* ch is now the newline of a line which we're going to
 377: 		 * ignore.
 378: 		 */
 379:     }
 380:     if (ch != EOF)
 381:         unget_char(ch, file);
 382: }
 383: 
 384: 
 385: /* int in_file(char *string, FILE *file)
 386:  *	return TRUE if one of the lines in file matches string exactly,
 387:  *	FALSE otherwise.
 388:  */
 389: static int
 390: in_file(string, file)
 391:     char *string;
 392:     FILE *file;
 393: {
 394:     char line[MAX_TEMPSTR];
 395: 
 396:     rewind(file);
 397:     while (fgets(line, MAX_TEMPSTR, file)) {
 398:         if (line[0] != '\0')
 399:             line[strlen(line)-1] = '\0';
 400:         if (0 == strcmp(line, string))
 401:             return TRUE;
 402:     }
 403:     return FALSE;
 404: }
 405: 
 406: 
 407: /* int allowed(char *username)
 408:  *	returns TRUE if (ALLOW_FILE exists and user is listed)
 409:  *	or (DENY_FILE exists and user is NOT listed)
 410:  *	or (neither file exists but user=="root" so it's okay)
 411:  */
 412: int
 413: allowed(username)
 414:     char *username;
 415: {
 416:     static int  init = FALSE;
 417:     static FILE *allow, *deny;
 418: 
 419:     if (!init) {
 420:         init = TRUE;
 421: #if defined(ALLOW_FILE) && defined(DENY_FILE)
 422:         allow = fopen(ALLOW_FILE, "r");
 423:         deny = fopen(DENY_FILE, "r");
 424:         Debug(DMISC, ("allow/deny enabled, %d/%d\n", !!allow, !!deny))
 425: #else
 426:         allow = NULL;
 427:         deny = NULL;
 428: #endif
 429:     }
 430: 
 431:     if (allow)
 432:         return (in_file(username, allow));
 433:     if (deny)
 434:         return (!in_file(username, deny));
 435: 
 436: #if defined(ALLOW_ONLY_ROOT)
 437:     return (strcmp(username, ROOT_USER) == 0);
 438: #else
 439:     return TRUE;
 440: #endif
 441: }
 442: 
 443: 
 444: void
 445: log_it(username, xpid, event, detail)
 446:     char    *username;
 447:     int xpid;
 448:     char    *event;
 449:     char    *detail;
 450: {
 451:     PID_T           pid = xpid;
 452: #if defined(LOG_FILE)
 453:     char            *msg;
 454:     TIME_T          now = time((TIME_T) 0);
 455:     register struct tm  *t = localtime(&now);
 456: #endif /*LOG_FILE*/
 457: 
 458: #if defined(SYSLOG)
 459:     static int      syslog_open = 0;
 460: #endif
 461: 
 462: #if defined(LOG_FILE)
 463:     /* we assume that MAX_TEMPSTR will hold the date, time, &punctuation.
 464: 	 */
 465:     msg = (char *)malloc(strlen(username)
 466:              + strlen(event)
 467:              + strlen(detail)
 468:              + MAX_TEMPSTR);
 469: 
 470:     if (LogFD < OK) {
 471:         LogFD = open(LOG_FILE, O_WRONLY|O_APPEND|O_CREAT, 0600);
 472:         if (LogFD < OK) {
 473:             fprintf(stderr, "%s: can't open log file\n",
 474:                 ProgramName);
 475:             perror(LOG_FILE);
 476:         } else {
 477:             (void) fcntl(LogFD, F_SETFD, 1);
 478:         }
 479:     }
 480: 
 481:     /* we have to sprintf() it because fprintf() doesn't always write
 482: 	 * everything out in one chunk and this has to be atomically appended
 483: 	 * to the log file.
 484: 	 */
 485:     sprintf(msg, "%s (%02d/%02d-%02d:%02d:%02d-%d) %s (%s)\n",
 486:         username,
 487:         t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec, pid,
 488:         event, detail);
 489: 
 490:     /* we have to run strlen() because sprintf() returns (char*) on old BSD
 491: 	 */
 492:     if (LogFD < OK || write(LogFD, msg, strlen(msg)) < OK) {
 493:         if (LogFD >= OK)
 494:             perror(LOG_FILE);
 495:         fprintf(stderr, "%s: can't write to log file\n", ProgramName);
 496:         write(STDERR, msg, strlen(msg));
 497:     }
 498: 
 499:     free(msg);
 500: #endif /*LOG_FILE*/
 501: 
 502: #if defined(SYSLOG)
 503:     if (!syslog_open) {
 504:         /* we don't use LOG_PID since the pid passed to us by
 505: 		 * our client may not be our own.  therefore we want to
 506: 		 * print the pid ourselves.
 507: 		 */
 508:         openlog(ProgramName, LOG_PID, LOG_CRON);
 509:         syslog_open = TRUE;     /* assume openlog success */
 510:     }
 511: 
 512:     syslog(LOG_INFO, "(%s) %s (%s)\n", username, event, detail);
 513: 
 514: #endif /*SYSLOG*/
 515: 
 516: #if DEBUGGING
 517:     if (DebugFlags) {
 518:         fprintf(stderr, "log_it: (%s %d) %s (%s)\n",
 519:             username, pid, event, detail);
 520:     }
 521: #endif
 522: }
 523: 
 524: 
 525: void
 526: log_close() {
 527:     if (LogFD != ERR) {
 528:         close(LogFD);
 529:         LogFD = ERR;
 530:     }
 531: }
 532: 
 533: 
 534: /* two warnings:
 535:  *	(1) this routine is fairly slow
 536:  *	(2) it returns a pointer to static storage
 537:  */
 538: char *
 539: first_word(s, t)
 540:     register char *s;   /* string we want the first word of */
 541:     char *t;        /* terminators, implicitly including \0 */
 542: {
 543:     static char retbuf[2][MAX_TEMPSTR + 1]; /* sure wish C had GC */
 544:     static int retsel = 0;
 545:     register char *rb, *rp;
 546: 
 547:     /* select a return buffer */
 548:     retsel = 1-retsel;
 549:     rb = &retbuf[retsel][0];
 550:     rp = rb;
 551: 
 552:     /* skip any leading terminators */
 553:     while (*s && (NULL != strchr(t, *s))) {
 554:         s++;
 555:     }
 556: 
 557:     /* copy until next terminator or full buffer */
 558:     while (*s && (NULL == strchr(t, *s)) && (rp < &rb[MAX_TEMPSTR])) {
 559:         *rp++ = *s++;
 560:     }
 561: 
 562:     /* finish the return-string and return it */
 563:     *rp = '\0';
 564:     return rb;
 565: }
 566: 
 567: 
 568: /* warning:
 569:  *	heavily ascii-dependent.
 570:  */
 571: void
 572: mkprint(dst, src, len)
 573:     register char *dst;
 574:     register unsigned char *src;
 575:     register int len;
 576: {
 577:     while (len-- > 0)
 578:     {
 579:         register unsigned char ch = *src++;
 580: 
 581:         if (ch < ' ') {         /* control character */
 582:             *dst++ = '^';
 583:             *dst++ = ch + '@';
 584:         } else if (ch < 0177) {     /* printable */
 585:             *dst++ = ch;
 586:         } else if (ch == 0177) {    /* delete/rubout */
 587:             *dst++ = '^';
 588:             *dst++ = '?';
 589:         } else {            /* parity character */
 590:             sprintf(dst, "\\%03o", ch);
 591:             dst += 4;
 592:         }
 593:     }
 594:     *dst = '\0';
 595: }
 596: 
 597: 
 598: /* warning:
 599:  *	returns a pointer to malloc'd storage, you must call free yourself.
 600:  */
 601: char *
 602: mkprints(src, len)
 603:     unsigned char *src;
 604:     unsigned int len;
 605: {
 606:     register char *dst = (char *)malloc(len*4 + 1);
 607: 
 608:     mkprint(dst, src, len);
 609: 
 610:     return dst;
 611: }
 612: 
 613: 
 614: #ifdef MAIL_DATE
 615: /* Sat, 27 Feb 93 11:44:51 CST
 616:  * 123456789012345678901234567
 617:  */
 618: char *
 619: arpadate(clock)
 620:     time_t *clock;
 621: {
 622:     time_t t = clock ?*clock :time(0L);
 623:     struct tm *tm = localtime(&t);
 624:     static char ret[30];    /* zone name might be >3 chars */
 625: 
 626:     (void) sprintf(ret, "%s, %2d %s %2d %02d:%02d:%02d %s",
 627:                DowNames[tm->tm_wday],
 628:                tm->tm_mday,
 629:                MonthNames[tm->tm_mon],
 630:                tm->tm_year,
 631:                tm->tm_hour,
 632:                tm->tm_min,
 633:                tm->tm_sec,
 634:                TZONE(*tm));
 635:     return ret;
 636: }
 637: #endif /*MAIL_DATE*/
 638: 
 639: static int save_euid;
 640: int swap_uids()
 641:     {
 642:     save_euid = geteuid();
 643:     return(seteuid(getuid()));
 644:     }
 645: 
 646: int swap_uids_back()
 647:     {
 648:     return(seteuid(save_euid));
 649:     }

Defined functions

acquire_daemonlock defined in line 236; never used
allowed defined in line 412; never used
arpadate defined in line 618; never used
first_word defined in line 538; never used
get_char defined in line 290; used 4 times
get_string defined in line 322; never used
in_file defined in line 389; used 2 times
log_close defined in line 525; never used
log_it defined in line 444; used 2 times
mkprint defined in line 571; used 1 times
mkprints defined in line 601; never used
set_cron_cwd defined in line 177; never used
set_cron_uid defined in line 167; never used
set_debug_flags defined in line 100; never used
skip_comments defined in line 347; never used
strcmp_until defined in line 45; used 1 times
strdtb defined in line 71; never used
swap_uids defined in line 640; never used
swap_uids_back defined in line 646; used 1 times
unget_char defined in line 305; used 1 times

Defined variables

LogFD defined in line 43; used 10 times
rcsid defined in line 19; never used
save_euid defined in line 639; used 2 times

Defined macros

LOG_CRON defined in line 40; used 2 times
Last modified: 1999-06-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4838
Valid CSS Valid XHTML 1.0 Strict