finger-modif/fingerd/fingerd.c

296 lines
7.3 KiB
C

/*
* Copyright (c) 1983 The Regents of the University of California.
* All rights reserved.
*
* 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. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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, WHETHER 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.
*/
char copyright[] =
"@(#) Copyright (c) 1983 The Regents of the University of California.\n"
"All rights reserved.\n";
/*
* from: @(#)fingerd.c 5.6 (Berkeley) 6/1/90"
*/
char rcsid[] =
"$Id: fingerd.c,v 1.23 1999/12/12 18:46:28 dholland Exp $";
#include <pwd.h>
#include <grp.h>
#include <netdb.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <syslog.h>
#include <getopt.h>
#include <netinet/in.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include "pathnames.h"
#include "../version.h"
#define ENTRIES 50
#define WS " \t\r\n"
/* These are used in this order if the finger path compiled in doesn't work. */
#define _ALT_PATH_FINGER_1 "/usr/local/bin/finger"
#define _ALT_PATH_FINGER_2 "/usr/ucb/finger"
#define _ALT_PATH_FINGER_3 "/usr/bin/finger"
static
void
fatal(const char *msg, int use_errno, int tolog, int toclient)
{
const char *err = "";
const char *sep = "";
if (use_errno) {
err = strerror(errno);
sep = ": ";
}
if (tolog) syslog(LOG_ERR, "%s%s%s\n", msg, sep, err);
if (toclient) fprintf(stderr, "fingerd: %s%s%s\r\n", msg, sep, err);
else fprintf(stderr, "fingerd: Internal error\r\n");
exit(1);
}
static
void
timeout(int sig)
{
(void)sig;
errno = ETIMEDOUT;
fatal("Input timeout", 0, 1, 1);
}
int
main(int argc, char *argv[])
{
#if 0
FILE *fp;
int p[2], ch;
pid_t pid;
#endif
int ca;
const char *av[ENTRIES + 1];
const char **avy;
char *const *avx;
char line[1024];
int welcome = 0, heavylogging = 0, nouserlist = 0;
int patience = 60, forwarding = 0;
int k, nusers;
char *s, *t;
const char *fingerpath = NULL;
struct sockaddr_in sn;
socklen_t sval = sizeof(sn);
if (getpeername(0, (struct sockaddr *) &sn, &sval) < 0) {
fatal("getpeername", 1, 0, 1);
}
openlog("fingerd", LOG_PID, LOG_DAEMON);
if (!getuid() || !geteuid()) {
struct passwd *pwd = getpwnam("nobody");
if (pwd) {
initgroups(pwd->pw_name, pwd->pw_gid);
setgid(pwd->pw_gid);
setuid(pwd->pw_uid);
}
seteuid(0); /* this should fail */
if (!getuid() || !geteuid()) {
fatal("setuid: couldn't drop root", 0, 1, 0);
}
}
/*endpwent(); -- is it safe to put this here? */
opterr = 0;
while ((ca = getopt(argc, argv, "wlL:p:uft:h?")) != EOF) {
switch(ca) {
case 'w':
welcome = 1;
break;
case 'l':
heavylogging = 1;
break;
case 'L':
case 'p':
fingerpath = optarg;
break;
case 'u':
nouserlist = 1;
break;
case 'f':
forwarding = 1;
break;
case 't':
patience = atoi(optarg);
break;
case '?':
case 'h':
default:
syslog(LOG_ERR, "usage: fingerd [-wulf]"
"[-pL /path/finger] [-t timeout]");
exit(1);
}
}
argc -= optind;
argv += optind;
/*
* Hang up after a while so people can't DoS by leaving lots of
* open sockets about.
*/
if (patience != 0) {
signal(SIGALRM, timeout);
alarm(patience);
}
if (!fgets(line, sizeof(line), stdin)) {
fatal("Client hung up - probable port-scan", 0, 1, 0);
}
if (welcome) {
char buf[256];
struct hostent *hp;
struct utsname utsname;
uname(&utsname);
gethostname(buf, sizeof(buf));
if ((hp = gethostbyname(buf))) {
/* paranoia: dns spoofing? */
strncpy(buf, hp->h_name, sizeof(buf));
buf[sizeof(buf)-1] = 0;
}
printf("\r\nWelcome to %s version %s at %s !\r\n\n",
utsname.sysname, utsname.release, buf);
fflush(stdout);
switch (fork()) {
case -1: /* fork failed, oh well */
break;
case 0: /* child */
execl(_PATH_UPTIME, _PATH_UPTIME, NULL);
_exit(1);
default: /* parent */
wait(NULL);
break;
}
fflush(stdout);
printf("\r\n");
fflush(stdout);
}
k = nusers = 0;
av[k++] = "finger";
for (s = strtok(line, WS); s && k<ENTRIES; s = strtok(NULL, WS)) {
/* RFC742: "/[Ww]" == "-l" */
if (!strncasecmp(s, "/w", 2)) memcpy(s, "-l", 2);
if (!forwarding) {
t = strchr(s, '@');
if (t) {
fprintf(stderr,
"fingerd: forwarding not allowed\r\n");
syslog(LOG_WARNING, "rejected %s\n", s);
exit(1);
}
}
if (heavylogging) {
if (*s=='-') syslog(LOG_INFO, "option %s\n", s);
else syslog(LOG_INFO, "fingered %s\n", s);
}
av[k++] = s;
if (*s!='-') nusers++;
}
av[k] = NULL;
if (nusers==0) {
/* finger @host */
if (nouserlist) {
syslog(LOG_WARNING, "rejected finger @host\n");
printf("Please supply a username\r\n");
return 0;
}
if (heavylogging) syslog(LOG_INFO, "fingered @host\n");
}
/* Yay! we don't need to do this any more - finger does it for us */
#if 0
if (pipe(p) < 0) {
fatal("pipe", 1, 1, 0);
}
pid = fork();
if (pid<0) {
fatal("fork", 1, 1, 0);
}
if (pid==0) {
/* child */
close(p[0]);
dup2(p[1], 1);
if (p[1]!=1) close(p[1]);
#endif
/*
* execv() takes (char *const *), because (char const *const *)
* doesn't work right in C (only in C++). C9x might fix this
* if we're lucky. In the meantime we need to defeat the type
* system to avoid warnings.
*/
avy = av;
/*avx = avy;*/
memcpy(&avx, &avy, sizeof(avx));
if (fingerpath) execv(fingerpath, avx);
execv(_PATH_FINGER, avx);
execv(_ALT_PATH_FINGER_1, avx);
execv(_ALT_PATH_FINGER_2, avx);
execv(_ALT_PATH_FINGER_3, avx);
syslog(LOG_ERR, "Finger program not found\n");
exit(1);
#if 0
}
/* parent */
close(p[1]);
/* convert \n to \r\n. This should be an option to finger... */
fp = fdopen(p[0], "r");
if (!fp) {
fatal("fdopen", 1, 1, 0);
}
while ((ch = getc(fp)) != EOF) {
if (ch == '\n') putchar('\r');
putchar(ch);
}
return 0;
#endif
}