Print this page
5433 at(1) doesn't properly handle being invoked from a path containing spaces
Reviewed by: Gary Mills <gary_mills@fastmail.fm>


  84         "       at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\
  85             "timespec\n"\
  86         "       at -l [-p project] [-q queuename] [at_job_id...]\n"\
  87         "       at -r at_job_id ...\n"
  88 
  89 #define FORMAT          "%a %b %e %H:%M:%S %Y"
  90 
  91 static int leap(int);
  92 static int atoi_for2(char *);
  93 static int check_queue(char *, int);
  94 static int list_jobs(int, char **, int, int);
  95 static int remove_jobs(int, char **, char *);
  96 static void usage(void);
  97 static void catch(int);
  98 static void copy(char *, FILE *, int);
  99 static void atime(struct tm *, struct tm *);
 100 static int not_this_project(char *);
 101 static char *mkjobname(time_t);
 102 static time_t parse_time(char *);
 103 static time_t gtime(struct tm *);

 104 void atabort(char *)__NORETURN;
 105 void yyerror(void);
 106 extern int yyparse(void);
 107 
 108 extern void     audit_at_delete(char *, char *, int);
 109 extern int      audit_at_create(char *, int);
 110 extern int      audit_cron_is_anc_name(char *);
 111 extern int      audit_cron_delete_anc_file(char *, char *);
 112 
 113 /*
 114  * Error in getdate(3G)
 115  */
 116 static char     *errlist[] = {
 117 /* 0 */         "",
 118 /* 1 */ "getdate: The DATEMSK environment variable is not set",
 119 /* 2 */ "getdate: Error on \"open\" of the template file",
 120 /* 3 */ "getdate: Error on \"stat\" of the template file",
 121 /* 4 */ "getdate: The template file is not a regular file",
 122 /* 5 */ "getdate: An error is encountered while reading the template",
 123 /* 6 */ "getdate: Malloc(3C) failed",


 529                  * We call isleap since leap() adds
 530                  * 1900 onto any value passed
 531                  */
 532 
 533         if (!leap(tptr->tm_year) && at.tm_mday == 29 && at.tm_mon == 1)
 534                 atabort("bad date - not a leap year");
 535 
 536         if ((leap(tptr->tm_year)) && tptr->tm_mon >= 2)
 537                 ++tv;
 538 
 539         for (i = 0; i < tptr->tm_mon; ++i)
 540                 tv += dmsize[i];
 541         tv += tptr->tm_mday - 1;
 542         tv = 24 * tv + tptr->tm_hour;
 543         tv = 60 * tv + tptr->tm_min;
 544         tv = 60 * tv + tptr->tm_sec;
 545         return (tv);
 546 }
 547 
 548 /*

















 549  * make job file from proto + stdin
 550  */
 551 static void
 552 copy(char *jobfile, FILE *inputfile, int when)
 553 {
 554         int c;
 555         FILE *pfp;
 556         char *shell;
 557         char    dirbuf[PATH_MAX + 1];
 558         char    line[LINE_MAX];
 559         char **ep;
 560         mode_t um;
 561         char *val;
 562         extern char **environ;
 563         uid_t realusr, effeusr;
 564         int ttyinput;
 565         int ulimit_flag = 0;
 566         struct rlimit rlp;
 567         struct project prj, *pprj;
 568         char pbuf[PROJECT_BUFSZ];


 616         } else {
 617                 /*
 618                  * Check if current user is a member of current project.
 619                  * This check is done here to avoid setproject() failure
 620                  * later when the job gets executed.  If current user does
 621                  * not belong to current project, user's default project
 622                  * will be used instead.  This is achieved by not specifying
 623                  * the project (": project: <project>\n") in the job file.
 624                  */
 625                 if ((user = getuser(getuid())) == NULL)
 626                         atabort(INVALIDUSER);
 627                 project = getprojid();
 628                 pprj = getprojbyid(project, &prj, pbuf, sizeof (pbuf));
 629                 if (pprj != NULL) {
 630                         if (inproj(user, pprj->pj_name, pbuf2, sizeof (pbuf2)))
 631                                 (void) printf(": project: %d\n", project);
 632                 }
 633         }
 634 
 635         for (ep = environ; *ep; ep++) {
 636                 if (strchr(*ep, '\'') != NULL)
 637                         continue;
 638                 if ((val = strchr(*ep, '=')) == NULL)
 639                         continue;
 640                 *val++ = '\0';
 641                 printf("export %s; %s='%s'\n", *ep, *ep, val);


 642                 *--val = '=';
 643         }
 644         if ((pfp = fopen(pname1, "r")) == NULL &&
 645             (pfp = fopen(pname, "r")) == NULL)
 646                 atabort("no prototype");
 647         /*
 648          * Put in a line to run the proper shell using the rest of
 649          * the file as input.  Note that 'exec'ing the shell will
 650          * cause sh() to leave a /tmp/sh### file around. (1053807)
 651          */
 652         printf("%s << '...the rest of this file is shell input'\n", shell);
 653 
 654         um = umask(0);
 655         while ((c = getc(pfp)) != EOF) {
 656                 if (c != '$')
 657                         putchar(c);
 658                 else switch (c =  getc(pfp)) {
 659                 case EOF:
 660                         goto out;
 661                 case 'd':
 662                         /*
 663                          * Must obtain current working directory as the user
 664                          */
 665 
 666                         dirbuf[0] = '\0';
 667                         realusr = getuid();
 668                         effeusr = geteuid();
 669                         /* change euid for getcwd */
 670                         if (seteuid(realusr) < 0) {
 671                                 atabort(CANTCHUID);
 672                         }
 673                         if (getcwd(dirbuf, sizeof (dirbuf)) == NULL) {
 674                                 atabort(
 675                                     "can't obtain current working directory");
 676                         }
 677                         /* change back afterwards */
 678                         if (seteuid(effeusr) < 0) {
 679                                 atabort(CANTCHUID);
 680                         }
 681                         printf("%s", dirbuf);
 682                         break;
 683                 case 'm':
 684                         printf("%o", um);
 685                         break;
 686                 case '<':
 687                         if (ulimit_flag) {
 688                                 if (getrlimit(RLIMIT_FSIZE, &rlp) == 0) {
 689                                         if (rlp.rlim_cur == RLIM_INFINITY)
 690                                                 printf("ulimit unlimited\n");
 691                                         else
 692                                                 printf("ulimit %lld\n",
 693                                                     rlp.rlim_cur / 512);
 694                                 }
 695                         }
 696                         /*
 697                          * fix for 1113572 - use fputs() so that a
 698                          * newline isn't appended to the one returned
 699                          * with fgets(); 1099381 - prompt for input.
 700                          */
 701                         while (fgets(line, LINE_MAX, inputfile) != NULL) {




  84         "       at [-c|-k|-s] [-m] [-f file] [-p project] [-q queuename] "\
  85             "timespec\n"\
  86         "       at -l [-p project] [-q queuename] [at_job_id...]\n"\
  87         "       at -r at_job_id ...\n"
  88 
  89 #define FORMAT          "%a %b %e %H:%M:%S %Y"
  90 
  91 static int leap(int);
  92 static int atoi_for2(char *);
  93 static int check_queue(char *, int);
  94 static int list_jobs(int, char **, int, int);
  95 static int remove_jobs(int, char **, char *);
  96 static void usage(void);
  97 static void catch(int);
  98 static void copy(char *, FILE *, int);
  99 static void atime(struct tm *, struct tm *);
 100 static int not_this_project(char *);
 101 static char *mkjobname(time_t);
 102 static time_t parse_time(char *);
 103 static time_t gtime(struct tm *);
 104 static void escapestr(const char *);
 105 void atabort(char *)__NORETURN;
 106 void yyerror(void);
 107 extern int yyparse(void);
 108 
 109 extern void     audit_at_delete(char *, char *, int);
 110 extern int      audit_at_create(char *, int);
 111 extern int      audit_cron_is_anc_name(char *);
 112 extern int      audit_cron_delete_anc_file(char *, char *);
 113 
 114 /*
 115  * Error in getdate(3G)
 116  */
 117 static char     *errlist[] = {
 118 /* 0 */         "",
 119 /* 1 */ "getdate: The DATEMSK environment variable is not set",
 120 /* 2 */ "getdate: Error on \"open\" of the template file",
 121 /* 3 */ "getdate: Error on \"stat\" of the template file",
 122 /* 4 */ "getdate: The template file is not a regular file",
 123 /* 5 */ "getdate: An error is encountered while reading the template",
 124 /* 6 */ "getdate: Malloc(3C) failed",


 530                  * We call isleap since leap() adds
 531                  * 1900 onto any value passed
 532                  */
 533 
 534         if (!leap(tptr->tm_year) && at.tm_mday == 29 && at.tm_mon == 1)
 535                 atabort("bad date - not a leap year");
 536 
 537         if ((leap(tptr->tm_year)) && tptr->tm_mon >= 2)
 538                 ++tv;
 539 
 540         for (i = 0; i < tptr->tm_mon; ++i)
 541                 tv += dmsize[i];
 542         tv += tptr->tm_mday - 1;
 543         tv = 24 * tv + tptr->tm_hour;
 544         tv = 60 * tv + tptr->tm_min;
 545         tv = 60 * tv + tptr->tm_sec;
 546         return (tv);
 547 }
 548 
 549 /*
 550  * Escape a string to be used inside the job shell script.
 551  */
 552 static void
 553 escapestr(const char *str)
 554 {
 555         char c;
 556         (void) putchar('\'');
 557         while ((c = *str++) != '\0') {
 558                 if (c != '\'')
 559                         (void) putchar(c);
 560                 else
 561                         (void) fputs("'\\''", stdout); /* ' -> '\'' */
 562         }
 563         (void) putchar('\'');
 564 }
 565 
 566 /*
 567  * make job file from proto + stdin
 568  */
 569 static void
 570 copy(char *jobfile, FILE *inputfile, int when)
 571 {
 572         int c;
 573         FILE *pfp;
 574         char *shell;
 575         char    dirbuf[PATH_MAX + 1];
 576         char    line[LINE_MAX];
 577         char **ep;
 578         mode_t um;
 579         char *val;
 580         extern char **environ;
 581         uid_t realusr, effeusr;
 582         int ttyinput;
 583         int ulimit_flag = 0;
 584         struct rlimit rlp;
 585         struct project prj, *pprj;
 586         char pbuf[PROJECT_BUFSZ];


 634         } else {
 635                 /*
 636                  * Check if current user is a member of current project.
 637                  * This check is done here to avoid setproject() failure
 638                  * later when the job gets executed.  If current user does
 639                  * not belong to current project, user's default project
 640                  * will be used instead.  This is achieved by not specifying
 641                  * the project (": project: <project>\n") in the job file.
 642                  */
 643                 if ((user = getuser(getuid())) == NULL)
 644                         atabort(INVALIDUSER);
 645                 project = getprojid();
 646                 pprj = getprojbyid(project, &prj, pbuf, sizeof (pbuf));
 647                 if (pprj != NULL) {
 648                         if (inproj(user, pprj->pj_name, pbuf2, sizeof (pbuf2)))
 649                                 (void) printf(": project: %d\n", project);
 650                 }
 651         }
 652 
 653         for (ep = environ; *ep; ep++) {


 654                 if ((val = strchr(*ep, '=')) == NULL)
 655                         continue;
 656                 *val++ = '\0';
 657                 (void) printf("export %s; %s=", *ep, *ep);
 658                 escapestr(val);
 659                 (void) putchar('\n');
 660                 *--val = '=';
 661         }
 662         if ((pfp = fopen(pname1, "r")) == NULL &&
 663             (pfp = fopen(pname, "r")) == NULL)
 664                 atabort("no prototype");
 665         /*
 666          * Put in a line to run the proper shell using the rest of
 667          * the file as input.  Note that 'exec'ing the shell will
 668          * cause sh() to leave a /tmp/sh### file around. (1053807)
 669          */
 670         printf("%s << '...the rest of this file is shell input'\n", shell);
 671 
 672         um = umask(0);
 673         while ((c = getc(pfp)) != EOF) {
 674                 if (c != '$')
 675                         putchar(c);
 676                 else switch (c =  getc(pfp)) {
 677                 case EOF:
 678                         goto out;
 679                 case 'd':
 680                         /*
 681                          * Must obtain current working directory as the user
 682                          */
 683 
 684                         dirbuf[0] = '\0';
 685                         realusr = getuid();
 686                         effeusr = geteuid();
 687                         /* change euid for getcwd */
 688                         if (seteuid(realusr) < 0) {
 689                                 atabort(CANTCHUID);
 690                         }
 691                         if (getcwd(dirbuf, sizeof (dirbuf)) == NULL) {
 692                                 atabort(
 693                                     "can't obtain current working directory");
 694                         }
 695                         /* change back afterwards */
 696                         if (seteuid(effeusr) < 0) {
 697                                 atabort(CANTCHUID);
 698                         }
 699                         escapestr(dirbuf);
 700                         break;
 701                 case 'm':
 702                         printf("%o", um);
 703                         break;
 704                 case '<':
 705                         if (ulimit_flag) {
 706                                 if (getrlimit(RLIMIT_FSIZE, &rlp) == 0) {
 707                                         if (rlp.rlim_cur == RLIM_INFINITY)
 708                                                 printf("ulimit unlimited\n");
 709                                         else
 710                                                 printf("ulimit %lld\n",
 711                                                     rlp.rlim_cur / 512);
 712                                 }
 713                         }
 714                         /*
 715                          * fix for 1113572 - use fputs() so that a
 716                          * newline isn't appended to the one returned
 717                          * with fgets(); 1099381 - prompt for input.
 718                          */
 719                         while (fgets(line, LINE_MAX, inputfile) != NULL) {