privs.h revision 249404
1139743Simp/*
239212Sgibbs *  privs.h - header for privileged operations
339212Sgibbs *  Copyright (C) 1993  Thomas Koenig
439212Sgibbs *
539212Sgibbs * Redistribution and use in source and binary forms, with or without
639212Sgibbs * modification, are permitted provided that the following conditions
739212Sgibbs * are met:
839212Sgibbs * 1. Redistributions of source code must retain the above copyright
939212Sgibbs *    notice, this list of conditions and the following disclaimer.
1039212Sgibbs * 2. The name of the author(s) may not be used to endorse or promote
1139212Sgibbs *    products derived from this software without specific prior written
1239212Sgibbs *    permission.
1339212Sgibbs *
1439212Sgibbs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1539212Sgibbs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1639212Sgibbs * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1739212Sgibbs * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1839212Sgibbs * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1939212Sgibbs * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2039212Sgibbs * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2139212Sgibbs * THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2239212Sgibbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2339212Sgibbs * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2439212Sgibbs *
2539212Sgibbs * $FreeBSD: head/usr.bin/at/privs.h 249404 2013-04-12 14:19:44Z gahr $
2639212Sgibbs */
2739212Sgibbs
2850477Speter#ifndef _PRIVS_H
2939212Sgibbs#define _PRIVS_H
3039212Sgibbs
3139212Sgibbs#include <unistd.h>
3239212Sgibbs
3339212Sgibbs/* Relinquish privileges temporarily for a setuid or setgid program
3455206Speter * with the option of getting them back later.  This is done by
3539212Sgibbs * utilizing POSIX saved user and group IDs.  Call RELINQUISH_PRIVS once
3639212Sgibbs * at the beginning of the main program.  This will cause all operations
3739212Sgibbs * to be executed with the real userid.  When you need the privileges
3839212Sgibbs * of the setuid/setgid invocation, call PRIV_START; when you no longer
3939212Sgibbs * need it, call PRIV_END.  Note that it is an error to call PRIV_START
4039212Sgibbs * and not PRIV_END within the same function.
4139212Sgibbs *
4239212Sgibbs * Use RELINQUISH_PRIVS_ROOT(a,b) if your program started out running
4339212Sgibbs * as root, and you want to drop back the effective userid to a
4439212Sgibbs * and the effective group id to b, with the option to get them back
4539212Sgibbs * later.
4639212Sgibbs *
4739212Sgibbs * If you no longer need root privileges, but those of some other
4839212Sgibbs * userid/groupid, you can call REDUCE_PRIV(a,b) when your effective
4939212Sgibbs * is the user's.
5039212Sgibbs *
5139212Sgibbs * Problems: Do not use return between PRIV_START and PRIV_END; this
5239212Sgibbs * will cause the program to continue running in an unprivileged
5339212Sgibbs * state.
5439212Sgibbs *
5539212Sgibbs * It is NOT safe to call exec(), system() or popen() with a user-
5671507Sjhb * supplied program (i.e. without carefully checking PATH and any
5739212Sgibbs * library load paths) with relinquished privileges; the called program
5839212Sgibbs * can acquire them just as easily.  Set both effective and real userid
5946581Sken * to the real userid before calling any of them.
6046581Sken */
6139212Sgibbs
6239212Sgibbsextern uid_t real_uid, effective_uid;
6339212Sgibbsextern gid_t real_gid, effective_gid;
6439212Sgibbs
6539212Sgibbs#ifdef MAIN
6639212Sgibbsuid_t real_uid, effective_uid;
6739212Sgibbsgid_t real_gid, effective_gid;
6839212Sgibbs#endif
6939212Sgibbs
7071507Sjhb#define RELINQUISH_PRIVS { \
7171507Sjhb	real_uid = getuid(); \
7271507Sjhb	effective_uid = geteuid(); \
7371507Sjhb	real_gid = getgid(); \
7471507Sjhb	effective_gid = getegid(); \
7539212Sgibbs	if (seteuid(real_uid) != 0) err(1, "seteuid failed"); \
7639212Sgibbs	if (setegid(real_gid) != 0) err(1, "setegid failed"); \
7739212Sgibbs}
7839212Sgibbs
7939212Sgibbs#define RELINQUISH_PRIVS_ROOT(a, b) { \
8039212Sgibbs	real_uid = (a); \
8139212Sgibbs	effective_uid = geteuid(); \
8239212Sgibbs	real_gid = (b); \
8339212Sgibbs	effective_gid = getegid(); \
8439212Sgibbs	if (setegid(real_gid) != 0) err(1, "setegid failed"); \
8539212Sgibbs	if (seteuid(real_uid) != 0) err(1, "seteuid failed"); \
8639212Sgibbs}
8739212Sgibbs
8839212Sgibbs#define PRIV_START { \
8939212Sgibbs	if (seteuid(effective_uid) != 0) err(1, "seteuid failed"); \
9039212Sgibbs	if (setegid(effective_gid) != 0) err(1, "setegid failed"); \
9171507Sjhb}
9239212Sgibbs
9339212Sgibbs#define PRIV_END { \
9439212Sgibbs	if (setegid(real_gid) != 0) err(1, "setegid failed"); \
9539212Sgibbs	if (seteuid(real_uid) != 0) err(1, "seteuid failed"); \
9646581Sken}
9746581Sken
9839212Sgibbs#define REDUCE_PRIV(a, b) { \
9939212Sgibbs	PRIV_START \
10039212Sgibbs	effective_uid = (a); \
10139212Sgibbs	effective_gid = (b); \
10239212Sgibbs	if (setregid((gid_t)-1, effective_gid) != 0) err(1, "setregid failed"); \
10339212Sgibbs	if (setreuid((uid_t)-1, effective_uid) != 0) err(1, "setreuid failed"); \
10439212Sgibbs	PRIV_END \
10539212Sgibbs}
10639212Sgibbs#endif
10739212Sgibbs