/*
* UTIL/DSTART.C - start diablo or dreaderd
*
* This is a startup program for the diablo/dreaderd daemons.
*
* It opens the listen port as root, switches uid/gid and then
* executes diablo or dreaderd from the dbin directory. It is
* designed to be run suid, although there are no guarantees
* as to its security. It should be no worse than the current
* method of starting diablo as root.
*
* Note that it only handles a single bind() address. It seems
* dreaderd allows multiple binds. Oh well, start dreaderd as
* root if that is needed.
*/
#include "defs.h"
int TxBufSize;
int RxBufSize;
char *NewsBindHost = NULL;
char *NewsService = "nntp";
int
main(int ac, char **av)
{
char *argv[255];
char *env[1];
char buf[64];
int i;
int lfd;
if (ac < 2 || (strcmp(av[1], "diablo") != 0 &&
strcmp(av[1], "dreaderd") != 0)) {
fprintf(stderr, "Usage: %s diablo|dreaderd [options]\n", av[0]);
exit(1);
}
LoadDiabloConfig(ac, av);
/*
* Options
*/
{
int i;
char *p;
for (i = 2; i < ac; ++i) {
char *ptr = av[i];
if (*ptr != '-')
continue;
ptr += 2;
switch(ptr[-1]) {
case 'B':
if (*ptr == 0)
ptr = av[++i];
if ((p = strrchr(ptr, ':')) != NULL) {
*p++ = 0;
NewsService = p;
NewsBindHost = strdup(SanitiseAddr(ptr));
} else {
NewsBindHost = strdup(SanitiseAddr(ptr));
}
break;
case 'C':
if (*ptr == 0)
++i;
break;
case 'P':
if (*ptr == 0)
ptr = av[++i];
if ((p = strrchr(ptr, ':')) != NULL) {
*p++ = 0;
NewsService = p;
NewsBindHost = strdup(SanitiseAddr(ptr));
} else {
NewsService = ptr;
}
break;
case 'R':
RxBufSize = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
if (RxBufSize < 4096)
RxBufSize = 4096;
break;
case 'T':
TxBufSize = strtol(((*ptr) ? ptr : av[++i]), NULL, 0);
break;
case 'V':
PrintVersion();
break;
}
}
}
{
struct sockaddr_in sin;
/*
* listen socket for news
*/
memset(&sin, 0, sizeof(sin));
lfd = socket(AF_INET, SOCK_STREAM, 0);
if (lfd < 0) {
perror("socket");
exit(1);
}
{
int on = 1;
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
setsockopt(lfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
}
if (TxBufSize) {
setsockopt(lfd, SOL_SOCKET, SO_SNDBUF, (void *)&TxBufSize, sizeof(int));
}
if (RxBufSize) {
setsockopt(lfd, SOL_SOCKET, SO_RCVBUF, (void *)&RxBufSize, sizeof(int));
}
if (NewsBindHost == NULL)
sin.sin_addr.s_addr = INADDR_ANY;
else if (strtol(NewsBindHost, NULL, 0) > 0) {
sin.sin_addr.s_addr = inet_addr(NewsBindHost);
} else {
struct hostent *he;
if ((he = gethostbyname(NewsBindHost)) != NULL) {
sin.sin_addr = *(struct in_addr *)he->h_addr;
} else {
fprintf(stderr, "Unknown host for bindhost option: %s\n",
NewsBindHost);
exit(1);
}
}
sin.sin_port = strtol(NewsService, NULL, 0);
if (sin.sin_port == 0) {
struct servent *se;
se = getservbyname(NewsService, NULL);
if (se == NULL) {
fprintf(stderr, "Unknown service name: %s\n", NewsService);
exit(1);
}
sin.sin_port = se->s_port;
} else {
sin.sin_port = htons(sin.sin_port);
}
sin.sin_family = AF_INET;
if (bind(lfd, (struct sockaddr *)&sin, sizeof(sin)) < 0) {
perror("bind");
exit(1);
}
}
printf("Listening on %s:%s\n",
NewsBindHost ? NewsBindHost : "ALL", NewsService);
#if NONBLK_ACCEPT_BROKEN
/* HPUX is broken, see lib/config.h */
#else
fcntl(lfd, F_SETFL, O_NONBLOCK);
#endif
/*
* change my uid/gid
*/
{
struct passwd *pw = getpwnam("news");
struct group *gr = getgrnam("news");
gid_t gid;
if (pw == NULL) {
perror("getpwnam('news')");
exit(1);
}
if (gr == NULL) {
perror("getgrnam('news')");
exit(1);
}
gid = gr->gr_gid;
setgroups(1, &gid);
setgid(gr->gr_gid);
setuid(pw->pw_uid);
}
if (strcmp(av[1], "diablo") == 0)
argv[0] = strdup(PatExpand("%s/dbin/diablo"));
else
argv[0] = strdup(PatExpand("%s/dbin/dreaderd"));
sprintf(buf, "-b%d", lfd);
argv[1] = buf;
av += 2;
for (i=2; i<ac; i++)
argv[i] = *av++;
argv[i] = NULL;
env[0] = NULL;
execve(argv[0], argv, env);
fprintf(stderr, "diablostart cant exec %s: %s\n", argv[0], strerror(errno));
_exit(1);
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1