示例#1
0
文件: job.c 项目: colmsjo/batches
void
become_user(struct cl_t *cl, struct passwd *pas, char *home)
/* Become the user who owns the job: change privileges, check PAM authorization,
 * and change dir to HOME. */
{

#ifndef RUN_NON_PRIVILEGED
    if (pas == NULL)
        die("become_user() called with a NULL struct passwd");

    /* Change running state to the user in question */
    if (initgroups(pas->pw_name, pas->pw_gid) < 0)
        die_e("initgroups failed: %s", pas->pw_name);

    if (setgid(pas->pw_gid) < 0)
        die("setgid failed: %s %d", pas->pw_name, pas->pw_gid);

    if (setuid(pas->pw_uid) < 0)
        die("setuid failed: %s %d", pas->pw_name, pas->pw_uid);
#endif                          /* not RUN_NON_PRIVILEGED */

    /* make sure HOME is defined and change dir to it */
    if (chdir(home) != 0) {
        error_e("Could not chdir to HOME dir '%s'. Trying to chdir to '/'.",
                home);
        if (chdir("/") < 0)
            die_e("Could not chdir to HOME dir /");
    }

}
示例#2
0
int
install_stdin(void)
    /* install what we get through stdin */
{
    int tmp_fd = 0;
    FILE *tmp_file = NULL;
    char *tmp_str = NULL;
    int c;
    short return_val = EXIT_OK;
	    	    
    tmp_fd = temp_file(&tmp_str);
    
    if( (tmp_file = fdopen(tmp_fd, "w")) == NULL )
	die_e("Could not fdopen file %s", tmp_str);

    while ( (c = getc(stdin)) != EOF )
	putc(c, tmp_file);

    fclose(tmp_file);
    close(tmp_fd);

    if ( make_file(tmp_str) == ERR )
	goto exiterr;
    else
	goto exit;

  exiterr:
	return_val = EXIT_ERR;    
  exit:
    if ( remove(tmp_str) != 0 )
	error_e("Could not remove %s", tmp_str);
    free(tmp_str);
    return return_val;

}
示例#3
0
void
list_file(char *file)
{
    FILE *f = NULL;
    int c;

    explain("listing %s's fcrontab", user);

    if ( (f = fopen(file, "r")) == NULL ) {
	if ( errno == ENOENT ) {
	    explain("user %s has no fcrontab.", user);
	    return ;
	}
	else
	    die_e("User %s could not read file \"%s\"", user, file);
    }
    else {

	while ( (c = getc(f)) != EOF )
	    putchar(c);

	fclose(f);

    }

}
示例#4
0
文件: job.c 项目: colmsjo/batches
void
die_mail_pame(cl_t * cl, int pamerrno, struct passwd *pas, char *str,
              env_list_t * env)
/* log an error in syslog, mail user if necessary, and die */
{
    char buf[MAX_MSG];

    snprintf(buf, sizeof(buf), "%s for user '%s'", str, pas->pw_name);

    if (is_mail(cl->cl_option)) {
        char **envp = env_list_export_envp(env);
        FILE *mailf =
            create_mail(cl, "Could not run fcron job", NULL, NULL, envp);

        /* print the error in both syslog and a file, in order to mail it to user */
        if (dup2(fileno(mailf), 1) != 1 || dup2(1, 2) != 2)
            die_e("dup2() error");      /* dup2 also clears close-on-exec flag */

        foreground = 1;
        error_pame(pamh, pamerrno, buf, cl->cl_shell);
        error("Job '%s' has *not* run.", cl->cl_shell);
        foreground = 0;

        pam_end(pamh, pamerrno);

        become_user(cl, pas, "/");

        launch_mailer(cl, mailf, envp);
        /* launch_mailer() does not return : we never get here */
    }
    else
        die_pame(pamh, pamerrno, buf, cl->cl_shell);
}
示例#5
0
文件: job.c 项目: colmsjo/batches
void
run_job_grand_child_setup_stderr_stdout(cl_t * line, int *pipe_fd)
    /* setup stderr and stdout correctly so as the mail containing
     * the output of the job can be send at the end of the job.
     * Close the pipe (both ways). */
{

    if (is_mail(line->cl_option)) {
        /* we can't dup2 directly to mailfd, since a "cmd > /dev/stderr" in
         * a script would erase all previously collected message */
        if (dup2(pipe_fd[1], 1) != 1 || dup2(1, 2) != 2)
            die_e("dup2() error");      /* dup2 also clears close-on-exec flag */
        /* we close the pipe_fd[]s : the resources remain, and the pipe will
         * be effectively close when the job stops */
        xclose_check(&(pipe_fd[0]), "pipe_fd[0] in setup_stderr_stdout");
        xclose_check(&(pipe_fd[1]), "pipe_fd[1] in setup_stderr_stdout");
        /* Standard buffering results in unwanted behavior (some messages,
         * at least error from fcron process itself, are lost) */
#ifdef HAVE_SETLINEBUF
        setlinebuf(stdout);
        setlinebuf(stderr);
#else
        setvbuf(stdout, NULL, _IONBF, 0);
        setvbuf(stderr, NULL, _IONBF, 0);
#endif
    }
    else if (foreground) {
        if (freopen("/dev/null", "w", stdout) == NULL)
            error_e("could not freopen /dev/null as stdout");
        if (freopen("/dev/null", "w", stderr) == NULL)
            error_e("could not freopen /dev/null as stderr");
    }

}
示例#6
0
int
main(int argc, char **argv)
{
    struct passwd *pass = NULL;
    char *cur_user = NULL;

    rootuid = get_user_uid_safe(ROOTNAME);
    rootgid = get_group_gid_safe(ROOTGROUP);

    if (strrchr(argv[0], '/') == NULL)
        prog_name = argv[0];
    else
        prog_name = strrchr(argv[0], '/') + 1;

    fcrontab_uid = get_user_uid_safe(USERNAME);

#ifdef USE_SETE_ID
    /* get user's permissions */
    if (seteuid(fcrontab_uid) != 0)
        die_e("Could not change euid to " USERNAME "[%d]", uid);
#endif                          /* USE_SETE_ID */

    if (argc == 2)
        fcronconf = argv[1];
    else if (argc > 2)
        usage();

    /* read fcron.conf and update global parameters */
    /* We deactivate output to console, because otherwise it may be used
     * by a malicious user to read some data it is not allow to read
     * (fcronsighup is suid root) */
    foreground = 0;
    read_conf();
    foreground = 1;

    uid = getuid();

    /* check if user is allowed to use this program */
    if (!(pass = getpwuid(uid)))
        die("user \"%s\" is not in passwd file. Aborting.", USERNAME);
    cur_user = strdup2(pass->pw_name);

    if (is_allowed(cur_user)) {
        /* check if daemon is running */
        if ((daemon_pid = read_pid()) != 0)
            sig_daemon();
        else
            fprintf(stderr, "fcron is not running :\n  modifications will"
                    " be taken into account at its next execution.\n");
    }
    else
        die("User \"%s\" is not allowed to use %s. Aborting.", cur_user,
            prog_name);

    if (cur_user)
        free(cur_user);
    return EXIT_OK;

}
示例#7
0
int
connect_fcron(void)
    /* connect to fcron through a socket, and identify user */
{
    int fd = -1;
    struct sockaddr_un addr;
    int len = 0;
    int sun_len = 0;

    if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
        die_e("could not create socket");

    addr.sun_family = AF_UNIX;
    len = strlen(fifofile);
    if (len > sizeof(addr.sun_path) - 1)
        die("Error : fifo file path too long (max is %d)",
            sizeof(addr.sun_path) - 1);
    /* length(fifofile) < sizeof(add.sun_path), so strncpy will terminate
     * the string with at least one \0 (not necessarily required by the OS,
     * but still a good idea) */
    strncpy(addr.sun_path, fifofile, sizeof(addr.sun_path));
    addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
    sun_len = (addr.sun_path - (char *)&addr) + len;
#if HAVE_SA_LEN
    addr.sun_len = sun_len;
#endif

    if (connect(fd, (struct sockaddr *)&addr, sun_len) < 0)
        die_e("Cannot connect() to fcron (check if fcron is running)");

/* Nothing to do on the client side if we use SO_PASSCRED */
#if !defined(SO_PASSCRED) && !defined(HAVE_GETPEERUCRED) && !defined(HAVE_GETPEEREID)
    if (authenticate_user_password(fd) == ERR) {
        fprintf(stderr, "Invalid password or too many authentication failures"
                " (try to connect later).\n(In the later case, fcron rejects all"
                " new authentication during %d secs)\n", AUTH_WAIT);
        die("Unable to authenticate user");
    }
#endif                          /* SO_PASSCRED HAVE_GETPEERUCRED HAVE_GETPEEREID */

    return fd;

}
示例#8
0
int
copy(char *orig, char *dest)
    /* copy orig file to dest */
{
    int from;
    int to_fd;
    int nb;
    char *copy_buf[LINE_LEN];

    if ( (from = open(orig, O_RDONLY)) == -1) {
	error_e("copy: open(orig)");
	return ERR;
    }
    /* create it as fcrontab_uid (to avoid problem if user's uid changed)
     * except for root. Root requires filesystem uid root for security
     * reasons */
#ifdef USE_SETE_ID
    if (asuid == ROOTUID) {
	if (seteuid(ROOTUID) != 0)
	    error_e("seteuid(ROOTUID)");
    } 
    else {
    	if (seteuid(fcrontab_uid) != 0)
	    error_e("seteuid(fcrontab_uid[%d])", fcrontab_uid);
    }
#endif
    to_fd = open(dest, O_WRONLY | O_CREAT | O_TRUNC | O_SYNC, S_IRUSR|S_IWUSR|S_IRGRP);
    if (to_fd == -1) {
	error_e("copy: dest");
	return ERR;
    }
#ifdef USE_SETE_ID
    if (asuid != ROOTUID && seteuid(uid) != 0)
	die_e("seteuid(uid[%d])", uid);
#endif
    if (asuid == ROOTUID ) {
	if ( fchmod(to_fd, S_IWUSR | S_IRUSR) != 0 )
	    error_e("Could not fchmod %s to 600", dest);
	if ( fchown(to_fd, ROOTUID, fcrontab_gid) != 0 )
	    error_e("Could not fchown %s to root", dest);
    }

    while ( (nb = read(from, copy_buf, sizeof(copy_buf))) != -1 && nb != 0 )
	if ( write(to_fd, copy_buf, nb) != nb ) {
	    error("Error while copying file. Aborting.\n");
	    close(from);
	    close(to_fd);
	    return ERR;
	}

    close(from);
    close(to_fd);
    
    return OK;
}
示例#9
0
文件: fcron.c 项目: colmsjo/batches
void
create_spooldir(char *dir)
    /* create a new spool dir for fcron : set correctly its mode and owner */
{
    int dir_fd = -1;
    struct stat st;
    uid_t useruid = get_user_uid_safe(USERNAME);
    gid_t usergid = get_group_gid_safe(GROUPNAME);

    if (mkdir(dir, 0) != 0 && errno != EEXIST)
        die_e("Cannot create dir %s", dir);

    if ((dir_fd = open(dir, 0)) < 0)
        die_e("Cannot open dir %s", dir);

    if (fstat(dir_fd, &st) != 0) {
        xclose_check(&dir_fd, "spooldir");
        die_e("Cannot fstat %s", dir);
    }

    if (!S_ISDIR(st.st_mode)) {
        xclose_check(&dir_fd, "spooldir");
        die("%s exists and is not a directory", dir);
    }

    if (fchown(dir_fd, useruid, usergid) != 0) {
        xclose_check(&dir_fd, "spooldir");
        die_e("Cannot fchown dir %s to %s:%s", dir, USERNAME, GROUPNAME);
    }

    if (fchmod
        (dir_fd,
         S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP) != 0) {
        xclose_check(&dir_fd, "spooldir");
        die_e("Cannot change dir %s's mode to 770", dir);
    }

    xclose_check(&dir_fd, "spooldir");

    exit(EXIT_OK);

}
示例#10
0
文件: fcron.c 项目: colmsjo/batches
void
get_lock()
    /* check if another fcron daemon is running with the same config (-c option) :
     * in this case, die. if not, write our pid to /var/run/fcron.pid in order to lock,
     * and to permit fcrontab to read our pid and signal us */
{
    int otherpid = 0;
    FILE *daemon_lockfp = NULL;
    int fd;

    if (((fd = open(pidfile, O_RDWR | O_CREAT, 0644)) == -1)
        || ((daemon_lockfp = fdopen(fd, "r+"))) == NULL)
        die_e("can't open or create %s", pidfile);

#ifdef HAVE_FLOCK
    if (flock(fd, LOCK_EX | LOCK_NB) != 0)
#else                           /* HAVE_FLOCK */
    if (lockf(fileno(daemon_lockfp), F_TLOCK, 0) != 0)
#endif                          /* ! HAVE_FLOCK */
    {
        if (fscanf(daemon_lockfp, "%d", &otherpid) >= 1)
            die_e("can't lock %s, running daemon's pid may be %d", pidfile,
                  otherpid);
        else
            die_e("can't lock %s, and unable to read running"
                  " daemon's pid", pidfile);
    }

    fcntl(fd, F_SETFD, 1);

    rewind(daemon_lockfp);
    fprintf(daemon_lockfp, "%d\n", (int)daemon_pid);
    fflush(daemon_lockfp);
    if (ftruncate(fileno(daemon_lockfp), ftell(daemon_lockfp)) < 0)
        error_e
            ("Unable to ftruncate(fileno(daemon_lockfp), ftell(daemon_lockfp))");

    /* abandon fd and daemon_lockfp even though the file is open. we need to
     * keep it open and locked, but we don't need the handles elsewhere.
     */

}
示例#11
0
static char *get_socket()
{
    Atom a;
    char *s;
    
    dpy=XOpenDisplay(NULL);
    
    if(dpy==NULL)
        die_e("Unable to open display.");
    
    a=XInternAtom(dpy, "_NOTION_MOD_NOTIONFLUX_SOCKET", True);
    
    if(a==None)
        die_e("Missing atom. Notion not running?");
    
    s=xwindow_get_string_property(DefaultRootWindow(dpy), a, NULL);
    
    XCloseDisplay(dpy);
    
    return s;
}
示例#12
0
int
remove_fcrontab(char rm_orig)
    /* remove user's fcrontab and tell daemon to update his conf */
    /* note : the binary fcrontab is removed by fcron */
{
    int return_val = OK;
    int fd;

    if ( rm_orig )
	explain("removing %s's fcrontab", user);

    /* remove source and formated file */
    if ( (rm_orig && remove(buf)) != 0 ) {
	if ( errno == ENOENT )
	    return_val = ENOENT;
	else
	    error_e("could not remove %s", buf);		
    }

#ifdef USE_SETE_ID
    if (seteuid(fcrontab_uid) != 0)
	error_e("seteuid(fcrontab_uid[%d])", fcrontab_uid);
#endif
	    
    /* try to remove the temp file in case he has not
     * been read by fcron daemon */
    snprintf(buf, sizeof(buf), "new.%s", user);
    remove(buf);

    /* finally create a file in order to tell the daemon
     * a file was removed, and launch a signal to daemon */
    snprintf(buf, sizeof(buf), "rm.%s", user);
    fd = open(buf, O_CREAT | O_TRUNC | O_EXCL, S_IRUSR | S_IWUSR);

#ifdef USE_SETE_ID
    if (seteuid(uid) != 0)
	die_e("seteuid(uid[%d])", uid);
#endif

    if ( fd == -1 ) {
	if ( errno != EEXIST )
	    error_e("Can't create file %s", buf);
    }
    else if ( asuid == ROOTUID && fchown(fd, ROOTUID, fcrontab_gid) != 0 )
	error_e("Could not fchown %s to root", buf);
    close(fd);
    
    need_sig = 1;

    return return_val;

}
示例#13
0
static void mywrite(int fd, const char *buf, int n)
{
    while(n>0){
        int k;
        k=write(fd, buf, n);
        if(k<0 && (errno!=EAGAIN && errno!=EINTR))
            die_e("Writing");
        if(k>0){
            n-=k;
            buf+=k;
        }
    }
}
示例#14
0
文件: job.c 项目: colmsjo/batches
void
launch_mailer(cl_t * line, FILE * mailf, char **sendmailenv)
    /* mail the output of a job to user */
{
#ifdef USE_SENDMAIL
    foreground = 0;

    /* set stdin to the job's output */

    /* fseek() should work, but it seems that it is not always the case
     * (users have reported problems on gentoo and LFS).
     * For those users, lseek() works, so I have decided to use both,
     * as I am not sure that lseek(fileno(...)...) will work as expected
     * on non linux systems. */
    if (fseek(mailf, 0, SEEK_SET) != 0)
        die_e("Can't fseek()");
    if (lseek(fileno(mailf), 0, SEEK_SET) != 0)
        die_e("Can't lseek()");
    if (dup2(fileno(mailf), 0) != 0)
        die_e("Can't dup2(fileno(mailf))");

    xcloselog();

    if (chdir("/") < 0)
        die_e("Could not chdir to /");

    /* run sendmail with mail file as standard input */
    /* // */
    debug("execle(%s, %s, %s, %s, NULL, sendmailenv)", sendmail, sendmail,
          SENDMAIL_ARGS, line->cl_mailto);
    /* // */
    execle(sendmail, sendmail, SENDMAIL_ARGS, line->cl_mailto, NULL,
           sendmailenv);
    die_e("Couldn't exec '%s'", sendmail);
#else                           /* defined(USE_SENDMAIL) */
    exit(EXIT_OK);
#endif
}
示例#15
0
void
xexit(int exit_val)
    /* launch signal if needed and exit */
{
    pid_t pid = 0;

    if ( need_sig == 1 ) {
	
	/* fork and exec fcronsighup */
	switch ( pid = fork() ) {
	case 0:
	    /* child */
	    execl(BINDIREX "/fcronsighup", BINDIREX "/fcronsighup",
		  fcronconf, NULL);
	    die_e("Could not exec " BINDIREX " fcronsighup");
	    break;

	case -1:
	    die_e("Could not fork (fcron has not been signaled)");
	    break;

	default:
	    /* parent */
	    waitpid(pid, NULL, 0);
	    break;
	}
    }

#ifdef HAVE_LIBPAM
    pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
    pam_end(pamh, pam_close_session(pamh, PAM_SILENT));
#endif

    exit(exit_val);

}
示例#16
0
static int myread(int fd, char *buf, int n)
{
    int left=n;
    
    while(left>0){
        int k;
        k=read(fd, buf, left);
        if(k<0 && (errno!=EAGAIN && errno!=EINTR))
            die_e("Writing");
        if(k==0)
            break;
        if(k>0){
            left-=k;
            buf+=k;
        }
    }
    return n-left;
}
示例#17
0
文件: job.c 项目: colmsjo/batches
void
change_user_setup_env(struct cl_t *cl,
                      char ***sendmailenv, char ***jobenv, char **curshell,
                      char **curhome, char **content_type, char **encoding)
/* call setup_user_and_env() and become_user().
 * As a result, *curshell and *curhome will be allocated and should thus be freed
 * if curshell and curhome are not NULL. */
{
    struct passwd *pas;

    errno = 0;
    pas = getpwnam(cl->cl_runas);
    if (pas == NULL)
        die_e("failed to get passwd fields for user \"%s\"", cl->cl_runas);

    setup_user_and_env(cl, pas, sendmailenv, jobenv, curshell, curhome,
                       content_type, encoding);

    become_user(cl, pas, (curhome != NULL) ? *curhome : "/");
}
示例#18
0
文件: fcron.c 项目: colmsjo/batches
int
main(int argc, char **argv)
{
    char *codeset = NULL;

    rootuid = get_user_uid_safe(ROOTNAME);
    rootgid = get_group_gid_safe(ROOTGROUP);

    /* we set it to 022 in order to get a pidfile readable by fcrontab
     * (will be set to 066 later) */
    saved_umask = umask(022);

    /* parse options */

    if (strrchr(argv[0], '/') == NULL)
        prog_name = argv[0];
    else
        prog_name = strrchr(argv[0], '/') + 1;

    {
        uid_t daemon_uid;
        if ((daemon_uid = getuid()) != rootuid)
            die("Fcron must be executed as root");
    }

    /* we have to set daemon_pid before the fork because it's
     * used in die() and die_e() functions */
    daemon_pid = getpid();

    /* save the value of the TZ env variable (used for option timezone) */
    orig_tz_envvar = strdup2(getenv("TZ"));

    parseopt(argc, argv);

    /* read fcron.conf and update global parameters */
    read_conf();

    /* initialize the logs before we become a daemon */
    xopenlog();

    /* change directory */

    if (chdir(fcrontabs) != 0)
        die_e("Could not change dir to %s", fcrontabs);

    /* Get the default locale character set for the mail
     * "Content-Type: ...; charset=" header */
    setlocale(LC_ALL, "");      /* set locale to system defaults or to
                                 * that specified by any  LC_* env vars */
    /* Except that "US-ASCII" is preferred to "ANSI_x3.4-1968" in MIME,
     * even though "ANSI_x3.4-1968" is the official charset name. */
    if ((codeset = nl_langinfo(CODESET)) != 0L &&
        strcmp(codeset, "ANSI_x3.4-1968") != 0)
        strncpy(default_mail_charset, codeset, sizeof(default_mail_charset));
    else
        strcpy(default_mail_charset, "US-ASCII");

    if (freopen("/dev/null", "r", stdin) == NULL)
        error_e("Could not open /dev/null as stdin");

    if (foreground == 0) {

        /* close stdout and stderr.
         * close unused descriptors
         * optional detach from controlling terminal */

        int fd;
        pid_t pid;

        switch (pid = fork()) {
        case -1:
            die_e("fork");
            break;
        case 0:
            /* child */
            break;
        default:
            /* parent */
/*  	    printf("%s[%d] " VERSION_QUOTED " : started.\n", */
/*  		   prog_name, pid); */
            exit(0);
        }

        daemon_pid = getpid();

        if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
#ifndef _HPUX_SOURCE
            ioctl(fd, TIOCNOTTY, 0);
#endif
            xclose_check(&fd, "/dev/tty");
        }

        if (freopen("/dev/null", "w", stdout) == NULL)
            error_e("Could not open /dev/null as stdout");
        if (freopen("/dev/null", "w", stderr) == NULL)
            error_e("Could not open /dev/null as stderr");

        /* close most other open fds */
        xcloselog();
        for (fd = 3; fd < 250; fd++)
            /* don't use xclose_check() as we do expect most of them to fail */
            (void)close(fd);

        /* finally, create a new session */
        if (setsid() == -1)
            error("Could not setsid()");

    }

    /* check if another fcron daemon is running, create pid file and lock it */
    get_lock();

    /* this program belongs to root : we set default permission mode
     * to  600 for security reasons, but we reset them to the saved
     * umask just before we run a job */
    umask(066);

    explain("%s[%d] " VERSION_QUOTED " started", prog_name, daemon_pid);

#ifdef HAVE_SIGNAL
    signal(SIGTERM, sigterm_handler);
    signal(SIGHUP, sighup_handler);
    siginterrupt(SIGHUP, 0);
    signal(SIGCHLD, sigchild_handler);
    siginterrupt(SIGCHLD, 0);
    signal(SIGUSR1, sigusr1_handler);
    siginterrupt(SIGUSR1, 0);
    signal(SIGUSR2, sigusr2_handler);
    siginterrupt(SIGUSR2, 0);
    /* we don't want SIGPIPE to kill fcron, and don't need to handle it */
    signal(SIGPIPE, SIG_IGN);
#elif HAVE_SIGSET
    sigset(SIGTERM, sigterm_handler);
    sigset(SIGHUP, sighup_handler);
    sigset(SIGCHLD, sigchild_handler);
    sigset(SIGUSR1, sigusr1_handler);
    sigset(SIGUSR2, sigusr2_handler);
    sigset(SIGPIPE, SIG_IGN);
#endif

    /* initialize job database */
    next_id = 0;

    /* initialize exe_array */
    exe_list = exe_list_init();

    /* initialize serial_array */
    serial_running = 0;
    serial_array_index = 0;
    serial_num = 0;
    serial_array_size = SERIAL_INITIAL_SIZE;
    serial_array =
        alloc_safe(serial_array_size * sizeof(cl_t *), "serial_array");

    /* initialize lavg_array */
    lavg_list = lavg_list_init();
    lavg_list->max_entries = lavg_queue_max;
    lavg_serial_running = 0;

#ifdef FCRONDYN
    /* initialize socket */
    init_socket();
#endif

    /* initialize random number generator :
     * WARNING : easy to guess !!! */
    /* we use the hostname and tv_usec in order to get different seeds
     * on two different machines starting fcron at the same moment */
    {
        char hostname[50];
        int i;
        unsigned int seed;
#ifdef HAVE_GETTIMEOFDAY
        struct timeval tv;      /* we use usec field to get more precision */
        gettimeofday(&tv, NULL);
        seed = ((unsigned int)tv.tv_usec) ^ ((unsigned int)tv.tv_sec);
#else
        seed = (unsigned int)time(NULL);
#endif
        gethostname(hostname, sizeof(hostname));

        for (i = 0; i < sizeof(hostname) - sizeof(seed); i += sizeof(seed))
            seed ^= (unsigned int)*(hostname + i);

        srand(seed);
    }

    main_loop();

    /* never reached */
    return EXIT_OK;
}
示例#19
0
文件: job.c 项目: colmsjo/batches
void
end_job(cl_t * line, int status, FILE * mailf, short mailpos,
        char **sendmailenv)
    /* if task have made some output, mail it to user */
{

    char mail_output = 0;
    char *m = NULL;

#ifdef USE_SENDMAIL
    if (mailf != NULL && (is_mailzerolength(line->cl_option)
                          || (is_mail(line->cl_option)
                              && (
                                     /* job wrote some output and we wan't it in any case: */
                                     ((fseek(mailf, 0, SEEK_END) == 0
                                       && ftell(mailf) > mailpos)
                                      && !is_erroronlymail(line->cl_option))
                                     ||
                                     /* or we want an email only if the job returned an error: */
                                     !(WIFEXITED(status)
                                       && WEXITSTATUS(status) == 0)
                              )
                          )
        )
        ) {
        /* an output exit : we will mail it */
        mail_output = 1;
    }
    /* or else there is no output to email -- mail_output is already set to 0 */
#endif                          /* USE_SENDMAIL */

    m = (mail_output == 1) ? " (mailing output)" : "";
    if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
        if (!is_nolog(line->cl_option))
            explain("Job '%s' completed%s", line->cl_shell, m);
    }
    else if (WIFEXITED(status)) {
        warn("Job '%s' terminated (exit status: %d)%s",
             line->cl_shell, WEXITSTATUS(status), m);
        /* there was an error : in order to inform the user by mail, we need
         * to add some data to mailf */
        if (mailf != NULL)
            fprintf(mailf, "Job '%s' terminated (exit status: %d)%s",
                    line->cl_shell, WEXITSTATUS(status), m);
    }
    else if (WIFSIGNALED(status)) {
        error("Job '%s' terminated due to signal %d%s",
              line->cl_shell, WTERMSIG(status), m);
        if (mailf != NULL)
            fprintf(mailf, "Job '%s' terminated due to signal %d%s",
                    line->cl_shell, WTERMSIG(status), m);
    }
    else {                      /* is this possible? */
        error("Job '%s' terminated abnormally %s", line->cl_shell, m);
        if (mailf != NULL)
            fprintf(mailf, "Job '%s' terminated abnormally %s", line->cl_shell,
                    m);
    }

#ifdef HAVE_LIBPAM
    /* we close the PAM session before running the mailer command :
     * it avoids a fork(), and we use PAM anyway to control whether a user command
     * should be run or not.
     * We consider that the administrator can use a PAM compliant mailer to control
     * whether a mail can be sent or not.
     * It should be ok like that, otherwise contact me ... -tg */

    /* Aiee! we may need to be root to do this properly under Linux.  Let's
     * hope we're more l33t than PAM and try it as non-root. If someone
     * complains, I'll fix this :P -hmh */
    pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT);
    pam_end(pamh, pam_close_session(pamh, PAM_SILENT));
#endif

    if (mail_output == 1) {
        launch_mailer(line, mailf, sendmailenv);
        /* never reached */
        die_e("Internal error: launch_mailer returned");
    }

    /* if mail is sent, execution doesn't get here : close /dev/null */
    xfclose_check(&mailf, "Can't close file mailf");

    exit(0);

}
示例#20
0
文件: job.c 项目: colmsjo/batches
int
run_job(struct exe_t *exeent)
    /* fork(), redirect outputs to a temp file, and execl() the task.
     * Return ERR if it could not fork() the first time, OK otherwise. */
{

    pid_t pid;
    cl_t *line = exeent->e_line;
    int pipe_pid_fd[2];
    int ret = 0;

    /* prepare the job execution */
    if (pipe(pipe_pid_fd) != 0) {
        error_e("pipe(pipe_pid_fd) : setting job_pid to -1");
        exeent->e_job_pid = -1;
        pipe_pid_fd[0] = pipe_pid_fd[1] = -1;
    }

#ifdef CHECKRUNJOB
    debug
        ("run_job(): first pipe created successfully : about to do first fork()");
#endif                          /* CHECKRUNJOB */

    switch (pid = fork()) {
    case -1:
        error_e("Fork error : could not exec '%s'", line->cl_shell);
        return ERR;
        break;

    case 0:
        /* child */
        {
            struct passwd *pas = NULL;
            char **jobenv = NULL;
            char **sendmailenv = NULL;
            char *curshell = NULL;
            char *curhome = NULL;
            char *content_type = NULL;
            char *encoding = NULL;
            FILE *mailf = NULL;
            int status = 0;
            int to_stdout = foreground && is_stdout(line->cl_option);
            int pipe_fd[2];
            short int mailpos = 0;      /* 'empty mail file' size */
#ifdef WITH_SELINUX
            int flask_enabled = is_selinux_enabled();
#endif

            /* // */
            debug("run_job(): child: %s, output to %s, %s, %s\n",
                  is_mail(line->cl_option) ? "mail" : "no mail",
                  to_stdout ? "stdout" : "file",
                  foreground ? "running in foreground" :
                  "running in background",
                  is_stdout(line->cl_option) ? "stdout" : "normal");
            /* // */

            errno = 0;
            pas = getpwnam(line->cl_runas);
            if (pas == NULL)
                die_e("failed to get passwd fields for user \"%s\"",
                      line->cl_runas);

            setup_user_and_env(line, pas, &sendmailenv, &jobenv, &curshell,
                               &curhome, &content_type, &encoding);

            /* close unneeded READ fd */
            xclose_check(&(pipe_pid_fd[0]), "child's pipe_pid_fd[0]");

            pipe_fd[0] = pipe_fd[1] = -1;
            if (!to_stdout && is_mail(line->cl_option)) {
                /* we create the temp file (if needed) before change_user(),
                 * as temp_file() needs root privileges */
                /* if we run in foreground, stdout and stderr point to the console.
                 * Otherwise, stdout and stderr point to /dev/null . */
                mailf = create_mail(line, NULL, content_type, encoding, jobenv);
                mailpos = ftell(mailf);
                if (pipe(pipe_fd) != 0)
                    die_e("could not pipe() (job not executed)");
            }

            become_user(line, pas, curhome);
            Free_safe(curhome);

            /* restore umask to default */
            umask(saved_umask);

            sig_dfl();

#ifdef CHECKRUNJOB
            debug
                ("run_job(): child: change_user() done -- about to do 2nd fork()");
#endif                          /* CHECKRUNJOB */

            /* now, run the job */
            switch (pid = fork()) {
            case -1:
                error_e("Fork error : could not exec '%s'", line->cl_shell);
                if (write(pipe_pid_fd[1], &pid, sizeof(pid)) < 0)
                    error_e("could not write child pid to pipe_pid_fd[1]");
                xclose_check(&(pipe_fd[0]), "child's pipe_fd[0]");
                xclose_check(&(pipe_fd[1]), "child's pipe_fd[1]");
                xclose_check(&(pipe_pid_fd[1]), "child's pipe_pid_fd[1]");
                exit(EXIT_ERR);
                break;

            case 0:
                /* grand child (child of the 2nd fork) */

                /* the grand child does not use this pipe: close remaining fd */
                xclose_check(&(pipe_pid_fd[1]), "grand child's pipe_pid_fd[1]");

                if (!to_stdout)
                    /* note : the following closes the pipe */
                    run_job_grand_child_setup_stderr_stdout(line, pipe_fd);

                foreground = 1;
                /* now, errors will be mailed to the user (or to /dev/null) */

                run_job_grand_child_setup_nice(line);

                xcloselog();

#if defined(CHECKJOBS) || defined(CHECKRUNJOB)
                /* this will force to mail a message containing at least the exact
                 * and complete command executed for each execution of all jobs */
                debug("run_job(): grand-child: Executing \"%s -c %s\"",
                      curshell, line->cl_shell);
#endif                          /* CHECKJOBS OR CHECKRUNJOB */

#ifdef WITH_SELINUX
                if (flask_enabled
                    && setexeccon(line->cl_file->cf_user_context) < 0)
                    die_e("Can't set execute context '%s' for user '%s'.",
                          line->cl_file->cf_user_context, line->cl_runas);
#else
                if (setsid() == -1) {
                    die_e("setsid(): errno %d", errno);
                }
#endif
                execle(curshell, curshell, "-c", line->cl_shell, NULL, jobenv);
                /* execle returns only on error */
                die_e("Couldn't exec shell '%s'", curshell);

                /* execution never gets here */

            default:
                /* child (parent of the 2nd fork) */

                /* close unneeded WRITE pipe and READ pipe */
                xclose_check(&(pipe_fd[1]), "child's pipe_fd[1]");

#ifdef CHECKRUNJOB
                debug("run_job(): child: pipe_fd[1] and pipe_pid_fd[0] closed"
                      " -- about to write grand-child pid to pipe");
#endif                          /* CHECKRUNJOB */

                /* give the pid of the child to the parent (main) fcron process */
                ret = write_pipe(pipe_pid_fd[1], &pid, sizeof(pid));
                if (ret != OK) {
                    if (ret == ERR)
                        error
                            ("run_job(): child: Could not write job pid to pipe");
                    else {
                        errno = ret;
                        error_e
                            ("run_job(): child: Could not write job pid to pipe");
                    }
                }

#ifdef CHECKRUNJOB
                debug("run_job(): child: grand-child pid written to pipe");
#endif                          /* CHECKRUNJOB */

                if (!is_nolog(line->cl_option))
                    explain("Job '%s' started for user %s (pid %d)",
                            line->cl_shell, line->cl_file->cf_user, pid);

                if (!to_stdout && is_mail(line->cl_option)) {
                    /* user wants a mail : we use the pipe */
                    char mailbuf[TERM_LEN];
                    FILE *pipef = fdopen(pipe_fd[0], "r");

                    if (pipef == NULL)
                        die_e("Could not fdopen() pipe_fd[0]");

                    mailbuf[sizeof(mailbuf) - 1] = '\0';
                    while (fgets(mailbuf, sizeof(mailbuf), pipef) != NULL)
                        if (fputs(mailbuf, mailf) < 0)
                            warn("fputs() failed to write to mail file for job '%s' (pid %d)", line->cl_shell, pid);
                    /* (closes also pipe_fd[0]): */
                    xfclose_check(&pipef, "child's pipef");
                }

                /* FIXME : FOLLOWING HACK USELESS ? */
                /* FIXME : HACK
                 * this is a try to fix the bug on sorcerer linux (no jobs
                 * exectued at all, and
                 * "Could not read job pid : setting it to -1: No child processes"
                 * error messages) */
                /* use a select() or similar to know when parent has read
                 * the pid (with a timeout !) */
                /* // */
                sleep(2);
                /* // */
#ifdef CHECKRUNJOB
                debug("run_job(): child: closing pipe with parent");
#endif                          /* CHECKRUNJOB */
                xclose_check(&(pipe_pid_fd[1]), "child's pipe_pid_fd[1]");

                /* we use a while because of a possible interruption by a signal */
                while ((pid = wait3(&status, 0, NULL)) > 0) {
#ifdef CHECKRUNJOB
                    debug("run_job(): child: ending job pid %d", pid);
#endif                          /* CHECKRUNJOB */
                    end_job(line, status, mailf, mailpos, sendmailenv);
                }

                /* execution never gets here */

            }

            /* execution should never gets here, but if it happened we exit with an error */
            exit(EXIT_ERR);
        }

    default:
        /* parent */

        /* close unneeded WRITE fd */
        xclose_check(&(pipe_pid_fd[1]), "parent's pipe_pid_fd[1]");

        exeent->e_ctrl_pid = pid;

#ifdef CHECKRUNJOB
        debug("run_job(): about to read grand-child pid...");
#endif                          /* CHECKRUNJOB */

        /* read the pid of the job */
        ret = read_pipe(pipe_pid_fd[0], &(exeent->e_job_pid), sizeof(pid_t));
        if (ret != OK) {
            if (ret == ERR) {
                error("Could not read job pid because of closed pipe:"
                      " setting it to -1");
            }
            else {
                errno = ret;
                error_e("Could not read job pid : setting it to -1");
            }

            exeent->e_job_pid = -1;
        }
        xclose_check(&(pipe_pid_fd[0]), "parent's pipe_pid_fd[0]");

#ifdef CHECKRUNJOB
        debug
            ("run_job(): finished reading pid of the job -- end of run_job().");
#endif                          /* CHECKRUNJOB */

    }

    return OK;

}
示例#21
0
文件: fcron.c 项目: colmsjo/batches
void
main_loop()
  /* main loop - get the time to sleep until next job execution,
   *             sleep, and then test all jobs and execute if needed. */
{
    time_t save;                /* time remaining until next save */
    time_t stime;               /* time to sleep until next job
                                 * execution */
#ifdef HAVE_GETTIMEOFDAY
    struct timeval tv;          /* we use usec field to get more precision */
#endif
#ifdef FCRONDYN
    int retcode = 0;
#endif

    debug("Entering main loop");

    now = time(NULL);

    synchronize_dir(".", is_system_startup());

    /* synchronize save with jobs execution */
    save = now + save_time;

    if (serial_num > 0 || once)
        stime = first_sleep;
    else if ((stime = time_to_sleep(save)) < first_sleep)
        /* force first execution after first_sleep sec : execution of jobs
         * during system boot time is not what we want */
        stime = first_sleep;
    debug("initial sleep time : %ld", stime);

    for (;;) {

#ifdef HAVE_GETTIMEOFDAY
#ifdef FCRONDYN
        gettimeofday(&tv, NULL);
        tv.tv_sec = (stime > 1) ? stime - 1 : 0;
        /* we set tv_usec to slightly more than necessary so as
         * we don't wake up too early, in which case we would
         * have to sleep again for some time */
        tv.tv_usec = 1001000 - tv.tv_usec;
        /* On some systems (BSD, etc), tv_usec cannot be greater than 999999 */
        if (tv.tv_usec > 999999)
            tv.tv_usec = 999999;
        /* note: read_set is set in socket.c */
        if ((retcode = select(set_max_fd + 1, &read_set, NULL, NULL, &tv)) < 0
            && errno != EINTR)
            die_e("select returned %d", errno);
#else
        if (stime > 1)
            sleep(stime - 1);
        gettimeofday(&tv, NULL);
        /* we set tv_usec to slightly more than necessary to avoid
         * infinite loop */
        usleep(1001000 - tv.tv_usec);
#endif                          /* FCRONDYN */
#else
        sleep(stime);
#endif                          /* HAVE_GETTIMEOFDAY */

        now = time(NULL);

        check_signal();

        debug("\n");

        test_jobs();

        while (serial_num > 0 && serial_running < serial_max_running)
            run_serial_job();

        if (once) {
            explain("Running with option once : exiting ... ");
            xexit(EXIT_OK);
        }

        if (save <= now) {
            save = now + save_time;
            /* save all files */
            save_file(NULL);
        }

#ifdef FCRONDYN
        /* check if there's a new connection, a new command to answer, etc ... */
        /* we do that *after* other checks, to avoid Denial Of Service attacks */
        check_socket(retcode);
#endif

        stime = check_lavg(save);
        debug("next sleep time : %ld", stime);

        check_signal();

    }

}
示例#22
0
文件: job.c 项目: colmsjo/batches
FILE *
create_mail(cl_t * line, char *subject, char *content_type, char *encoding,
            char **env)
    /* create a temp file and write in it a mail header */
{
    /* create temporary file for stdout and stderr of the job */
    int mailfd = temp_file(NULL);
    FILE *mailf = fdopen(mailfd, "r+");
    char hostname[USER_NAME_LEN];
    /* is this a complete mail address ? (ie. with a "@", not only a username) */
    char add_hostname = 0;
    int i = 0;

    if (mailf == NULL)
        die_e("Could not fdopen() mailfd");

#ifdef HAVE_GETHOSTNAME
    if (gethostname(hostname, sizeof(hostname)) != 0) {
        error_e("Could not get hostname");
        hostname[0] = '\0';
    }
    else {
        /* it is unspecified whether a truncated hostname is NUL-terminated */
        hostname[USER_NAME_LEN - 1] = '\0';

        /* check if mailto is a complete mail address */
        add_hostname = (strchr(line->cl_mailto, '@') == NULL) ? 1 : 0;
    }
#else                           /* HAVE_GETHOSTNAME */
    hostname[0] = '\0';
#endif                          /* HAVE_GETHOSTNAME */

    /* write mail header */
    if (add_hostname)
        fprintf(mailf, "To: %s@%s\n", line->cl_mailto, hostname);
    else
        fprintf(mailf, "To: %s\n", line->cl_mailto);

    if (subject)
        fprintf(mailf, "Subject: fcron <%s@%s> %s: %s\n",
                line->cl_file->cf_user, (hostname[0] != '\0') ? hostname : "?",
                subject, line->cl_shell);
    else
        fprintf(mailf, "Subject: fcron <%s@%s> %s\n", line->cl_file->cf_user,
                (hostname[0] != '\0') ? hostname : "?", line->cl_shell);

    if (content_type == NULL) {
        fprintf(mailf, "Content-Type: text/plain; charset=%s\n",
                default_mail_charset);
    }
    else {
        /* user specified Content-Type header. */
        char *c = NULL;

        /* Remove new-lines or users could specify arbitrary mail headers!
         * (fcrontab should already prevent that, but better safe than sorry) */
        for (c = content_type; *c != '\0'; c++) {
            if (*c == '\n')
                *c = ' ';
        }
        fprintf(mailf, "Content-Type: %s\n", content_type);
    }

    if (encoding != NULL) {
        char *c = NULL;

        /* Remove new-lines or users could specify arbitrary mail headers!
         * (fcrontab should already prevent that, but better safe than sorry) */
        for (c = encoding; *c != '\0'; c++) {
            if (*c == '\n')
                *c = ' ';
        }
        fprintf(mailf, "Content-Transfer-Encoding: %s\n", encoding);
    }

    /* Add headers so as automated systems can identify that this message
     * is an automated one sent by fcron.
     * That's useful for example for vacation auto-reply systems: no need
     * to send such an automated response to fcron! */

    /* The Auto-Submitted header is
     * defined (and suggested by) RFC3834. */
    fprintf(mailf, "Auto-Submitted: auto-generated\n");

    /* See environ(7) and execle(3) to get documentation on environ:
     * it is an array of NULL-terminated strings, whose last entry is NULL */
    if (env != NULL) {
        for (i = 0; env[i] != NULL; i++) {
            fprintf(mailf, "X-Cron-Env: <%s>\n", env[i]);
        }
    }

    /* Final line return to end the header section: */
    fprintf(mailf, "\n");

    return mailf;
}
示例#23
0
int
main(int argc, char **argv)
{

#ifdef HAVE_LIBPAM
    int    retcode = 0;
    const char * const * env;
#endif
#ifdef USE_SETE_ID
    struct passwd *pass;
#endif

    memset(buf, 0, sizeof(buf));
    memset(file, 0, sizeof(file));

    if (strrchr(argv[0],'/')==NULL) prog_name = argv[0];
    else prog_name = strrchr(argv[0],'/')+1;
    
    uid = getuid();

    /* get current dir */
    if ( getcwd(orig_dir, sizeof(orig_dir)) == NULL )
	die_e("getcwd");

    /* interpret command line options */
    parseopt(argc, argv);

#ifdef USE_SETE_ID
    if ( ! (pass = getpwnam(USERNAME)) )
	die("user \"%s\" is not in passwd file. Aborting.", USERNAME);
    fcrontab_uid = pass->pw_uid;
    fcrontab_gid = pass->pw_gid;

#ifdef HAVE_LIBPAM
    /* Open PAM session for the user and obtain any security
       credentials we might need */

    debug("username: %s", user);
    retcode = pam_start("fcrontab", user, &apamconv, &pamh);
    if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not start PAM");
    retcode = pam_authenticate(pamh, 0);    /* is user really user? */
    if (retcode != PAM_SUCCESS)
	die_pame(pamh, retcode, "Could not authenticate user using PAM (%d)", retcode);
    retcode = pam_acct_mgmt(pamh, 0); /* permitted access? */
    if (retcode != PAM_SUCCESS)
	die_pame(pamh, retcode, "Could not init PAM account management (%d)", retcode);
    retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
    if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not set PAM credentials");
    retcode = pam_open_session(pamh, 0);
    if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not open PAM session");

    env = (const char * const *) pam_getenvlist(pamh);
    while (env && *env) {
	if (putenv((char*) *env)) die_e("Could not copy PAM environment");
	env++;
    }

    /* Close the log here, because PAM calls openlog(3) and
       our log messages could go to the wrong facility */
    xcloselog();
#endif /* USE_PAM */

    if (uid != fcrontab_uid)
	if (seteuid(fcrontab_uid) != 0) 
	    die_e("Couldn't change euid to fcrontab_uid[%d]",fcrontab_uid);
    /* change directory */
    if (chdir(fcrontabs) != 0) {
	error_e("Could not chdir to %s", fcrontabs);
	xexit (EXIT_ERR);
    }
    /* get user's permissions */
    if (seteuid(uid) != 0) 
	die_e("Could not change euid to %d", uid); 
    if (setegid(fcrontab_gid) != 0) 
	die_e("Could not change egid to " GROUPNAME "[%d]", fcrontab_gid); 

#else /* USE_SETE_ID */

    if (setuid(ROOTUID) != 0 ) 
	die_e("Could not change uid to ROOTUID"); 
    if (setgid(ROOTGID) != 0)
    	die_e("Could not change gid to ROOTGID");
    /* change directory */
    if (chdir(fcrontabs) != 0) {
	error_e("Could not chdir to %s", fcrontabs);
	xexit (EXIT_ERR);
    }
#endif /* USE_SETE_ID */
    
    /* this program is seteuid : we set default permission mode
     * to 640 for a normal user, 600 for root, for security reasons */
    if ( asuid == ROOTUID )
	umask(066);  /* octal : '0' + number in octal notation */
    else
	umask(026);

    snprintf(buf, sizeof(buf), "%s.orig", user);

    /* determine what action should be taken */
    if ( file_opt ) {

	if ( strcmp(argv[file_opt], "-") == 0 )

	    xexit(install_stdin());

	else {

	    if ( *argv[file_opt] != '/' )
		/* this is just the file name, not the path : complete it */
		snprintf(file, sizeof(file), "%s/%s", orig_dir, argv[file_opt]);
	    else {
		strncpy(file, argv[file_opt], sizeof(file) - 1);
		file[sizeof(file)-1] = '\0';
	    }

	    if (make_file(file) == OK)
		xexit(EXIT_OK);
	    else
		xexit(EXIT_ERR);

	}

    } 

    /* remove user's entries */
    if ( rm_opt == 1 ) {
	if ( remove_fcrontab(1) == ENOENT )
	    fprintf(stderr, "no fcrontab for %s\n", user);
	xexit (EXIT_OK);
    }

    /* list user's entries */
    if ( list_opt == 1 ) {
	list_file(buf);
	xexit(EXIT_OK);
    }


    /* edit user's entries */
    if ( edit_opt == 1 ) {
	edit_file(buf);
	xexit(EXIT_OK);
    }

    /* reinstall user's entries */
    if ( reinstall_opt == 1 ) {
	reinstall(buf);
	xexit(EXIT_OK);
    }

    /* never reached */
    return EXIT_OK;
}
示例#24
0
int
main(int argc, char **argv)
{
    int return_code = 0;
    int fd = (-1);              /* fd == -1 means connection to fcron is not currently open */
    struct passwd *pass = NULL;

    rootuid = get_user_uid_safe(ROOTNAME);
    rootgid = get_group_gid_safe(ROOTGROUP);

    if (strrchr(argv[0], '/') == NULL)
        prog_name = argv[0];
    else
        prog_name = strrchr(argv[0], '/') + 1;

    user_uid = getuid();
    user_gid = getgid();
    if ((pass = getpwuid(user_uid)) == NULL)
        die("user \"%s\" is not in passwd file. Aborting.", USERNAME);
    user_str = strdup2(pass->pw_name);

    /* drop suid rights that we don't need, but keep the sgid rights
     * for now as we will need them for read_conf() and is_allowed() */
#ifdef USE_SETE_ID
    seteuid_safe(user_uid);
#endif
    if (setuid(user_uid) < 0)
        die_e("could not setuid() to %d", user_uid);

    /* interpret command line options */
    parseopt(argc, argv);

    /* read fcron.conf and update global parameters */
    read_conf();

    if (!is_allowed(user_str)) {
        die("User \"%s\" is not allowed to use %s. Aborting.", user_str,
            prog_name);
    }

    /* we don't need anymore special rights : drop remaining ones */
#ifdef USE_SETE_ID
    setegid_safe(user_gid);
#endif
    if (setgid(user_gid) < 0)
        die_e("could not setgid() to %d", user_gid);

    /* check for broken pipes ... */
    signal(SIGPIPE, sigpipe_handler);

    if (cmd_str == NULL)
        return_code = interactive_mode(fd);
    else
        return_code = talk_fcron(cmd_str, fd);

    xexit((return_code == OK) ? EXIT_OK : EXIT_ERR);

    /* never reached */
    return EXIT_OK;

}
示例#25
0
void
sig_daemon(void)
    /* send SIGHUP to daemon to tell him configuration has changed */
    /* SIGHUP is sent once 10s before the next minute to avoid
     * some bad users to block daemon by sending it SIGHUP all the time */
{
    /* we don't need to make root wait */
    if (uid != rootuid) {
        time_t t = 0;
        int sl = 0;
        FILE *fp = NULL;
        int fd = 0;
        struct tm *tm = NULL;
        char sigfile[PATH_LEN];
        char buf[PATH_LEN];

        sigfile[0] = '\0';
        t = time(NULL);
        tm = localtime(&t);

        if ((sl = 60 - (t % 60) - 10) < 0) {
            if ((tm->tm_min = tm->tm_min + 2) >= 60) {
                tm->tm_hour++;
                tm->tm_min -= 60;
            }
            snprintf(buf, sizeof(buf), "%02d:%02d", tm->tm_hour, tm->tm_min);
            sl = 60 - (t % 60) + 50;
        }
        else {
            if (++tm->tm_min >= 60) {
                tm->tm_hour++;
                tm->tm_min -= 60;
            }
            snprintf(buf, sizeof(buf), "%02d:%02d", tm->tm_hour, tm->tm_min);
        }
        fprintf(stderr, "Modifications will be taken into account"
                " at %s.\n", buf);

        /* if fcrontabs is too long, snprintf will not be able to add "/fcrontab.sig"
         * string at the end of sigfile */
        if (strlen(fcrontabs) > (sizeof(sigfile) - sizeof("/fcrontab.sig")))
            die("fcrontabs string too long (more than %d characters)",
                (sizeof(sigfile) - sizeof("/fcrontab.sig")));
        snprintf(sigfile, sizeof(sigfile), "%s/fcrontab.sig", fcrontabs);

        switch (fork()) {
        case -1:
            remove(sigfile);
            die_e("could not fork : daemon has not been signaled");
            break;
        case 0:
            /* child */
            break;
        default:
            /* parent */
            return;
        }

        foreground = 0;

        /* try to create a lock file */
        /* // */
        debug("uid: %d, euid: %d, gid: %d, egid: %d", getuid(), geteuid(),
              getgid(), getegid());
        /* // */
        fd = open(sigfile, O_RDWR | O_CREAT, 0644);
        if (fd == -1)
            die_e("can't open or create %s", sigfile);
        fp = fdopen(fd, "r+");
        if (fp == NULL)
            die_e("can't fdopen %s", sigfile);


#ifdef HAVE_FLOCK
        if (flock(fd, LOCK_EX | LOCK_NB) != 0) {
            debug("fcrontab is already waiting for signalling the daemon :"
                  " exiting.");
            return;
        }
#else                           /* HAVE_FLOCK */
        if (lockf(fd, F_TLOCK, 0) != 0) {
            debug("fcrontab is already waiting for signalling the daemon :"
                  " exiting.");
            return;
        }
#endif                          /* ! HAVE_FLOCK */

        sleep(sl);

        /* also closes the underlying file descriptor fd: */
        xfclose_check(&fp, sigfile);
        /* also reset fd, now closed by xfclose_check(), to make it clear it is closed */
        fd = -1;

        if (remove(sigfile) < 0)
            error_e("Could not remove %s");
    }
    else
        /* we are root */
        fprintf(stderr,
                "Modifications will be taken into account" " right now.\n");

    if ((daemon_pid = read_pid()) == 0)
        /* daemon is not running any longer : we exit */
        return;

    foreground = 1;

#ifdef USE_SETE_ID
    if (seteuid(rootuid) != 0)
        error_e("seteuid(rootuid)");
#endif                          /* USE_SETE_ID */

    if (kill(daemon_pid, SIGHUP) != 0)
        die_e("could not send SIGHUP to daemon (pid %d)", daemon_pid);

#ifdef USE_SETE_ID
    /* get user's permissions */
    if (seteuid(fcrontab_uid) != 0)
        die_e("Could not change euid to " USERNAME "[%d]", uid);
#endif                          /* USE_SETE_ID */

}
示例#26
0
int main(int argc, char *argv[])
{
    int sock;
    struct sockaddr_un serv;
    const char *sockname;
    int use_stdin=1;
    char res;
    int n;
    
    if(argc>1){
        if(argc!=3 || strcmp(argv[1], "-e")!=0)
            die("Usage: notionflux [-e code]");
            
        if(strlen(argv[2])>=MAX_DATA)
            die("Too much data.");
        
        use_stdin=0;
    }
        
    sockname=get_socket();
    if(sockname==NULL)
        die("No socket.");
    
    if(strlen(sockname)>SOCK_MAX)
        die("Socket name too long.");
    
    sock=socket(AF_UNIX, SOCK_STREAM, 0);
    if(sock<0)
        die_e("Opening socket");
 
    serv.sun_family=AF_UNIX;
    strcpy(serv.sun_path, sockname);
    
    if(connect(sock, (struct sockaddr*)&serv, sizeof(struct sockaddr_un))<0)
        die_e("Connecting socket");
    
    if(!use_stdin){
        mywrite(sock, argv[2], strlen(argv[2])+1);
    }else{
        char c='\0';
        while(1){
            if(fgets(buf, MAX_DATA, stdin)==NULL)
                break;
            mywrite(sock, buf, strlen(buf));
        }
        mywrite(sock, &c, 1);
    }

    n=myread(sock, &res, 1);
    
    if(n!=1 || (res!='E' && res!='S'))
        die("Invalid response");

    while(1){
        n=myread(sock, buf, MAX_DATA);
        
        if(n==0)
            break;
        
        if(res=='S')
            mywrite(1, buf, n);
        else /* res=='E' */
            mywrite(2, buf, n);
        
        if(n<MAX_DATA)
            break;
    }

    return 0;
}