fingerd.c revision 1.38
1/* $OpenBSD: fingerd.c,v 1.38 2015/11/13 01:23:59 deraadt Exp $ */ 2 3/* 4 * Copyright (c) 1983, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/socket.h> 33#include <netinet/in.h> 34#include <arpa/inet.h> 35#include <errno.h> 36 37#include <err.h> 38#include <unistd.h> 39#include <syslog.h> 40#include <netdb.h> 41#include <stdio.h> 42#include <stdlib.h> 43#include <string.h> 44#include <stdarg.h> 45#include <limits.h> 46#include "pathnames.h" 47 48__dead void logerr(const char *, ...); 49__dead void usage(void); 50 51void 52usage(void) 53{ 54 syslog(LOG_ERR, 55 "usage: fingerd [-lMmpSsu] [-P filename]"); 56 exit(2); 57} 58 59 60int 61main(int argc, char *argv[]) 62{ 63 FILE *fp; 64 int ch, ac = 2; 65 int p[2], logging, secure, user_required, short_list; 66#define ENTRIES 50 67 char **comp, *prog; 68 char **ap, *av[ENTRIES + 1], line[8192], *lp, *hname; 69 char hostbuf[HOST_NAME_MAX+1]; 70 71 prog = _PATH_FINGER; 72 logging = secure = user_required = short_list = 0; 73 openlog("fingerd", LOG_PID, LOG_DAEMON); 74 opterr = 0; 75 while ((ch = getopt(argc, argv, "sluSmMpP:")) != -1) 76 switch (ch) { 77 case 'l': 78 logging = 1; 79 break; 80 case 'P': 81 prog = optarg; 82 break; 83 case 's': 84 secure = 1; 85 break; 86 case 'u': 87 user_required = 1; 88 break; 89 case 'S': 90 if (ac < ENTRIES) { 91 short_list = 1; 92 av[ac++] = "-s"; 93 } 94 break; 95 case 'm': 96 if (ac < ENTRIES) 97 av[ac++] = "-m"; 98 break; 99 case 'M': 100 if (ac < ENTRIES) 101 av[ac++] = "-M"; 102 break; 103 case 'p': 104 if (ac < ENTRIES) 105 av[ac++] = "-p"; 106 break; 107 default: 108 usage(); 109 } 110 111 if (logging) { 112 struct sockaddr_storage ss; 113 struct sockaddr *sa; 114 socklen_t sval; 115 116 sval = sizeof(ss); 117 if (getpeername(0, (struct sockaddr *)&ss, &sval) < 0) 118 err(1, "getpeername"); 119 sa = (struct sockaddr *)&ss; 120 if (getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf), 121 NULL, 0, 0) != 0) { 122 strlcpy(hostbuf, "?", sizeof(hostbuf)); 123 } 124 hname = hostbuf; 125 } 126 127 if (fgets(line, sizeof(line), stdin) == NULL) { 128 if (logging) 129 syslog(LOG_NOTICE, "query from %s: %s", hname, 130 feof(stdin) ? "EOF" : strerror(errno)); 131 exit(1); 132 } 133 134 if (logging) 135 syslog(LOG_NOTICE, "query from %s: `%.*s'", hname, 136 (int)strcspn(line, "\r\n"), line); 137 138 /* 139 * Note: we assume that finger(1) will treat "--" as end of 140 * command args (ie: that it uses getopt(3)). 141 */ 142 av[ac++] = "--"; 143 comp = &av[1]; 144 for (lp = line, ap = &av[ac]; ac < ENTRIES;) { 145 size_t len; 146 147 if ((*ap = strtok(lp, " \t\r\n")) == NULL) 148 break; 149 lp = NULL; 150 if (secure && strchr(*ap, '@')) { 151 (void) puts("forwarding service denied\r"); 152 exit(1); 153 } 154 155 len = strlen(*ap); 156 while (len > 0 && (*ap)[len - 1] == '@') 157 (*ap)[--len] = '\0'; 158 if (**ap == '\0') 159 continue; 160 161 /* RFC1196: "/[Ww]" == "-l" */ 162 if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) { 163 if (!short_list) { 164 av[1] = "-l"; 165 comp = &av[0]; 166 } 167 } else { 168 ap++; 169 ac++; 170 } 171 } 172 av[ENTRIES - 1] = NULL; 173 174 if ((lp = strrchr(prog, '/'))) 175 *comp = ++lp; 176 else 177 *comp = prog; 178 179 if (user_required) { 180 for (ap = comp + 1; strcmp("--", *(ap++)); ) 181 ; 182 if (*ap == NULL) { 183 (void) puts("must provide username\r"); 184 exit(1); 185 } 186 } 187 188 if (pipe(p) < 0) 189 logerr("pipe: %s", strerror(errno)); 190 191 switch (vfork()) { 192 case 0: 193 (void) close(p[0]); 194 if (p[1] != 1) { 195 (void) dup2(p[1], 1); 196 (void) close(p[1]); 197 } 198 execv(prog, comp); 199 syslog(LOG_ERR, "execv: %s: %s", prog, strerror(errno)); 200 _exit(1); 201 case -1: 202 logerr("fork: %s", strerror(errno)); 203 } 204 (void) close(p[1]); 205 if (!(fp = fdopen(p[0], "r"))) 206 logerr("fdopen: %s", strerror(errno)); 207 while ((ch = getc(fp)) != EOF) { 208 if (ch == '\n') 209 putchar('\r'); 210 putchar(ch); 211 } 212 exit(0); 213} 214 215void 216logerr(const char *fmt, ...) 217{ 218 va_list ap; 219 220 va_start(ap, fmt); 221 (void) vsyslog(LOG_ERR, fmt, ap); 222 va_end(ap); 223 exit(1); 224} 225