home *** CD-ROM | disk | FTP | other *** search
/ Nebula / nebula.bin / SourceCode / CronVixie2.1 / crontab.c < prev    next >
C/C++ Source or Header  |  1992-01-14  |  9KB  |  411 lines

  1. #if !defined(lint) && !defined(LINT)
  2. static char rcsid[] = "$Header: /private/Net/beauty/src/vixie-cron-2.1/RCS/crontab.c,v 2.2 90/07/18 00:23:56 vixie Exp Locker: irving $";
  3. #endif
  4.  
  5. /* Revision 1.5  87/05/02  17:33:22  paul
  6.  * pokecron?  (RCS file has the rest of the log)
  7.  * 
  8.  * Revision 1.5  87/05/02  17:33:22  paul
  9.  * baseline for mod.sources release
  10.  * 
  11.  * Revision 1.4  87/03/31  13:11:48  paul
  12.  * I won't say that rs@mirror gave me this idea but crontab uses getopt() now
  13.  * 
  14.  * Revision 1.3  87/03/30  23:43:48  paul
  15.  * another suggestion from rs@mirror:
  16.  *   use getpwuid(getuid)->pw_name instead of getenv("USER")
  17.  *   this is a boost to security...
  18.  * 
  19.  * Revision 1.2  87/02/11  17:40:12  paul
  20.  * changed command syntax to allow append and replace instead of append as
  21.  * default and no replace at all.
  22.  * 
  23.  * Revision 1.1  87/01/26  23:49:06  paul
  24.  * Initial revision
  25.  */
  26.  
  27. /* Copyright 1988,1990 by Paul Vixie
  28.  * All rights reserved
  29.  *
  30.  * Distribute freely, except: don't remove my name from the source or
  31.  * documentation (don't take credit for my work), mark your changes (don't
  32.  * get me blamed for your possible bugs), don't alter or remove this
  33.  * notice.  May be sold if buildable source is provided to buyer.  No
  34.  * warrantee of any kind, express or implied, is included with this
  35.  * software; use at your own risk, responsibility for damages (if any) to
  36.  * anyone resulting from the use of this software rests entirely with the
  37.  * user.
  38.  *
  39.  * Send bug reports, bug fixes, enhancements, requests, flames, etc., and
  40.  * I'll try to keep a version up to date.  I can be reached as follows:
  41.  * Paul Vixie, 329 Noe Street, San Francisco, CA, 94114, (415) 864-7013,
  42.  * paul@vixie.sf.ca.us || {hoptoad,pacbell,decwrl,crash}!vixie!paul
  43.  */
  44.  
  45.  
  46. #define    MAIN_PROGRAM
  47.  
  48.  
  49. #include "cron.h"
  50. #include <pwd.h>
  51. #include <errno.h>
  52. #include <sys/file.h>
  53. #if defined(BSD)
  54. # include <sys/time.h>
  55. #endif  /*BSD*/
  56.  
  57. extern    char    *sprintf();
  58.  
  59.  
  60. static int    Pid;
  61. static char    User[MAX_UNAME], RealUser[MAX_UNAME];
  62. static char    Filename[MAX_FNAME];
  63. static FILE    *NewCrontab;
  64. static int    CheckErrorCount;
  65. static enum    {opt_unknown, opt_list, opt_delete, opt_replace}
  66.         Option;
  67.  
  68. extern void    log_it();
  69.  
  70. #if DEBUGGING
  71. static char    *Options[] = {"???", "list", "delete", "replace"};
  72. #endif
  73.  
  74. static void
  75. usage()
  76. {
  77.     fprintf(stderr, "usage:  %s [-u user] ...\n", ProgramName);
  78.     fprintf(stderr, " ... -l         (list user's crontab)\n");
  79.     fprintf(stderr, " ... -d         (delete user's crontab)\n");
  80.     fprintf(stderr, " ... -r file    (replace user's crontab)\n");
  81.     exit(ERROR_EXIT);
  82. }
  83.  
  84.  
  85. main(argc, argv)
  86.     int    argc;
  87.     char    *argv[];
  88. {
  89.     static void    parse_args(), set_cron_uid(), set_cron_cwd(),
  90.         list_cmd(), delete_cmd(), replace_cmd();
  91.  
  92.     Pid = getpid();
  93.     ProgramName = argv[0];
  94. #if defined(BSD)
  95.     setlinebuf(stderr);
  96. #endif
  97.     parse_args(argc, argv);        /* sets many globals, opens a file */
  98.     set_cron_uid();
  99.     set_cron_cwd();
  100.     if (!allowed(User)) {
  101.         fprintf(stderr,
  102.             "You (%s) are not allowed to use this program (%s)\n",
  103.             User, ProgramName);
  104.         fprintf(stderr, "See crontab(1) for more information\n");
  105.         log_it(RealUser, Pid, "AUTH", "crontab command not allowed");
  106.         exit(ERROR_EXIT);
  107.     }
  108.     switch (Option)
  109.     {
  110.     case opt_list:        list_cmd();
  111.                 break;
  112.     case opt_delete:    delete_cmd();
  113.                 break;
  114.     case opt_replace:    replace_cmd();
  115.                 break;
  116.     }
  117. }
  118.     
  119.  
  120. static void
  121. parse_args(argc, argv)
  122.     int    argc;
  123.     char    *argv[];
  124. {
  125.     void        usage();
  126.     char        *getenv(), *strcpy();
  127.     int        getuid();
  128.     struct passwd    *getpwnam();
  129.     extern int    getopt(), optind;
  130.     extern char    *optarg;
  131.  
  132.     struct passwd    *pw;
  133.     int        argch;
  134.  
  135.     if (!(pw = getpwuid(getuid())))
  136.     {
  137.         fprintf(stderr, "%s: your UID isn't in the passwd file.\n",
  138.             ProgramName);
  139.         fprintf(stderr, "bailing out.\n");
  140.         exit(ERROR_EXIT);
  141.     }
  142.     strcpy(User, pw->pw_name);
  143.     strcpy(RealUser, User);
  144.     Filename[0] = '\0';
  145.     Option = opt_unknown;
  146.     while (EOF != (argch = getopt(argc, argv, "u:ldr:x:")))
  147.     {
  148.         switch (argch)
  149.         {
  150.         case 'x':
  151.             if (!set_debug_flags(optarg))
  152.                 usage();
  153.             break;
  154.         case 'u':
  155.             if (getuid() != ROOT_UID)
  156.             {
  157.                 fprintf(stderr,
  158.                     "must be privileged to use -u\n");
  159.                 exit(ERROR_EXIT);
  160.             }
  161.             if ((struct passwd *)NULL == getpwnam(optarg))
  162.             {
  163.                 fprintf(stderr, "%s:  user `%s' unknown\n",
  164.                     ProgramName, optarg);
  165.                 exit(ERROR_EXIT);
  166.             }
  167.             (void) strcpy(User, optarg);
  168.             break;
  169.         case 'l':
  170.             if (Option != opt_unknown)
  171.                 usage();
  172.             Option = opt_list;
  173.             break;
  174.         case 'd':
  175.             if (Option != opt_unknown)
  176.                 usage();
  177.             Option = opt_delete;
  178.             break;
  179.         case 'r':
  180.             if (Option != opt_unknown)
  181.                 usage();
  182.             Option = opt_replace;
  183.             (void) strcpy(Filename, optarg);
  184.             break;
  185.         default:
  186.             usage();
  187.         }
  188.     }
  189.  
  190.     endpwent();
  191.  
  192.     if (Option == opt_unknown || argv[optind] != NULL)
  193.         usage();
  194.  
  195.     if (Option == opt_replace) {
  196.         if (!Filename[0]) {
  197.             /* getopt(3) says this can't be true
  198.              * but I'm paranoid today.
  199.              */
  200.             fprintf(stderr, "filename must be given for -a or -r\n");
  201.             usage();
  202.         }
  203.         /* we have to open the file here because we're going to
  204.          * chdir(2) into /var/cron before we get around to
  205.          * reading the file.
  206.          */
  207.         if (!strcmp(Filename, "-")) {
  208.             NewCrontab = stdin;
  209.         } else {
  210.             if (!(NewCrontab = fopen(Filename, "r"))) {
  211.                 perror(Filename);
  212.                 exit(ERROR_EXIT);
  213.             }
  214.         }
  215.     }
  216.  
  217.     Debug(DMISC, ("user=%s, file=%s, option=%s\n",
  218.                     User, Filename, Options[(int)Option]))
  219. }
  220.  
  221.  
  222. static void
  223. list_cmd()
  224. {
  225.     extern    errno;
  226.     char    n[MAX_FNAME];
  227.     FILE    *f;
  228.     int    ch;
  229.  
  230.     log_it(RealUser, Pid, "LIST", User);
  231.     (void) sprintf(n, CRON_TAB(User));
  232.     if (!(f = fopen(n, "r")))
  233.     {
  234.         if (errno == ENOENT)
  235.             fprintf(stderr, "no crontab for %s\n", User);
  236.         else
  237.             perror(n);
  238.         exit(ERROR_EXIT);
  239.     }
  240.  
  241.     /* file is open. copy to stdout, close.
  242.      */
  243.     Set_LineNum(1)
  244.     while (EOF != (ch = get_char(f)))
  245.         putchar(ch);
  246.     fclose(f);
  247. }
  248.  
  249.  
  250. static void
  251. delete_cmd()
  252. {
  253.     extern    errno;
  254.     int    unlink();
  255.     static void    poke_daemon();
  256.     char    n[MAX_FNAME];
  257.  
  258.     log_it(RealUser, Pid, "DELETE", User);
  259.     (void) sprintf(n, CRON_TAB(User));
  260.     if (unlink(n))
  261.     {
  262.         if (errno == ENOENT)
  263.             fprintf(stderr, "no crontab for %s\n", User);
  264.         else
  265.             perror(n);
  266.         exit(ERROR_EXIT);
  267.     }
  268.     poke_daemon();
  269. }
  270.  
  271.  
  272. static void
  273. check_error(msg)
  274.     char    *msg;
  275. {
  276.     CheckErrorCount += 1;
  277.     fprintf(stderr, "\"%s\", line %d: %s\n", Filename, LineNumber, msg);
  278. }
  279.  
  280.  
  281. static void
  282. replace_cmd()
  283. {
  284.     char    *sprintf();
  285.     entry    *load_entry();
  286.     int    load_env();
  287.     int    unlink();
  288.     void    free_entry();
  289.     void    check_error();
  290.     static void    poke_daemon();
  291.     extern    errno;
  292.  
  293.     char    n[MAX_FNAME], envstr[MAX_ENVSTR], tn[MAX_FNAME];
  294.     FILE    *tmp;
  295.     int    ch;
  296.     entry    *e;
  297.     int    status;
  298.     time_t    now = time(NULL);
  299.  
  300.     (void) sprintf(n, "tmp.%d", Pid);
  301.     (void) sprintf(tn, CRON_TAB(n));
  302.     if (!(tmp = fopen(tn, "w"))) {
  303.         perror(tn);
  304.         exit(ERROR_EXIT);
  305.     }
  306.  
  307.     /* write a signature at the top of the file.  for brian.
  308.      */
  309.     fprintf(tmp, "# (%s installed on %-24.24s)\n", Filename, ctime(&now));
  310.     fprintf(tmp, "# (Cron version -- %s)\n", rcsid);
  311.  
  312.     /* copy the crontab to the tmp
  313.      */
  314.     Set_LineNum(1)
  315.     while (EOF != (ch = get_char(NewCrontab)))
  316.         putc(ch, tmp);
  317.     fclose(NewCrontab);
  318.     fflush(tmp);  rewind(tmp);
  319.  
  320.     if (ferror(tmp)) {
  321.         fprintf("%s: error while writing new crontab to %s\n",
  322.             ProgramName, tn);
  323.         fclose(tmp);  unlink(tn);
  324.         exit(ERROR_EXIT);
  325.     }
  326.  
  327.     /* check the syntax of the file being installed.
  328.      */
  329.  
  330.     /* BUG: was reporting errors after the EOF if there were any errors
  331.      * in the file proper -- kludged it by stopping after first error.
  332.      *        vix 31mar87
  333.      */
  334.     CheckErrorCount = 0;
  335.     while (!CheckErrorCount && (status = load_env(envstr, tmp)) >= OK)
  336.     {
  337.         if (status == FALSE)
  338.         {
  339.             if (NULL != (e = load_entry(NewCrontab, check_error)))
  340.                 free((char *) e);
  341.         }
  342.     }
  343.  
  344.     if (CheckErrorCount != 0)
  345.     {
  346.         fprintf(stderr, "errors in crontab file, can't install.\n");
  347.         fclose(tmp);  unlink(tn);
  348.         exit(ERROR_EXIT);
  349.     }
  350.  
  351.     if (fchown(fileno(tmp), ROOT_UID, -1) < OK)
  352.     {
  353.         perror("chown");
  354.         fclose(tmp);  unlink(tn);
  355.         exit(ERROR_EXIT);
  356.     }
  357.  
  358.     if (fchmod(fileno(tmp), 0600) < OK)
  359.     {
  360.         perror("chown");
  361.         fclose(tmp);  unlink(tn);
  362.         exit(ERROR_EXIT);
  363.     }
  364.  
  365.     if (fclose(tmp) == EOF) {
  366.         perror("fclose");
  367.         unlink(tn);
  368.         exit(ERROR_EXIT);
  369.     }
  370.  
  371.     (void) sprintf(n, CRON_TAB(User));
  372.     if (rename(tn, n))
  373.     {
  374.         fprintf(stderr, "%s: error renaming %s to %s\n",
  375.             ProgramName, tn, n);
  376.         perror("rename");
  377.         unlink(tn);
  378.         exit(ERROR_EXIT);
  379.     }
  380.     log_it(RealUser, Pid, "REPLACE", User);
  381.  
  382.     poke_daemon();
  383. }
  384.  
  385.  
  386. static void
  387. poke_daemon()
  388. {
  389. #if defined(BSD)
  390.     struct timeval tvs[2];
  391.     struct timezone tz;
  392.  
  393.     (void) gettimeofday(&tvs[0], &tz);
  394.     tvs[1] = tvs[0];
  395.     if (utimes(SPOOL_DIR, tvs) < OK)
  396.     {
  397.         fprintf(stderr, "crontab: can't update mtime on spooldir\n");
  398.         perror(SPOOL_DIR);
  399.         return;
  400.     }
  401. #endif  /*BSD*/
  402. #if defined(ATT)
  403.     if (utime(SPOOL_DIR, NULL) < OK)
  404.     {
  405.         fprintf(stderr, "crontab: can't update mtime on spooldir\n");
  406.         perror(SPOOL_DIR);
  407.         return;
  408.     }
  409. #endif  /*ATT*/
  410. }
  411.