/* $Id: startinnfeed.c 7065 2004-12-19 21:49:18Z rra $
**
** Raise system limits and exec innfeed.
**
** This is a setuid root wrapper around innfeed to increase system limits
** (file descriptor limits and stack and data sizes). In order to prevent
** abuse, it uses roughly the same security model as inndstart; only the
** news user can run this program, and it attempts to drop privileges when
** doing operations that don't require it.
*/
#include "config.h"
#include "clibrary.h"
#include <syslog.h>
#include <errno.h>
#include <grp.h>
#include <pwd.h>
/* FreeBSD 3.4 RELEASE needs <sys/time.h> before <sys/resource.h>. */
#if HAVE_SETRLIMIT
# if HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
# include <sys/resource.h>
#endif
#include "inn/innconf.h"
#include "inn/messages.h"
#include "libinn.h"
/* Options for debugging malloc. */
#ifdef USE_DMALLOC
# define DMALLOC_OPTIONS \
"DMALLOC_OPTIONS=debug=0x4e405c3,inter=100,log=innfeed-logfile"
#endif
int
main(int argc, char *argv[])
{
struct passwd * pwd;
struct group * grp;
uid_t news_uid;
gid_t news_gid;
char ** innfeed_argv;
char * spawn_path;
int i;
#if HAVE_SETRLIMIT
struct rlimit rl;
#endif
openlog("innfeed", L_OPENLOG_FLAGS | LOG_PID, LOG_INN_PROG);
message_handlers_warn(1, message_log_syslog_warning);
message_handlers_die(1, message_log_syslog_err);
/* Convert NEWSUSER and NEWSGRP to a UID and GID. getpwnam() and
getgrnam() don't set errno normally, so don't print strerror() on
failure; it probably contains garbage.*/
pwd = getpwnam(NEWSUSER);
if (!pwd) die("can't getpwnam(%s)", NEWSUSER);
news_uid = pwd->pw_uid;
grp = getgrnam(NEWSGRP);
if (!grp) die("can't getgrnam(%s)", NEWSGRP);
news_gid = grp->gr_gid;
/* Exit if run by another user. */
if (getuid() != news_uid)
die("ran by UID %lu, who isn't %s (%lu)", (unsigned long) getuid(),
NEWSUSER, (unsigned long) news_uid);
/* Drop privileges to read inn.conf. */
if (seteuid(news_uid) < 0)
sysdie("can't seteuid(%lu)", (unsigned long) news_uid);
if (!innconf_read(NULL))
exit(1);
/* Regain privileges to increase system limits. */
if (seteuid(0) < 0) sysdie("can't seteuid(0)");
if (innconf->rlimitnofile >= 0)
if (setfdlimit(innconf->rlimitnofile) < 0)
syswarn("can't set file descriptor limit to %ld",
innconf->rlimitnofile);
/* These calls will fail on some systems, such as HP-UX 11.00. On those
systems, we just blindly assume that the stack and data limits are
high enough (they generally are). */
#if HAVE_SETRLIMIT
rl.rlim_cur = RLIM_INFINITY;
rl.rlim_max = RLIM_INFINITY;
# ifdef RLIMIT_DATA
setrlimit(RLIMIT_DATA, &rl);
# endif
#endif /* HAVE_SETRLIMIT */
/* Permanently drop privileges. */
if (setuid(news_uid) < 0 || getuid() != news_uid)
sysdie("can't setuid to %lu", (unsigned long) news_uid);
/* Check for imapfeed -- continue to use "innfeed" in variable
names for historical reasons regardless */
if ((argc > 1) && (strcmp(argv[1],"imapfeed") == 0))
{
argc--;
argv++;
spawn_path = concat(innconf->pathbin, "/imapfeed", (char *) 0);
}
else
spawn_path = concat(innconf->pathbin, "/innfeed", (char *) 0);
/* Build the argument vector for innfeed. */
innfeed_argv = xmalloc((argc + 1) * sizeof(char *));
innfeed_argv[0] = spawn_path;
for (i = 1; i <= argc; i++)
innfeed_argv[i] = argv[i];
innfeed_argv[argc] = NULL;
/* Set debugging malloc options. */
#ifdef USE_DMALLOC
putenv(DMALLOC_OPTIONS);
#endif
/* Exec innfeed. */
execv(innfeed_argv[0], innfeed_argv);
sysdie("can't exec %s", innfeed_argv[0]);
/* Not reached. */
return 1;
}
syntax highlighted by Code2HTML, v. 0.9.1