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); }
void setup_user_and_env(struct cl_t *cl, struct passwd *pas, char ***sendmailenv, char ***jobenv, char **curshell, char **curhome, char **content_type, char **encoding) /* Check PAM authorization, and setup the environment variables * to run sendmail and to run the job itself. Change dir to HOME and check if SHELL is ok */ /* (*curshell) and (*curhome) will be allocated and should thus be freed * if curshell and curhome are not NULL. */ /* Return the the two env var sets, the shell to use to execle() commands and the home dir */ { env_list_t *env_list = env_list_init(); env_t *e = NULL; char *path = NULL; char *myshell = NULL; #ifdef HAVE_LIBPAM int retcode = 0; char **env; #endif if (pas == NULL) die("setup_user_and_env() called with a NULL struct passwd"); env_list_setenv(env_list, "USER", pas->pw_name, 1); env_list_setenv(env_list, "LOGNAME", pas->pw_name, 1); env_list_setenv(env_list, "HOME", pas->pw_dir, 1); /* inherit fcron's PATH for sendmail. We will later change it to DEFAULT_JOB_PATH * or a user defined PATH for the job itself */ path = getenv("PATH"); env_list_setenv(env_list, "PATH", (path != NULL) ? path : DEFAULT_JOB_PATH, 1); if (cl->cl_tz != NULL) env_list_setenv(env_list, "TZ", cl->cl_tz, 1); /* To ensure compatibility with Vixie cron, we don't use the shell defined * in /etc/passwd by default, but the default value from fcron.conf instead: */ if (shell != NULL && shell[0] != '\0') /* default: use value from fcron.conf */ env_list_setenv(env_list, "SHELL", shell, 1); else /* shell is empty, ie. not defined: fail back to /etc/passwd's value */ env_list_setenv(env_list, "SHELL", pas->pw_shell, 1); #if ( ! defined(RUN_NON_PRIVILEGED)) && defined(HAVE_LIBPAM) /* Open PAM session for the user and obtain any security * credentials we might need */ retcode = pam_start("fcron", pas->pw_name, &apamconv, &pamh); if (retcode != PAM_SUCCESS) die_pame(pamh, retcode, "Could not start PAM for '%s'", cl->cl_shell); /* Some system seem to need that pam_authenticate() call. * Anyway, we have no way to authentificate the user : * we must set auth to pam_permit. */ retcode = pam_authenticate(pamh, PAM_SILENT); if (retcode != PAM_SUCCESS) die_mail_pame(cl, retcode, pas, "Could not authenticate PAM user", env_list); retcode = pam_acct_mgmt(pamh, PAM_SILENT); /* permitted access? */ if (retcode != PAM_SUCCESS) die_mail_pame(cl, retcode, pas, "Could not init PAM account management", env_list); retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); if (retcode != PAM_SUCCESS) die_mail_pame(cl, retcode, pas, "Could not set PAM credentials", env_list); retcode = pam_open_session(pamh, PAM_SILENT); if (retcode != PAM_SUCCESS) die_mail_pame(cl, retcode, pas, "Could not open PAM session", env_list); for (env = pam_getenvlist(pamh); env && *env; env++) { env_list_putenv(env_list, *env, 1); } /* Close the log here, because PAM calls openlog(3) and * our log messages could go to the wrong facility */ xcloselog(); #endif /* ( ! defined(RUN_NON_PRIVILEGED)) && defined(HAVE_LIBPAM) */ /* export the environment for sendmail before we apply user customization */ if (sendmailenv != NULL) *sendmailenv = env_list_export_envp(env_list); /* Now add user customizations to the environment to form jobenv */ if (jobenv != NULL) { /* Make sure we don't keep fcron daemon's PATH (which we used for sendmail) */ env_list_setenv(env_list, "PATH", DEFAULT_JOB_PATH, 1); for (e = env_list_first(cl->cl_file->cf_env_list); e != NULL; e = env_list_next(cl->cl_file->cf_env_list)) { env_list_putenv(env_list, e->e_envvar, 1); } /* make sure HOME is defined */ env_list_putenv(env_list, "HOME=/", 0); /* don't overwrite if already defined */ if (curhome != NULL) { (*curhome) = strdup2(env_list_getenv(env_list, "HOME")); } /* check that SHELL is valid */ myshell = env_list_getenv(env_list, "SHELL"); if (myshell == NULL || myshell[0] == '\0') { myshell = shell; } else if (access(myshell, X_OK) != 0) { if (errno == ENOENT) error("shell \"%s\" : no file or directory. SHELL set to %s", myshell, shell); else error_e("shell \"%s\" not valid : SHELL set to %s", myshell, shell); myshell = shell; } env_list_setenv(env_list, "SHELL", myshell, 1); if (curshell != NULL) *curshell = strdup2(myshell); *jobenv = env_list_export_envp(env_list); } if (content_type != NULL) { (*content_type) = strdup2(env_list_getenv(env_list, "CONTENT_TYPE")); } if (encoding != NULL) { (*encoding) = strdup2(env_list_getenv(env_list, "CONTENT_TRANSFER_ENCODING")); } env_list_destroy(env_list); }
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; }