summaryrefslogtreecommitdiff
path: root/fingerd/fingerd.c
diff options
context:
space:
mode:
Diffstat (limited to 'fingerd/fingerd.c')
-rw-r--r--fingerd/fingerd.c295
1 files changed, 295 insertions, 0 deletions
diff --git a/fingerd/fingerd.c b/fingerd/fingerd.c
new file mode 100644
index 0000000..856d2ba
--- /dev/null
+++ b/fingerd/fingerd.c
@@ -0,0 +1,295 @@
+/*
+ * 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
+}