fingerd.c revision 1.42
1/* $OpenBSD: fingerd.c,v 1.42 2021/07/12 15:09:18 beck 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 (unveil(prog, "x") == -1) 112 err(1, "unveil %s", prog); 113 if (pledge("stdio inet dns proc exec", NULL) == -1) 114 err(1, "pledge"); 115 116 if (logging) { 117 struct sockaddr_storage ss; 118 struct sockaddr *sa; 119 socklen_t sval; 120 121 sval = sizeof(ss); 122 if (getpeername(0, (struct sockaddr *)&ss, &sval) == -1) 123 err(1, "getpeername"); 124 sa = (struct sockaddr *)&ss; 125 126 if (pledge("stdio dns proc exec", NULL) == -1) 127 err(1, "pledge"); 128 129 if (getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf), 130 NULL, 0, 0) != 0) { 131 strlcpy(hostbuf, "?", sizeof(hostbuf)); 132 } 133 hname = hostbuf; 134 } 135 136 if (pledge("stdio proc exec", NULL) == -1) 137 err(1, "pledge"); 138 139 if (fgets(line, sizeof(line), stdin) == NULL) { 140 if (logging) 141 syslog(LOG_NOTICE, "query from %s: %s", hname, 142 feof(stdin) ? "EOF" : strerror(errno)); 143 exit(1); 144 } 145 146 if (logging) 147 syslog(LOG_NOTICE, "query from %s: `%.*s'", hname, 148 (int)strcspn(line, "\r\n"), line); 149 150 /* 151 * Note: we assume that finger(1) will treat "--" as end of 152 * command args (ie: that it uses getopt(3)). 153 */ 154 av[ac++] = "--"; 155 comp = &av[1]; 156 for (lp = line, ap = &av[ac]; ac < ENTRIES;) { 157 size_t len; 158 159 if ((*ap = strtok(lp, " \t\r\n")) == NULL) 160 break; 161 lp = NULL; 162 if (secure && strchr(*ap, '@')) { 163 (void) puts("forwarding service denied\r"); 164 exit(1); 165 } 166 167 len = strlen(*ap); 168 while (len > 0 && (*ap)[len - 1] == '@') 169 (*ap)[--len] = '\0'; 170 if (**ap == '\0') 171 continue; 172 173 /* RFC1196: "/[Ww]" == "-l" */ 174 if ((*ap)[0] == '/' && ((*ap)[1] == 'W' || (*ap)[1] == 'w')) { 175 if (!short_list) { 176 av[1] = "-l"; 177 comp = &av[0]; 178 } 179 } else { 180 ap++; 181 ac++; 182 } 183 } 184 av[ENTRIES - 1] = NULL; 185 186 if ((lp = strrchr(prog, '/'))) 187 *comp = ++lp; 188 else 189 *comp = prog; 190 191 if (user_required) { 192 for (ap = comp + 1; strcmp("--", *(ap++)); ) 193 ; 194 if (*ap == NULL) { 195 (void) puts("must provide username\r"); 196 exit(1); 197 } 198 } 199 200 if (pipe(p) == -1) 201 logerr("pipe: %s", strerror(errno)); 202 203 switch (vfork()) { 204 case 0: 205 (void) close(p[0]); 206 if (p[1] != 1) { 207 (void) dup2(p[1], 1); 208 (void) close(p[1]); 209 } 210 execv(prog, comp); 211 syslog(LOG_ERR, "execv: %s: %s", prog, strerror(errno)); 212 _exit(1); 213 case -1: 214 logerr("fork: %s", strerror(errno)); 215 } 216 if (pledge("stdio", NULL) == -1) 217 err(1, "pledge"); 218 219 (void) close(p[1]); 220 if (!(fp = fdopen(p[0], "r"))) 221 logerr("fdopen: %s", strerror(errno)); 222 while ((ch = getc(fp)) != EOF) { 223 if (ch == '\n') 224 putchar('\r'); 225 putchar(ch); 226 } 227 exit(0); 228} 229 230void 231logerr(const char *fmt, ...) 232{ 233 va_list ap; 234 235 va_start(ap, fmt); 236 (void) vsyslog(LOG_ERR, fmt, ap); 237 va_end(ap); 238 exit(1); 239} 240