diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2004-12-22 17:11:53 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2004-12-22 17:11:53 +0000 |
commit | 558379a898cb3b6d88df1b70512b0da8beca3b7a (patch) | |
tree | e59138ac8408c412fff5159eb978cc632c1b64ee /src | |
parent | a937d33de16c39f2a613c9b33e77ab8066be2900 (diff) | |
download | ipacct-558379a898cb3b6d88df1b70512b0da8beca3b7a.tar.gz ipacct-558379a898cb3b6d88df1b70512b0da8beca3b7a.tar.bz2 |
(user): New variable
(options): New option --user
(parse_opt): Handle --user
(main): Change to non-root privileges.
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 130 |
1 files changed, 129 insertions, 1 deletions
@@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* $Id: main.c,v 1.5 2002/06/17 16:30:07 gray Exp $ */ +/* $Id: main.c,v 1.6 2004/12/22 17:11:53 gray Exp $ */ #if defined(HAVE_CONFIG_H) # include <config.h> #endif @@ -26,6 +26,7 @@ #include <sys/time.h> #include <stdlib.h> #include <unistd.h> +#include <pwd.h> #include <syslog.h> #include <time.h> #include <errno.h> @@ -73,6 +74,7 @@ static char *expr = NULL; static time_t ttw = 0; static int syntax_check = 0; /* check the config file and exit */ static int test_mode = 0; +char *user = NULL; const char *argp_program_version = "ipacct (" PACKAGE ") " VERSION; static char doc[] = "ip traffic accounting daemon"; @@ -106,6 +108,8 @@ static struct argp_option options[] = { "Increase verbosity level", 0 }, { "fixed-clocks", 'x', NULL, 0, "Dump statistics at precise time intervals", 0 }, + { "user", 'u', "USER-NAME", 0, + "Run with this user privileges", 0 }, {NULL, 0, NULL, 0, NULL, 0} }; @@ -165,6 +169,9 @@ parse_opt (key, arg, state) case 'x': fixed_clocks++; break; + case 'u': + user = optarg; + break; default: return ARGP_ERR_UNKNOWN; } @@ -180,6 +187,126 @@ static struct argp argp = { NULL, NULL }; +/* Change to the given uid/gid. Clear the supplementary group list. + On success returns 0. + On failure returns 1 (or exits, depending on topt settings. See + anubis_error) */ +static int +change_privs (uid_t uid, gid_t gid) +{ + int rc = 0; + gid_t emptygidset[1]; + + /* Reset group permissions */ + emptygidset[0] = gid ? gid : getegid(); + if (geteuid() == 0 && setgroups(1, emptygidset)) { + error ("setgroups(1, %lu) failed: %s", + (u_long) emptygidset[0], + strerror (errno)); + rc = 1; + } + + /* Switch to the user's gid. On some OSes the effective gid must + be reset first */ + +#if defined(HAVE_SETEGID) + if ((rc = setegid(gid)) < 0) + error ("setegid(%lu) failed: %s", + (u_long) gid, strerror (errno)); +#elif defined(HAVE_SETREGID) + if ((rc = setregid(gid, gid)) < 0) + error ("setregid(%lu,%lu) failed: %s", + (u_long) gid, (u_long) gid, strerror (errno)); +#elif defined(HAVE_SETRESGID) + if ((rc = setresgid(gid, gid, gid)) < 0) + error ("setresgid(%lu,%lu,%lu) failed: %s", + (u_long) gid, + (u_long) gid, + (u_long) gid, + strerror (errno)); +#endif + + if (rc == 0 && gid != 0) { + if ((rc = setgid(gid)) < 0 && getegid() != gid) + error ("setgid(%lu) failed: %s", + (u_long) gid, + strerror (errno)); + if (rc == 0 && getegid() != gid) { + error("cannot set effective gid to %lu: %s", + (u_long) gid, + strerror (errno)); + rc = 1; + } + } + + /* now reset uid */ + if (rc == 0 && uid != 0) { + uid_t euid; + + if (setuid(uid) + || geteuid() != uid + || (getuid() != uid + && (geteuid() == 0 || getuid() == 0))) { + +#if defined(have_setreuid) + if (geteuid() != uid) { + if (setreuid(uid, -1) < 0) { + syslog (log_error, + "setreuid(%lu,-1) failed: %s", + (u_long) uid, + strerror (errno)); + rc = 1; + } + if (setuid(uid) < 0) { + syslog (log_error, + "second setuid(%lu) failed: %s", + (u_long) uid, + strerror (errno)); + rc = 1; + } + } else +#endif + { + error ("setuid(%lu) failed: %s", + (u_long) uid, + strerror (errno)); + rc = 1; + } + } + + + euid = geteuid(); + if (uid != 0 && setuid(0) == 0) { + error ("seteuid(0) succeeded when it should not"); + rc = 1; + } else if (uid != euid && setuid(euid) == 0) { + error ("cannot drop non-root setuid privileges"); + rc = 1; + } + } + return rc; +} + +void +change_user () +{ + struct passwd *pwd; + + if (user == NULL) + return; + + pwd = getpwnam (user); + if (pwd) { + if (change_privs (pwd->pw_uid, pwd->pw_gid)) + exit (1); + + chdir (pwd->pw_dir); + syslog (LOG_INFO, "UID:%d (%s), GID:%d, EUID:%d, EGID:%d", + (int) getuid (), pwd->pw_name, (int) getgid (), + (int) geteuid (), (int) getegid ()); + } +} + int main(argc, argv) int argc; @@ -245,6 +372,7 @@ main(argc, argv) init_syslog(); } + change_user(); run(pcap, callback); cleanup(); |