int main(int argc, char *argv[]) { int opt; int params = 3; int ret; char **handle_args; char *progname; (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if (init_yes() < 0) { (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES), strerror(errno)); exit(BC_ERROR); } /* * retro-compatibility: installing the bootblock is the default * and there is no switch for it. */ do_install = B_TRUE; while ((opt = getopt(argc, argv, "dVMFfmneiu:")) != EOF) { switch (opt) { case 'm': write_mbr = B_TRUE; break; case 'n': nowrite = B_TRUE; break; case 'f': force_mbr = B_TRUE; break; case 'i': do_getinfo = B_TRUE; do_install = B_FALSE; params = 1; break; case 'V': verbose_dump = B_TRUE; break; case 'd': boot_debug = B_TRUE; break; case 'F': force_update = B_TRUE; break; case 'e': strip = B_TRUE; break; case 'M': do_mirror_bblk = B_TRUE; do_install = B_FALSE; params = 2; break; case 'u': do_version = B_TRUE; update_str = malloc(strlen(optarg) + 1); if (update_str == NULL) { (void) fprintf(stderr, gettext("Unable to " "allocate memory\n")); exit(BC_ERROR); } (void) strlcpy(update_str, optarg, strlen(optarg) + 1); break; default: /* fall through to process non-optional args */ break; } } /* check arguments */ if (argc != optind + params) { usage(argv[0]); exit(BC_ERROR); } /* * clean up options (and bail out if an unrecoverable combination is * requested. */ progname = argv[0]; check_options(progname); handle_args = argv + optind; if (nowrite) (void) fprintf(stdout, DRY_RUN); if (do_getinfo) { ret = handle_getinfo(progname, handle_args); } else if (do_mirror_bblk) { ret = handle_mirror(progname, handle_args); } else { ret = handle_install(progname, handle_args); } return (ret); }
int main(int argc, char **argv) { int c, r; int rflag = 0; int lflag = 0; int gflag = 0; int eflag = 0; int errflg = 0; char *pp; FILE *fp, *tmpfp; struct stat stbuf; struct passwd *pwp; time_t omodtime; char *editor; uid_t ruid; pid_t pid; int stat_loc; int ret; char real_login[UNAMESIZE]; int tmpfd = -1; pam_handle_t *pamh; int pam_error; char *buf; size_t buflen; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); if (init_yes() < 0) { (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES), strerror(errno)); exit(1); } while ((c = getopt(argc, argv, "eglr")) != EOF) switch (c) { case 'e': eflag++; break; case 'g': gflag++; break; case 'l': lflag++; break; case 'r': rflag++; break; case '?': errflg++; break; } if (eflag + lflag + rflag > 1) errflg++; if (gflag && !lflag) errflg++; argc -= optind; argv += optind; if (errflg || argc > 1) crabort(BADUSAGE); ruid = getuid(); if ((pwp = getpwuid(ruid)) == NULL) crabort(INVALIDUSER); if (strlcpy(real_login, pwp->pw_name, sizeof (real_login)) >= sizeof (real_login)) crabort(NAMETOOLONG); if ((eflag || lflag || rflag) && argc == 1) { if ((pwp = getpwnam(*argv)) == NULL) crabort(INVALIDUSER); if (!cron_admin(real_login)) { if (pwp->pw_uid != ruid) crabort(NOTROOT); else pp = getuser(ruid); } else pp = *argv++; } else { pp = getuser(ruid); } if (pp == NULL) { if (per_errno == 2) crabort(BADSHELL); else crabort(INVALIDUSER); } if (strlcpy(login, pp, sizeof (login)) >= sizeof (login)) crabort(NAMETOOLONG); if (!allowed(login, CRONALLOW, CRONDENY)) crabort(NOTALLOWED); /* Do account validation check */ pam_error = pam_start("cron", pp, NULL, &pamh); if (pam_error != PAM_SUCCESS) { crabort((char *)pam_strerror(pamh, pam_error)); } pam_error = pam_acct_mgmt(pamh, PAM_SILENT); if (pam_error != PAM_SUCCESS) { (void) fprintf(stderr, gettext("Warning - Invalid account: " "'%s' not allowed to execute cronjobs\n"), pp); } (void) pam_end(pamh, PAM_SUCCESS); /* check for unaudited shell */ if (audit_crontab_not_allowed(ruid, pp)) crabort(AUDITREJECT); cf = xmalloc(strlen(CRONDIR)+strlen(login)+2); strcat(strcat(strcpy(cf, CRONDIR), "/"), login); if (rflag) { r = unlink(cf); cron_sendmsg(DELETE, login, login, CRON); audit_crontab_delete(cf, r); exit(0); } if (lflag) { char sysconf[PATH_MAX]; if (gflag) { if (snprintf(sysconf, sizeof (sysconf), "%s/%s", SYSCRONDIR, login) < sizeof (sysconf) && (fp = fopen(sysconf, "r")) != NULL) { while (fgets(line, CTLINESIZE, fp) != NULL) fputs(line, stdout); fclose(fp); exit(0); } else { crabort(BADOPEN); } } else { if ((fp = fopen(cf, "r")) == NULL) crabort(BADOPEN); while (fgets(line, CTLINESIZE, fp) != NULL) fputs(line, stdout); fclose(fp); exit(0); } } if (eflag) { if ((fp = fopen(cf, "r")) == NULL) { if (errno != ENOENT) crabort(BADOPEN); } (void) strcpy(edtemp, "/tmp/crontabXXXXXX"); tmpfd = mkstemp(edtemp); if (fchown(tmpfd, ruid, -1) == -1) { (void) close(tmpfd); crabort("fchown of temporary file failed"); } (void) close(tmpfd); /* * Fork off a child with user's permissions, * to edit the crontab file */ if ((pid = fork()) == (pid_t)-1) crabort("fork failed"); if (pid == 0) { /* child process */ /* give up super-user privileges. */ setuid(ruid); if ((tmpfp = fopen(edtemp, "w")) == NULL) crabort("can't create temporary file"); if (fp != NULL) { /* * Copy user's crontab file to temporary file. */ while (fgets(line, CTLINESIZE, fp) != NULL) { fputs(line, tmpfp); if (ferror(tmpfp)) { fclose(fp); fclose(tmpfp); crabort("write error on" "temporary file"); } } if (ferror(fp)) { fclose(fp); fclose(tmpfp); crabort(BADREAD); } fclose(fp); } if (fclose(tmpfp) == EOF) crabort("write error on temporary file"); if (stat(edtemp, &stbuf) < 0) crabort("can't stat temporary file"); omodtime = stbuf.st_mtime; #ifdef _XPG_NOTDEFINED editor = getenv("VISUAL"); if (editor == NULL) { #endif editor = getenv("EDITOR"); if (editor == NULL) editor = VIPATH; #ifdef _XPG_NOTDEFINED } #endif buflen = strlen(editor) + strlen(edtemp) + 2; buf = xmalloc(buflen); (void) snprintf(buf, buflen, "%s %s", editor, edtemp); sleep(1); while (1) { ret = system(buf); /* sanity checks */ if ((tmpfp = fopen(edtemp, "r")) == NULL) crabort("can't open temporary file"); if (fstat(fileno(tmpfp), &stbuf) < 0) crabort("can't stat temporary file"); if (stbuf.st_size == 0) crabort("temporary file empty"); if (omodtime == stbuf.st_mtime) { (void) unlink(edtemp); fprintf(stderr, gettext( "The crontab file was not" " changed.\n")); exit(1); } if ((ret) && (errno != EINTR)) { /* * Some editors (like 'vi') can return * a non-zero exit status even though * everything is okay. Need to check. */ fprintf(stderr, gettext(ED_ERROR)); fflush(stderr); if (isatty(fileno(stdin))) { /* Interactive */ fprintf(stdout, gettext(ED_PROMPT), yesstr, nostr, nostr); fflush(stdout); if (yes()) { /* Edit again */ continue; } else { /* Dump changes */ (void) unlink(edtemp); exit(1); } } else { /* * Non-interactive, dump changes */ (void) unlink(edtemp); exit(1); } } exit(0); } /* while (1) */ } /* fix for 1125555 - ignore common signals while waiting */ (void) signal(SIGINT, SIG_IGN); (void) signal(SIGHUP, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); (void) signal(SIGTERM, SIG_IGN); wait(&stat_loc); if ((stat_loc & 0xFF00) != 0) exit(1); /* * unlink edtemp as 'ruid'. The file contents will be held * since we open the file descriptor 'tmpfp' before calling * unlink. */ if (((ret = seteuid(ruid)) < 0) || ((tmpfp = fopen(edtemp, "r")) == NULL) || (unlink(edtemp) == -1)) { fprintf(stderr, "crontab: %s: %s\n", edtemp, errmsg(errno)); if ((ret < 0) || (tmpfp == NULL)) (void) unlink(edtemp); exit(1); } else seteuid(0); copycron(tmpfp); } else { if (argc == 0) copycron(stdin); else if (seteuid(getuid()) != 0 || (fp = fopen(argv[0], "r")) == NULL) crabort(BADOPEN); else { seteuid(0); copycron(fp); } } cron_sendmsg(ADD, login, login, CRON); /* * if (per_errno == 2) * fprintf(stderr, gettext(WARNSHELL)); */ return (0); }
int main(int argc, char **argv) { int j; struct inserts *psave; int c; int initsize; char *cmdname, **initlist; char *arg; char *next; /* initialization */ blank = wctype("blank"); n_inserts = 0; psave = saveargv; (void) setlocale(LC_ALL, ""); #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ #endif (void) textdomain(TEXT_DOMAIN); if (init_yes() < 0) { ermsg(_(ERR_MSG_INIT_YES), strerror(errno)); exit(1); } parseargs(argc, argv); /* handling all of xargs arguments: */ while ((c = getopt(mac, mav, "0tpe:E:I:i:L:l:n:s:x")) != EOF) { switch (c) { case '0': ZERO = TRUE; break; case 't': /* -t: turn trace mode on */ TRACE = TRUE; break; case 'p': /* -p: turn on prompt mode. */ if ((PROMPT = open("/dev/tty", O_RDONLY)) == -1) { PERR("can't read from tty for -p"); } else { TRACE = TRUE; } break; case 'e': /* * -e[eofstr]: set/disable end-of-file. * N.B. that an argument *isn't* required here; but * parseargs forced an argument if not was given. The * forced argument is the default... */ LEOF = optarg; /* can be empty */ break; case 'E': /* * -E eofstr: change end-of-file string. * eofstr *is* required here, but can be empty: */ LEOF = optarg; break; case 'I': /* -I replstr: Insert mode. replstr *is* required. */ INSERT = PER_LINE = LEGAL = TRUE; N_ARGS = 0; INSPAT = optarg; if (*optarg == '\0') { ermsg(_("Option requires an argument: -%c\n"), c); } break; case 'i': /* * -i [replstr]: insert mode, with *optional* replstr. * N.B. that an argument *isn't* required here; if * it's not given, then the string INSPAT_STR will * be assumed. * * Since getopts(3C) doesn't handle the case of an * optional variable argument at all, we have to * parse this by hand: */ INSERT = PER_LINE = LEGAL = TRUE; N_ARGS = 0; if ((optarg != NULL) && (*optarg != '\0')) { INSPAT = optarg; } else { /* * here, there is no next argument. so * we reset INSPAT to the INSPAT_STR. * we *have* to do this, as -i/I may have * been given previously, and XCU4 requires * that only "the last one specified takes * effect". */ INSPAT = INSPAT_STR; } break; case 'L': /* * -L number: # of times cmd is executed * number *is* required here: */ PER_LINE = TRUE; N_ARGS = 0; INSERT = FALSE; if ((PER_LINE = atoi(optarg)) <= 0) { ermsg(_("#lines must be positive int: %s\n"), optarg); } break; case 'l': /* * -l [number]: # of times cmd is executed * N.B. that an argument *isn't* required here; if * it's not given, then 1 is assumed. * * parseargs handles the optional arg processing. */ PER_LINE = LEGAL = TRUE; /* initialization */ N_ARGS = 0; INSERT = FALSE; if ((optarg != NULL) && (*optarg != '\0')) { if ((PER_LINE = atoi(optarg)) <= 0) PER_LINE = 1; } break; case 'n': /* -n number: # stdin args */ /* * -n number: # stdin args. * number *is* required here: */ if ((N_ARGS = atoi(optarg)) <= 0) { ermsg(_("#args must be positive int: %s\n"), optarg); } else { LEGAL = DASHX || N_ARGS == 1; INSERT = PER_LINE = FALSE; } break; case 's': /* -s size: set max size of each arg list */ BUFLIM = atoi(optarg); if (BUFLIM > BUFSIZE || BUFLIM <= 0) { ermsg(_("0 < max-cmd-line-size <= %d: %s\n"), BUFSIZE, optarg); } break; case 'x': /* -x: terminate if args > size limit */ DASHX = LEGAL = TRUE; break; default: /* * bad argument. complain and get ready to die. */ usage(); exit(2); break; } } /* * if anything called ermsg(), something screwed up, so * we exit early. */ if (OK == FALSE) { usage(); exit(2); } /* * we're finished handling xargs's options, so now pick up * the command name (if any), and it's options. */ mac -= optind; /* dec arg count by what we've processed */ mav += optind; /* inc to current mav */ if (mac <= 0) { /* if there're no more args to process, */ cmdname = "/usr/bin/echo"; /* our default command */ *ARGV++ = addarg(cmdname); /* use the default cmd. */ } else { /* otherwise keep parsing rest of the string. */ /* * note that we can't use getopts(3C), and *must* parse * this by hand, as we don't know apriori what options the * command will take. */ cmdname = *mav; /* get the command name */ /* pick up the remaining args from the command line: */ while ((OK == TRUE) && (mac-- > 0)) { /* * while we haven't crapped out, and there's * work to do: */ if (INSERT && ! ERR) { if (strstr(*mav, INSPAT) != NULL) { if (++n_inserts > MAXINSERTS) { ermsg(_("too many args " "with %s\n"), INSPAT); ERR = TRUE; } psave->p_ARGV = ARGV; (psave++)->p_skel = *mav; } } *ARGV++ = addarg(*mav++); } } /* pick up args from standard input */ initlist = ARGV; initsize = linesize; lastarg[0] = '\0'; while (OK) { N_args = 0; N_lines = 0; ARGV = initlist; linesize = initsize; next = argbuf; while (MORE || (lastarg[0] != '\0')) { int l; if (*lastarg != '\0') { arg = strcpy(next, lastarg); *lastarg = '\0'; } else if ((arg = getarg(next)) == NULL) { break; } l = strlen(arg) + 1; linesize += l; next += l; /* Inserts are handled specially later. */ if ((n_inserts == 0) && (linesize >= BUFLIM)) { /* * Legal indicates hard fail if the list is * truncated due to size. So fail, or if we * cannot create any list because it would be * too big. */ if (LEGAL || N_args == 0) { EMSG(LIST2LONG); exit(2); /* NOTREACHED */ } /* * Otherwise just save argument for later. */ (void) strcpy(lastarg, arg); break; } *ARGV++ = arg; N_args++; if ((PER_LINE && N_lines >= PER_LINE) || (N_ARGS && (N_args) >= N_ARGS)) { break; } if ((ARGV - arglist) == MAXARGS) { break; } } *ARGV = NULL; if (N_args == 0) { /* Reached the end with no more work. */ exit(exitstat); } /* insert arg if requested */ if (!ERR && INSERT) { p_ibuf = ins_buf; ARGV--; j = ibufsize = 0; for (psave = saveargv; ++j <= n_inserts; ++psave) { addibuf(psave); if (ERR) break; } } *ARGV = NULL; if (n_inserts > 0) { /* * if we've done any insertions, re-calculate the * linesize. bomb out if we've exceeded our length. */ linesize = 0; for (ARGV = arglist; *ARGV != NULL; ARGV++) { linesize += strlen(*ARGV) + 1; } if (linesize >= BUFLIM) { EMSG(LIST2LONG); exit(2); /* NOTREACHED */ } } /* exec command */ if (!ERR) { if (!MORE && (PER_LINE && N_lines == 0 || N_ARGS && N_args == 0)) exit(exitstat); OK = TRUE; j = TRACE ? echoargs() : TRUE; if (j) { /* * for xcu4, all invocations of cmdname must * return 0, in order for us to return 0. * so if we have a non-zero status here, * quit immediately. */ exitstat |= lcall(cmdname, arglist); } } } if (OK) return (exitstat); /* * if exitstat was set, to match XCU4 complience, * return that value, otherwise, return 1. */ return (exitstat ? exitstat : 1); }