fingerd.c revision 1.36
1/* $OpenBSD: fingerd.c,v 1.36 2012/12/04 02:24:47 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 "pathnames.h" 46 47__dead void logerr(const char *, ...); 48__dead void usage(void); 49 50void 51usage(void) 52{ 53 syslog(LOG_ERR, 54 "usage: fingerd [-lMmpSsu] [-P filename]"); 55 exit(2); 56} 57 58 59int 60main(int argc, char *argv[]) 61{ 62 FILE *fp; 63 int ch, ac = 2; 64 int p[2], logging, secure, user_required, short_list; 65#define ENTRIES 50 66 char **comp, *prog; 67 char **ap, *av[ENTRIES + 1], line[8192], *lp, *hname; 68 char hostbuf[MAXHOSTNAMELEN]; 69 70 prog = _PATH_FINGER; 71 logging = secure = user_required = short_list = 0; 72 openlog("fingerd", LOG_PID, LOG_DAEMON); 73 opterr = 0; 74 while ((ch = getopt(argc, argv, "sluSmMpP:")) != -1) 75 switch (ch) { 76 case 'l': 77 logging = 1; 78 break; 79 case 'P': 80 prog = optarg; 81 break; 82 case 's': 83 secure = 1; 84 break; 85 case 'u': 86 user_required = 1; 87 break; 88 case 'S': 89 if (ac < ENTRIES) { 90 short_list = 1; 91 av[ac++] = "-s"; 92 } 93 break; 94 case 'm': 95 if (ac < ENTRIES) 96 av[ac++] = "-m"; 97 break; 98 case 'M': 99 if (ac < ENTRIES) 100 av[ac++] = "-M"; 101 break; 102 case 'p': 103 if (ac < ENTRIES) 104 av[ac++] = "-p"; 105 break; 106 default: 107 usage(); 108 } 109 110 if (logging) { 111 struct sockaddr_storage ss; 112 struct sockaddr *sa; 113 socklen_t sval; 114 115 sval = sizeof(ss); 116 if (getpeername(0, (struct sockaddr *)&ss, &sval) < 0) 117 err(1, "getpeername"); 118 sa = (struct sockaddr *)&ss; 119 if (getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf), 120 NULL, 0, 0) != 0) { 121 strlcpy(hostbuf, "?", sizeof(hostbuf)); 122 } 123 hname = hostbuf; 124 } 125 126 if (fgets(line, sizeof(line), stdin) == NULL) { 127 if (logging) 128 syslog(LOG_NOTICE, "query from %s: %s", hname, 129 feof(stdin) ? "EOF" : strerror(errno)); 130 exit(1); 131 } 132 133 if (logging) 134 syslog(LOG_NOTICE, "query from %s: `%.*s'", hname, 135 (int)strcspn(line, "\r\n"), line); 136 137 /* 138 * Note: we assume that finger(1) will treat "--" as end of 139 * command args (ie: that it uses getopt(3)). 140 */ 141 av[ac++] = "--"; 142 comp = &av[1]; 143 for (lp = line, ap = &av[ac]; ac < ENTRIES;) { 144 size_t len; 145 146 if ((*ap = strtok(lp, " \t\r\n")) == NULL) 147 break; 148 lp = NULL; 149 if (secure && strchr(*ap, '@')) { 150 (void) puts("forwarding service denied\r"); 151 exit(1); 152 } 153 154 len = strlen(*ap); 155 while (len > 0 && (*ap)[len - 1] == '@') 156 (*ap)[--len] = '\0'; 157 if (**ap == '\0') 158 continue; 159 160 /* RFC1196: "/[Ww]" == "-l" */ 161 if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) { 162 if (!short_list) { 163 av[1] = "-l"; 164 comp = &av[0]; 165 } 166 } else { 167 ap++; 168 ac++; 169 } 170 } 171 av[ENTRIES - 1] = NULL; 172 173 if ((lp = strrchr(prog, '/'))) 174 *comp = ++lp; 175 else 176 *comp = prog; 177 178 if (user_required) { 179 for (ap = comp + 1; strcmp("--", *(ap++)); ) 180 ; 181 if (*ap == NULL) { 182 (void) puts("must provide username\r"); 183 exit(1); 184 } 185 } 186 187 if (pipe(p) < 0) 188 logerr("pipe: %s", strerror(errno)); 189 190 switch (vfork()) { 191 case 0: 192 (void) close(p[0]); 193 if (p[1] != 1) { 194 (void) dup2(p[1], 1); 195 (void) close(p[1]); 196 } 197 execv(prog, comp); 198 logerr("execv: %s: %s", prog, strerror(errno)); 199 case -1: 200 logerr("fork: %s", strerror(errno)); 201 } 202 (void) close(p[1]); 203 if (!(fp = fdopen(p[0], "r"))) 204 logerr("fdopen: %s", strerror(errno)); 205 while ((ch = getc(fp)) != EOF) { 206 if (ch == '\n') 207 putchar('\r'); 208 putchar(ch); 209 } 210 exit(0); 211} 212 213void 214logerr(const char *fmt, ...) 215{ 216 va_list ap; 217 218 va_start(ap, fmt); 219 (void) vsyslog(LOG_ERR, fmt, ap); 220 va_end(ap); 221 exit(1); 222} 223