You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
426 lines
12 KiB
426 lines
12 KiB
diff -up at-3.1.13/at.c.pam at-3.1.13/at.c |
|
--- at-3.1.13/at.c.pam 2012-04-19 16:50:57.491000001 +0200 |
|
+++ at-3.1.13/at.c 2012-04-19 16:50:57.505000001 +0200 |
|
@@ -141,18 +141,13 @@ sigc(int signo) |
|
/* If the user presses ^C, remove the spool file and exit |
|
*/ |
|
if (fcreated) { |
|
- /* |
|
PRIV_START |
|
- |
|
+ /* |
|
We need the unprivileged uid here since the file is owned by the real |
|
(not effective) uid. |
|
*/ |
|
- setregid(real_gid, effective_gid); |
|
- unlink(atfile); |
|
- setregid(effective_gid, real_gid); |
|
- /* |
|
+ unlink(atfile); |
|
PRIV_END |
|
- */ |
|
} |
|
exit(EXIT_FAILURE); |
|
} |
|
@@ -318,26 +313,19 @@ writefile(time_t runtimer, char queue) |
|
* bit. Yes, this is a kluge. |
|
*/ |
|
cmask = umask(S_IRUSR | S_IWUSR | S_IXUSR); |
|
- seteuid(real_uid); |
|
+ if ((seteuid(effective_uid)) < 0) |
|
+ perr("Error in seteuid: %s", errno); |
|
if ((fd = open(atfile, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, S_IRUSR)) == -1) |
|
perr("Cannot create atjob file %.500s", atfile); |
|
- seteuid(effective_uid); |
|
|
|
if ((fd2 = dup(fd)) < 0) |
|
perr("Error in dup() of job file"); |
|
|
|
- /* |
|
if (fchown(fd2, real_uid, real_gid) != 0) |
|
- perr("Cannot give away file"); |
|
- */ |
|
+ perr("Cannot give real_uid and real_gid the file"); |
|
|
|
PRIV_END |
|
|
|
- /* We no longer need suid root; now we just need to be able to write |
|
- * to the directory, if necessary. |
|
- */ |
|
- |
|
- REDUCE_PRIV(daemon_uid, daemon_gid) |
|
/* We've successfully created the file; let's set the flag so it |
|
* gets removed in case of an interrupt or error. |
|
*/ |
|
@@ -661,7 +649,7 @@ process_jobs(int argc, char **argv, int |
|
We need the unprivileged uid here since the file is owned by the real |
|
(not effective) uid. |
|
*/ |
|
- setregid(real_gid, effective_gid); |
|
+ PRIV_START |
|
|
|
if (queue == '=') { |
|
fprintf(stderr, "Warning: deleting running job\n"); |
|
@@ -670,8 +658,8 @@ process_jobs(int argc, char **argv, int |
|
perr("Cannot unlink %.500s", dirent->d_name); |
|
rc = EXIT_FAILURE; |
|
} |
|
+ PRIV_END |
|
|
|
- setregid(effective_gid, real_gid); |
|
done = 1; |
|
|
|
break; |
|
@@ -681,7 +669,7 @@ process_jobs(int argc, char **argv, int |
|
FILE *fp; |
|
int ch; |
|
|
|
- setregid(real_gid, effective_gid); |
|
+ PRIV_START |
|
fp = fopen(dirent->d_name, "r"); |
|
|
|
if (fp) { |
|
@@ -694,7 +682,7 @@ process_jobs(int argc, char **argv, int |
|
perr("Cannot open %.500s", dirent->d_name); |
|
rc = EXIT_FAILURE; |
|
} |
|
- setregid(effective_gid, real_gid); |
|
+ PRIV_END |
|
} |
|
break; |
|
|
|
diff -up at-3.1.13/atd.c.pam at-3.1.13/atd.c |
|
--- at-3.1.13/atd.c.pam 2012-04-19 16:50:57.498000001 +0200 |
|
+++ at-3.1.13/atd.c 2012-04-19 16:52:37.209000138 +0200 |
|
@@ -111,7 +111,7 @@ static int run_as_daemon = 0; |
|
|
|
static volatile sig_atomic_t term_signal = 0; |
|
|
|
-#ifdef HAVE_PAM |
|
+#ifdef WITH_PAM |
|
#include <security/pam_appl.h> |
|
|
|
static pam_handle_t *pamh = NULL; |
|
@@ -120,15 +120,7 @@ static const struct pam_conv conv = { |
|
NULL |
|
}; |
|
|
|
-#define PAM_FAIL_CHECK if (retcode != PAM_SUCCESS) { \ |
|
- fprintf(stderr,"\n%s\n",pam_strerror(pamh, retcode)); \ |
|
- syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \ |
|
- pam_end(pamh, retcode); exit(1); \ |
|
- } |
|
-#define PAM_END { retcode = pam_close_session(pamh,0); \ |
|
- pam_end(pamh,retcode); } |
|
- |
|
-#endif /* HAVE_PAM */ |
|
+#endif /* WITH_PAM */ |
|
|
|
/* Signal handlers */ |
|
RETSIGTYPE |
|
@@ -235,7 +227,7 @@ run_file(const char *filename, uid_t uid |
|
char fmt[64]; |
|
unsigned long jobno; |
|
int rc; |
|
-#ifdef HAVE_PAM |
|
+#ifdef WITH_PAM |
|
int retcode; |
|
#endif |
|
|
|
@@ -395,17 +387,11 @@ run_file(const char *filename, uid_t uid |
|
fstat(fd_out, &buf); |
|
size = buf.st_size; |
|
|
|
-#ifdef HAVE_PAM |
|
- PRIV_START |
|
- retcode = pam_start("atd", pentry->pw_name, &conv, &pamh); |
|
- PAM_FAIL_CHECK; |
|
- retcode = pam_acct_mgmt(pamh, PAM_SILENT); |
|
- PAM_FAIL_CHECK; |
|
- retcode = pam_open_session(pamh, PAM_SILENT); |
|
- PAM_FAIL_CHECK; |
|
- retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); |
|
- PAM_FAIL_CHECK; |
|
- PRIV_END |
|
+#ifdef WITH_PAM |
|
+ AT_START_PAM; |
|
+ AT_OPEN_PAM_SESSION; |
|
+ closelog(); |
|
+ openlog("atd", LOG_PID, LOG_ATD); |
|
#endif |
|
|
|
close(STDIN_FILENO); |
|
@@ -419,7 +405,14 @@ run_file(const char *filename, uid_t uid |
|
else if (pid == 0) { |
|
char *nul = NULL; |
|
char **nenvp = &nul; |
|
+ char **pam_envp=0L; |
|
|
|
+ PRIV_START |
|
+#ifdef WITH_PAM |
|
+ pam_envp = pam_getenvlist(pamh); |
|
+ if ( ( pam_envp != 0L ) && (pam_envp[0] != 0L) ) |
|
+ nenvp = pam_envp; |
|
+#endif |
|
/* Set up things for the child; we want standard input from the |
|
* input file, and standard output and error sent to our output file. |
|
*/ |
|
@@ -438,8 +431,6 @@ run_file(const char *filename, uid_t uid |
|
close(fd_in); |
|
close(fd_out); |
|
|
|
- PRIV_START |
|
- |
|
nice((tolower((int) queue) - 'a' + 1) * 2); |
|
|
|
if (initgroups(pentry->pw_name, pentry->pw_gid)) |
|
@@ -458,7 +449,16 @@ run_file(const char *filename, uid_t uid |
|
|
|
if (execle("/bin/sh", "sh", (char *) NULL, nenvp) != 0) |
|
perr("Exec failed for /bin/sh"); |
|
- |
|
+#ifdef WITH_PAM |
|
+ if ( ( nenvp != &nul ) && (pam_envp != 0L) && (*pam_envp != 0L)) |
|
+ { |
|
+ for( nenvp = pam_envp; *nenvp != 0L; nenvp++) |
|
+ free(*nenvp); |
|
+ free( pam_envp ); |
|
+ nenvp = &nul; |
|
+ pam_envp=0L; |
|
+ } |
|
+#endif |
|
PRIV_END |
|
} |
|
/* We're the parent. Let's wait. |
|
@@ -471,14 +471,6 @@ run_file(const char *filename, uid_t uid |
|
*/ |
|
waitpid(pid, (int *) NULL, 0); |
|
|
|
-#ifdef HAVE_PAM |
|
- PRIV_START |
|
- pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); |
|
- retcode = pam_close_session(pamh, PAM_SILENT); |
|
- pam_end(pamh, retcode); |
|
- PRIV_END |
|
-#endif |
|
- |
|
/* Send mail. Unlink the output file after opening it, so it |
|
* doesn't hang around after the run. |
|
*/ |
|
@@ -509,8 +501,20 @@ run_file(const char *filename, uid_t uid |
|
unlink(newname); |
|
free(newname); |
|
|
|
+#ifdef ATD_MAIL_PROGRAM |
|
if (((send_mail != -1) && (buf.st_size != size)) || (send_mail == 1)) { |
|
+ int mail_pid = -1; |
|
+#ifdef WITH_PAM |
|
+ AT_START_PAM; |
|
+ AT_OPEN_PAM_SESSION; |
|
+ closelog(); |
|
+ openlog("atd", LOG_PID, LOG_ATD); |
|
+#endif |
|
+ |
|
+ mail_pid = fork(); |
|
|
|
+ if ( mail_pid == 0 ) |
|
+ { |
|
PRIV_START |
|
|
|
if (initgroups(pentry->pw_name, pentry->pw_gid)) |
|
@@ -535,7 +539,21 @@ run_file(const char *filename, uid_t uid |
|
perr("Exec failed for mail command"); |
|
|
|
PRIV_END |
|
+ } |
|
+ else if ( mail_pid == -1 ) { |
|
+ perr("fork of mailer failed"); |
|
+ } |
|
+ else { |
|
+ /* Parent */ |
|
+ waitpid(mail_pid, (int *) NULL, 0); |
|
+ } |
|
+#ifdef WITH_PAM |
|
+ AT_CLOSE_PAM; |
|
+ closelog(); |
|
+ openlog("atd", LOG_PID, LOG_ATD); |
|
+#endif |
|
} |
|
+#endif |
|
exit(EXIT_SUCCESS); |
|
} |
|
|
|
diff -up at-3.1.13/config.h.in.pam at-3.1.13/config.h.in |
|
--- at-3.1.13/config.h.in.pam 2011-06-25 14:43:14.000000000 +0200 |
|
+++ at-3.1.13/config.h.in 2012-04-19 16:50:57.506000001 +0200 |
|
@@ -68,8 +68,8 @@ |
|
/* Define to 1 if you have the <nlist.h> header file. */ |
|
#undef HAVE_NLIST_H |
|
|
|
-/* Define to 1 for PAM support */ |
|
-#undef HAVE_PAM |
|
+/* Define if you are building with_pam */ |
|
+#undef WITH_PAM |
|
|
|
/* Define to 1 if you have the `pstat_getdynamic' function. */ |
|
#undef HAVE_PSTAT_GETDYNAMIC |
|
diff -up at-3.1.13/configure.ac.pam at-3.1.13/configure.ac |
|
--- at-3.1.13/configure.ac.pam 2011-06-25 14:43:14.000000000 +0200 |
|
+++ at-3.1.13/configure.ac 2012-04-19 16:50:57.506000001 +0200 |
|
@@ -84,7 +84,7 @@ AC_FUNC_GETLOADAVG |
|
AC_CHECK_FUNCS(getcwd mktime strftime setreuid setresuid sigaction waitpid) |
|
AC_CHECK_HEADERS(security/pam_appl.h, [ |
|
PAMLIB="-lpam" |
|
- AC_DEFINE(HAVE_PAM, 1, [Define to 1 for PAM support]) |
|
+ AC_DEFINE(WITH_PAM, 1, [Define to 1 for PAM support]) |
|
]) |
|
|
|
dnl Checking for programs |
|
@@ -238,6 +238,13 @@ AC_ARG_WITH(daemon_username, |
|
) |
|
AC_SUBST(DAEMON_USERNAME) |
|
|
|
+AC_ARG_WITH(pam, |
|
+[ --with-pam Define to enable pam support ], |
|
+AC_DEFINE(WITH_PAM), |
|
+) |
|
+AC_CHECK_LIB(pam, pam_start, PAMLIB='-lpam -lpam_misc') |
|
+AC_SUBST(PAMLIB) |
|
+ |
|
AC_MSG_CHECKING(groupname to run under) |
|
AC_ARG_WITH(daemon_groupname, |
|
[ --with-daemon_groupname=DAEMON_GROUPNAME Groupname to run under (default daemon) ], |
|
diff -up at-3.1.13/perm.c.pam at-3.1.13/perm.c |
|
--- at-3.1.13/perm.c.pam 2011-06-25 14:43:14.000000000 +0200 |
|
+++ at-3.1.13/perm.c 2012-04-19 16:53:09.192001742 +0200 |
|
@@ -51,6 +51,14 @@ |
|
#define PRIV_END while(0) |
|
#endif |
|
|
|
+#ifdef WITH_PAM |
|
+#include <security/pam_appl.h> |
|
+static pam_handle_t *pamh = NULL; |
|
+static const struct pam_conv conv = { |
|
+ NULL |
|
+}; |
|
+#endif |
|
+ |
|
/* Structures and unions */ |
|
|
|
|
|
@@ -108,18 +116,45 @@ user_in_file(const char *path, const cha |
|
int |
|
check_permission() |
|
{ |
|
- uid_t uid = geteuid(); |
|
+ uid_t euid = geteuid(), uid=getuid(), egid=getegid(), gid=getgid(); |
|
struct passwd *pentry; |
|
int allow = 0, deny = 1; |
|
|
|
- if (uid == 0) |
|
+ int retcode = 0; |
|
+ if (euid == 0) |
|
return 1; |
|
|
|
- if ((pentry = getpwuid(uid)) == NULL) { |
|
+ if ((pentry = getpwuid(euid)) == NULL) { |
|
perror("Cannot access user database"); |
|
exit(EXIT_FAILURE); |
|
} |
|
|
|
+#ifdef WITH_PAM |
|
+/* |
|
+ * We must check if the atd daemon userid will be allowed to gain the job owner user's |
|
+ * credentials with PAM . If not, the user has been denied at(1) usage, eg. with pam_access. |
|
+ */ |
|
+ if (setreuid(daemon_uid, daemon_uid) != 0) { |
|
+ fprintf(stderr, "cannot set egid: %s", strerror(errno)); |
|
+ exit(1); |
|
+ } |
|
+ if (setregid(daemon_gid, daemon_gid) != 0) { |
|
+ fprintf(stderr, "cannot set euid: %s", strerror(errno)); |
|
+ exit(1); |
|
+ } |
|
+ |
|
+ AT_START_PAM; |
|
+ AT_CLOSE_PAM; |
|
+ if (setregid(gid,egid) != 0) { |
|
+ fprintf(stderr, "cannot set egid: %s", strerror(errno)); |
|
+ exit(1); |
|
+ } |
|
+ if (setreuid(uid,euid) != 0) { |
|
+ fprintf(stderr, "cannot set euid: %s", strerror(errno)); |
|
+ exit(1); |
|
+ } |
|
+#endif |
|
+ |
|
allow = user_in_file(ETCDIR "/at.allow", pentry->pw_name); |
|
if (allow==0 || allow==1) |
|
return allow; |
|
diff -up at-3.1.13/privs.h.pam at-3.1.13/privs.h |
|
--- at-3.1.13/privs.h.pam 2011-06-25 14:43:14.000000000 +0200 |
|
+++ at-3.1.13/privs.h 2012-04-19 16:53:46.296016675 +0200 |
|
@@ -144,3 +144,63 @@ extern gid_t real_gid, effective_gid, da |
|
#error "Cannot implement user ID swapping without setreuid or setresuid" |
|
#endif |
|
#endif |
|
+ |
|
+#ifdef WITH_PAM |
|
+/* PAM failed after session was open. */ |
|
+#define PAM_SESSION_FAIL if (retcode != PAM_SUCCESS) \ |
|
+ pam_close_session(pamh,PAM_SILENT); |
|
+ |
|
+/* syslog will be logging error messages */ |
|
+#ifdef HAVE_UNISTD_H |
|
+#include <syslog.h> |
|
+#endif |
|
+ |
|
+/* PAM fail even before opening the session */ |
|
+#define PAM_FAIL_CHECK \ |
|
+ do { if (retcode != PAM_SUCCESS) { \ |
|
+ fprintf(stderr,"PAM failure: %s\n",pam_strerror(pamh, retcode)); \ |
|
+ syslog(LOG_ERR,"%s",pam_strerror(pamh, retcode)); \ |
|
+ if (pamh) \ |
|
+ pam_end(pamh, retcode); \ |
|
+ if (setregid(getgid(),getegid()) != 0) { \ |
|
+ fprintf(stderr, "cannot set egid: %s", strerror(errno)); \ |
|
+ exit(1); \ |
|
+ } \ |
|
+ if (setreuid(getuid(),geteuid()) != 0) { \ |
|
+ fprintf(stderr, "cannot set euid: %s", strerror(errno)); \ |
|
+ exit(1); \ |
|
+ } \ |
|
+ exit(1); \ |
|
+ } \ |
|
+ } while (0) \ |
|
+ |
|
+static int pam_session_opened = 0; //global for open session |
|
+ |
|
+#define AT_START_PAM { \ |
|
+ retcode = pam_start("atd", pentry->pw_name, &conv, &pamh); \ |
|
+ PAM_FAIL_CHECK; \ |
|
+ retcode = pam_set_item(pamh, PAM_TTY, "atd"); \ |
|
+ PAM_FAIL_CHECK; \ |
|
+ retcode = pam_acct_mgmt(pamh, PAM_SILENT); \ |
|
+ PAM_FAIL_CHECK; \ |
|
+} |
|
+ |
|
+#define AT_OPEN_PAM_SESSION { \ |
|
+ retcode = pam_open_session(pamh, PAM_SILENT); \ |
|
+ PAM_FAIL_CHECK; \ |
|
+ retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED | PAM_SILENT); \ |
|
+ PAM_FAIL_CHECK; \ |
|
+ if (retcode == PAM_SUCCESS) \ |
|
+ pam_session_opened = 1; \ |
|
+} |
|
+ |
|
+#define AT_CLOSE_PAM { \ |
|
+ if (pam_session_opened != 0) { \ |
|
+ pam_setcred(pamh, PAM_DELETE_CRED | PAM_SILENT); \ |
|
+ pam_close_session(pamh, PAM_SILENT); \ |
|
+ } \ |
|
+ pam_end(pamh, PAM_SUCCESS); \ |
|
+} |
|
+ |
|
+#endif |
|
+
|
|
|