Use functions instead of preprocessor abuse.

This commit is contained in:
dholland 2016-03-13 00:32:09 +00:00
parent b247a5c33c
commit d9047ae69b
8 changed files with 183 additions and 98 deletions

View File

@ -1,11 +1,15 @@
# $NetBSD: Makefile,v 1.14 2011/08/16 10:35:03 christos Exp $
# $NetBSD: Makefile,v 1.15 2016/03/13 00:32:09 dholland Exp $
.include <bsd.own.mk>
PROG= atrun
SRCS= atrun.c
BINDIR= /usr/libexec
MAN= atrun.8
.PATH.c: ${NETBSDSRCDIR}/usr.bin/at
SRCS+= privs.c
CPPFLAGS+= -I${NETBSDSRCDIR}/usr.bin/at
COPTS.atrun.c = -Wno-format-nonliteral

View File

@ -1,4 +1,4 @@
/* $NetBSD: atrun.c,v 1.21 2011/09/16 16:13:17 plunky Exp $ */
/* $NetBSD: atrun.c,v 1.22 2016/03/13 00:32:09 dholland Exp $ */
/*
* atrun.c - run jobs queued by at; run with root privileges.
@ -49,7 +49,6 @@
/* Local headers */
#define MAIN
#include "privs.h"
#include "pathnames.h"
#include "atrun.h"
@ -59,7 +58,7 @@
#if 0
static char rcsid[] = "$OpenBSD: atrun.c,v 1.7 1997/09/08 22:12:10 millert Exp $";
#else
__RCSID("$NetBSD: atrun.c,v 1.21 2011/09/16 16:13:17 plunky Exp $");
__RCSID("$NetBSD: atrun.c,v 1.22 2016/03/13 00:32:09 dholland Exp $");
#endif
static int debug = 0;
@ -108,6 +107,12 @@ perrx(const char *fmt, ...)
exit(EXIT_FAILURE);
}
__dead void
privs_fail(const char *msg)
{
perr("%s", msg);
}
static int
write_string(int fd, const char *a)
{
@ -160,12 +165,12 @@ run_file(const char *filename, uid_t uid, gid_t gid)
gid_t ngid;
int serrno;
PRIV_START;
privs_enter();
if (chmod(filename, S_IRUSR) == -1)
perr("Cannot change file permissions to `%s'", filename);
PRIV_END;
privs_exit();
pid = fork();
if (pid == -1)
@ -184,12 +189,12 @@ run_file(const char *filename, uid_t uid, gid_t gid)
perrx("Userid %lu not found - aborting job `%s'",
(unsigned long)uid, filename);
PRIV_START;
privs_enter();
stream = fopen(filename, "r");
serrno = errno;
PRIV_END;
privs_exit();
if (stream == NULL) {
errno = serrno;
@ -206,12 +211,12 @@ run_file(const char *filename, uid_t uid, gid_t gid)
if (fstat(fd_in, &buf) == -1)
perr("Error in fstat of input file descriptor");
PRIV_START;
privs_enter();
if (lstat(filename, &lbuf) == -1)
perr("Error in lstat of `%s'", filename);
PRIV_END;
privs_exit();
if (S_ISLNK(lbuf.st_mode))
perrx("Symbolic link encountered in job `%s' - aborting",
@ -253,7 +258,7 @@ run_file(const char *filename, uid_t uid, gid_t gid)
(void)fclose(stream);
PRIV_START;
privs_enter();
if (chdir(_PATH_ATSPOOL) == -1)
perr("Cannot chdir to `%s'", _PATH_ATSPOOL);
@ -267,7 +272,7 @@ run_file(const char *filename, uid_t uid, gid_t gid)
O_WRONLY | O_CREAT | O_EXCL, S_IWUSR | S_IRUSR)) == -1)
perr("Cannot create output file `%s'", filename);
PRIV_END;
privs_exit();
write_string(fd_out, "To: ");
write_string(fd_out, mailname);
@ -309,7 +314,7 @@ run_file(const char *filename, uid_t uid, gid_t gid)
(void)close(fd_in);
(void)close(fd_out);
PRIV_START;
privs_enter();
if (chdir(_PATH_ATJOBS) == -1)
perr("Cannot chdir to `%s'", _PATH_ATJOBS);
@ -333,7 +338,7 @@ run_file(const char *filename, uid_t uid, gid_t gid)
* Send mail. Unlink the output file first, so it is deleted
* after the run.
*/
PRIV_START;
privs_enter();
if (stat(filename, &buf) == -1)
perr("Error in stat of output file `%s'", filename);
@ -342,12 +347,12 @@ run_file(const char *filename, uid_t uid, gid_t gid)
(void)unlink(filename);
PRIV_END;
privs_exit();
if ((buf.st_size != size) || send_mail) {
/* Fork off a child for sending mail */
PRIV_START;
privs_enter();
become_user(pentry, uid);
@ -355,7 +360,7 @@ run_file(const char *filename, uid_t uid, gid_t gid)
"-odi", "-oem", "-t", (char *) NULL);
perr("Exec failed for mail command `%s'", _PATH_SENDMAIL);
PRIV_END;
privs_exit();
}
exit(EXIT_SUCCESS);
}
@ -406,7 +411,7 @@ main(int argc, char *argv[])
* We don't need root privileges all the time; running under uid
* and gid nobody is fine except for privileged operations.
*/
RELINQUISH_PRIVS_ROOT(pwd->pw_uid, grp->gr_gid);
privs_relinquish_root(pwd->pw_uid, grp->gr_gid);
opterr = 0;
errno = 0;
@ -433,7 +438,7 @@ main(int argc, char *argv[])
}
}
PRIV_START;
privs_enter();
if (chdir(_PATH_ATJOBS) == -1)
perr("Cannot change directory to `%s'", _PATH_ATJOBS);
@ -453,7 +458,7 @@ main(int argc, char *argv[])
if ((spool = opendir(".")) == NULL)
perr("Cannot open `%s'", _PATH_ATJOBS);
PRIV_END;
privs_exit();
now = time(NULL);
run_batch = 0;
@ -461,13 +466,13 @@ main(int argc, char *argv[])
batch_gid = (gid_t) -1;
while ((dirent = readdir(spool)) != NULL) {
PRIV_START;
privs_enter();
if (stat(dirent->d_name, &buf) == -1)
perr("Cannot stat `%s' in `%s'", dirent->d_name,
_PATH_ATJOBS);
PRIV_END;
privs_exit();
/* We don't want directories */
if (!S_ISREG(buf.st_mode))
@ -498,11 +503,11 @@ main(int argc, char *argv[])
/* Delete older files */
if ((run_time < now) && !(S_IXUSR & buf.st_mode) &&
(S_IRUSR & buf.st_mode)) {
PRIV_START;
privs_enter();
(void)unlink(dirent->d_name);
PRIV_END;
privs_exit();
}
}

View File

@ -1,9 +1,9 @@
# $NetBSD: Makefile,v 1.11 2009/04/14 22:15:17 lukem Exp $
# $NetBSD: Makefile,v 1.12 2016/03/13 00:32:09 dholland Exp $
USE_FORT?= yes # setuid
PROG= at
SRCS= at.c panic.c parsetime.c perm.c stime.c
SRCS= at.c panic.c parsetime.c perm.c privs.c stime.c
LINKS= ${BINDIR}/at ${BINDIR}/atq \
${BINDIR}/at ${BINDIR}/atrm \
${BINDIR}/at ${BINDIR}/batch

View File

@ -1,4 +1,4 @@
/* $NetBSD: at.c,v 1.30 2011/08/29 14:24:03 joerg Exp $ */
/* $NetBSD: at.c,v 1.31 2016/03/13 00:32:09 dholland Exp $ */
/*
* at.c : Put file into atrun queue
@ -57,7 +57,6 @@
#include "perm.h"
#include "pathnames.h"
#include "stime.h"
#define MAIN
#include "privs.h"
/* Macros */
@ -72,7 +71,7 @@ enum { ATQ, ATRM, AT, BATCH, CAT }; /* what program we want to run */
#if 0
static char rcsid[] = "$OpenBSD: at.c,v 1.15 1998/06/03 16:20:26 deraadt Exp $";
#else
__RCSID("$NetBSD: at.c,v 1.30 2011/08/29 14:24:03 joerg Exp $");
__RCSID("$NetBSD: at.c,v 1.31 2016/03/13 00:32:09 dholland Exp $");
#endif
#endif
@ -108,9 +107,9 @@ sigc(int signo)
/* If a signal interrupts us, remove the spool file and exit. */
if (fcreated) {
PRIV_START;
privs_enter();
(void)unlink(atfile);
PRIV_END;
privs_exit();
}
(void)raise_default_signal(signo);
exit(EXIT_FAILURE);
@ -207,7 +206,7 @@ writefile(time_t runtimer, unsigned char queue)
* to make sure we're alone when doing this.
*/
PRIV_START;
privs_enter();
if ((lockdes = open(_PATH_LOCKFILE, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR)) < 0)
perr("Cannot open lockfile " _PATH_LOCKFILE);
@ -260,7 +259,7 @@ writefile(time_t runtimer, unsigned char queue)
if (fchown(fd2, real_uid, real_gid) == -1)
perr("Cannot give away file");
PRIV_END;
privs_exit();
/*
* We've successfully created the file; let's set the flag so it
@ -402,7 +401,7 @@ writefile(time_t runtimer, unsigned char queue)
(void)fclose(fp);
PRIV_START;
privs_enter();
/*
* Set the x bit so that we're ready to start executing
@ -410,7 +409,7 @@ writefile(time_t runtimer, unsigned char queue)
if (fchmod(fd2, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
perr("Cannot give away file");
PRIV_END;
privs_exit();
(void)close(fd2);
(void)fprintf(stderr,
@ -436,7 +435,7 @@ list_jobs(void)
char timestr[TIMESIZE];
int first = 1;
PRIV_START;
privs_enter();
if (chdir(_PATH_ATJOBS) == -1)
perr("Cannot change to " _PATH_ATJOBS);
@ -493,7 +492,7 @@ list_jobs(void)
jobno);
}
(void)closedir(spool);
PRIV_END;
privs_exit();
}
static void
@ -508,7 +507,7 @@ process_jobs(int argc, char **argv, int what)
unsigned char queue;
int jobno;
PRIV_START;
privs_enter();
if (chdir(_PATH_ATJOBS) == -1)
perr("Cannot change to " _PATH_ATJOBS);
@ -516,15 +515,15 @@ process_jobs(int argc, char **argv, int what)
if ((spool = opendir(".")) == NULL)
perr("Cannot open " _PATH_ATJOBS);
PRIV_END;
privs_exit();
/* Loop over every file in the directory */
while((dirent = readdir(spool)) != NULL) {
PRIV_START;
privs_enter();
if (stat(dirent->d_name, &buf) == -1)
perr("Cannot stat in " _PATH_ATJOBS);
PRIV_END;
privs_exit();
if (sscanf(dirent->d_name, "%c%5x%8lx", &queue, &jobno, &ctm) !=3)
continue;
@ -537,23 +536,23 @@ process_jobs(int argc, char **argv, int what)
switch (what) {
case ATRM:
PRIV_START;
privs_enter();
if (unlink(dirent->d_name) == -1)
perr(dirent->d_name);
PRIV_END;
privs_exit();
break;
case CAT: {
FILE *fp;
int ch;
PRIV_START;
privs_enter();
fp = fopen(dirent->d_name, "r");
PRIV_END;
privs_exit();
if (!fp)
perr("Cannot open file");
@ -593,7 +592,7 @@ main(int argc, char **argv)
int disp_version = 0;
time_t timer;
RELINQUISH_PRIVS;
privs_relinquish();
/* Eat any leading paths */
if ((pgm = strrchr(argv[0], '/')) == NULL)

View File

@ -1,4 +1,4 @@
/* $NetBSD: panic.c,v 1.13 2008/04/05 16:26:57 christos Exp $ */
/* $NetBSD: panic.c,v 1.14 2016/03/13 00:32:09 dholland Exp $ */
/*
* panic.c - terminate fast in case of error
@ -46,7 +46,7 @@
#if 0
static char rcsid[] = "$OpenBSD: panic.c,v 1.4 1997/03/01 23:40:09 millert Exp $";
#else
__RCSID("$NetBSD: panic.c,v 1.13 2008/04/05 16:26:57 christos Exp $");
__RCSID("$NetBSD: panic.c,v 1.14 2016/03/13 00:32:09 dholland Exp $");
#endif
#endif
@ -61,9 +61,9 @@ panic(const char *a)
* Something fatal has happened, print error message and exit.
*/
if (fcreated) {
PRIV_START;
privs_enter();
(void)unlink(atfile);
PRIV_END;
privs_exit();
}
errx(EXIT_FAILURE, "%s", a);
}
@ -78,13 +78,20 @@ perr(const char *a)
*/
perror(a);
if (fcreated) {
PRIV_START;
privs_enter();
(void)unlink(atfile);
PRIV_END;
privs_exit();
}
exit(EXIT_FAILURE);
}
__dead
void
privs_fail(const char *msg)
{
perr(msg);
}
__dead
void
usage(void)

View File

@ -1,4 +1,4 @@
/* $NetBSD: perm.c,v 1.3 2008/04/05 16:26:57 christos Exp $ */
/* $NetBSD: perm.c,v 1.4 2016/03/13 00:32:09 dholland Exp $ */
/*
* perm.c - check user permission for at(1)
@ -51,7 +51,7 @@
#if 0
static char rcsid[] = "$OpenBSD: perm.c,v 1.1 1997/03/01 23:40:12 millert Exp $";
#else
__RCSID("$NetBSD: perm.c,v 1.3 2008/04/05 16:26:57 christos Exp $");
__RCSID("$NetBSD: perm.c,v 1.4 2016/03/13 00:32:09 dholland Exp $");
#endif
#endif
@ -96,20 +96,20 @@ check_permission(void)
exit(EXIT_FAILURE);
}
PRIV_START;
privs_enter();
fp = fopen(_PATH_AT_ALLOW, "r");
PRIV_END;
privs_exit();
if (fp != NULL) {
return check_for_user(fp, pentry->pw_name);
} else {
PRIV_START;
privs_enter();
fp = fopen(_PATH_AT_DENY, "r");
PRIV_END;
privs_exit();
if (fp != NULL)
return !check_for_user(fp, pentry->pw_name);

99
usr.bin/at/privs.c Normal file
View File

@ -0,0 +1,99 @@
/* $NetBSD: privs.c,v 1.1 2016/03/13 00:32:09 dholland Exp $ */
/*
* privs.c - privileged operations
* Copyright (C) 1993 Thomas Koenig
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author(s) may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* From: OpenBSD: privs.h,v 1.4 1997/03/01 23:40:12 millert Exp
*/
#include <unistd.h>
#include "privs.h"
/*
* Relinquish privileges temporarily for a setuid or setgid program
* with the option of getting them back later. This is done by
* using POSIX saved user and groups ids. Call RELINQUISH_PRIVS once
* at the beginning of the main program. This will cause all operations
* to be executed with the real userid. When you need the privileges
* of the setuid/setgid invocation, call PRIV_START; when you no longer
* need it, call PRIV_END. Note that it is an error to call PRIV_START
* and not PRIV_END within the same function.
*
* Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running
* as root, and you want to drop back the effective userid to a
* and the effective group id to b, with the option to get them back
* later.
*
* Problems: Do not use return between PRIV_START and PRIV_END; this
* will cause the program to continue running in an unprivileged
* state.
*
* It is NOT safe to call exec(), system() or popen() with a user-
* supplied program (i.e. without carefully checking PATH and any
* library load paths) with relinquished privileges; the called program
* can acquire them just as easily. Set both effective and real userid
* to the real userid before calling any of them.
*/
uid_t real_uid, effective_uid;
gid_t real_gid, effective_gid;
void
privs_enter(void)
{
if (seteuid(effective_uid) == -1)
privs_fail("Cannot get user privs");
if (setegid(effective_gid) == -1)
privs_fail("Cannot get group privs");
}
void
privs_exit(void)
{
if (setegid(real_gid) == -1)
privs_fail("Cannot relinguish group privs");
if (seteuid(real_uid) == -1)
privs_fail("Cannot relinguish user privs");
}
void
privs_relinquish(void)
{
real_uid = getuid();
effective_uid = geteuid();
real_gid = getgid();
effective_gid = getegid();
privs_exit();
}
void
privs_relinquish_root(uid_t ruid, gid_t rgid)
{
real_uid = ruid;
real_gid = rgid;
effective_uid = geteuid();
effective_gid = getegid();
privs_exit();
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: privs.h,v 1.8 2008/04/05 16:26:57 christos Exp $ */
/* $NetBSD: privs.h,v 1.9 2016/03/13 00:32:09 dholland Exp $ */
/*
* privs.h - header for privileged operations
@ -30,9 +30,8 @@
#ifndef _PRIVS_H_
#define _PRIVS_H_
#include <unistd.h>
/* Relinquish privileges temporarily for a setuid or setgid program
/*
* Relinquish privileges temporarily for a setuid or setgid program
* with the option of getting them back later. This is done by
* using POSIX saved user and groups ids. Call RELINQUISH_PRIVS once
* at the beginning of the main program. This will cause all operations
@ -57,44 +56,16 @@
* to the real userid before calling any of them.
*/
#ifndef MAIN
extern
#endif
uid_t real_uid, effective_uid;
extern uid_t real_uid, effective_uid;
extern gid_t real_gid, effective_gid;
#ifndef MAIN
extern
#endif
gid_t real_gid, effective_gid;
void privs_relinquish(void);
void privs_relinquish_root(uid_t ruid, gid_t rgid);
#define RELINQUISH_PRIVS do { \
real_uid = getuid(); \
effective_uid = geteuid(); \
real_gid = getgid(); \
effective_gid = getegid(); \
PRIV_END; \
} while (/*CONSTCOND*/ 0)
void privs_enter(void);
void privs_exit(void);
#define RELINQUISH_PRIVS_ROOT(a, b) do { \
real_uid = (a); \
effective_uid = geteuid(); \
real_gid = (b); \
effective_gid = getegid(); \
PRIV_END; \
} while (/*CONSTCOND*/ 0)
#define PRIV_START do { \
if (seteuid(effective_uid) == -1) \
perr("Cannot get user privs"); \
if (setegid(effective_gid) == -1) \
perr("Cannot get group privs"); \
} while (/*CONSTCOND*/ 0)
#define PRIV_END do { \
if (setegid(real_gid) == -1) \
perr("Cannot relinguish group privs"); \
if (seteuid(real_uid) == -1) \
perr("Cannot relinguish user privs"); \
} while (/*CONSTCOND*/ 0)
/* caller provides this */
__dead void privs_fail(const char *msg);
#endif /* _PRIV_H_ */