File: | src/libexec/fingerd/fingerd.c |
Warning: | line 205, column 10 This function call is prohibited after a successful vfork |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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(*__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__attribute__((__noreturn__)) void logerr(const char *, ...); | |||
49 | __dead__attribute__((__noreturn__)) void usage(void); | |||
50 | ||||
51 | void | |||
52 | usage(void) | |||
53 | { | |||
54 | syslog(LOG_ERR3, | |||
55 | "usage: fingerd [-lMmpSsu] [-P filename]"); | |||
56 | exit(2); | |||
57 | } | |||
58 | ||||
59 | ||||
60 | int | |||
61 | main(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 ENTRIES50 50 | |||
67 | char **comp, *prog; | |||
68 | char **ap, *av[ENTRIES50 + 1], line[8192], *lp, *hname; | |||
69 | char hostbuf[HOST_NAME_MAX255+1]; | |||
70 | ||||
71 | prog = _PATH_FINGER"/usr/bin/finger"; | |||
72 | logging = secure = user_required = short_list = 0; | |||
73 | openlog("fingerd", LOG_PID0x01, LOG_DAEMON(3<<3)); | |||
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 < ENTRIES50) { | |||
91 | short_list = 1; | |||
92 | av[ac++] = "-s"; | |||
93 | } | |||
94 | break; | |||
95 | case 'm': | |||
96 | if (ac < ENTRIES50) | |||
97 | av[ac++] = "-m"; | |||
98 | break; | |||
99 | case 'M': | |||
100 | if (ac < ENTRIES50) | |||
101 | av[ac++] = "-M"; | |||
102 | break; | |||
103 | case 'p': | |||
104 | if (ac < ENTRIES50) | |||
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((void *)0)) == -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((void *)0)) == -1) | |||
127 | err(1, "pledge"); | |||
128 | ||||
129 | if (getnameinfo(sa, sa->sa_len, hostbuf, sizeof(hostbuf), | |||
130 | NULL((void *)0), 0, 0) != 0) { | |||
131 | strlcpy(hostbuf, "?", sizeof(hostbuf)); | |||
132 | } | |||
133 | hname = hostbuf; | |||
134 | } | |||
135 | ||||
136 | if (pledge("stdio proc exec", NULL((void *)0)) == -1) | |||
137 | err(1, "pledge"); | |||
138 | ||||
139 | if (fgets(line, sizeof(line), stdin(&__sF[0])) == NULL((void *)0)) { | |||
140 | if (logging) | |||
141 | syslog(LOG_NOTICE5, "query from %s: %s", hname, | |||
142 | feof(stdin)(!__isthreaded ? ((((&__sF[0]))->_flags & 0x0020) != 0) : (feof)((&__sF[0]))) ? "EOF" : strerror(errno(*__errno()))); | |||
143 | exit(1); | |||
144 | } | |||
145 | ||||
146 | if (logging
| |||
147 | syslog(LOG_NOTICE5, "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 < ENTRIES50;) { | |||
157 | size_t len; | |||
158 | ||||
159 | if ((*ap = strtok(lp, " \t\r\n")) == NULL((void *)0)) | |||
160 | break; | |||
161 | lp = NULL((void *)0); | |||
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[ENTRIES50 - 1] = NULL((void *)0); | |||
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((void *)0)) { | |||
195 | (void) puts("must provide username\r"); | |||
196 | exit(1); | |||
197 | } | |||
198 | } | |||
199 | ||||
200 | if (pipe(p) == -1) | |||
201 | logerr("pipe: %s", strerror(errno(*__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_ERR3, "execv: %s: %s", prog, strerror(errno(*__errno()))); | |||
212 | _exit(1); | |||
213 | case -1: | |||
214 | logerr("fork: %s", strerror(errno(*__errno()))); | |||
215 | } | |||
216 | if (pledge("stdio", NULL((void *)0)) == -1) | |||
217 | err(1, "pledge"); | |||
218 | ||||
219 | (void) close(p[1]); | |||
220 | if (!(fp = fdopen(p[0], "r"))) | |||
221 | logerr("fdopen: %s", strerror(errno(*__errno()))); | |||
222 | while ((ch = getc(fp)(!__isthreaded ? (--(fp)->_r < 0 ? __srget(fp) : (int)( *(fp)->_p++)) : (getc)(fp))) != EOF(-1)) { | |||
223 | if (ch == '\n') | |||
224 | putchar('\r')(!__isthreaded ? __sputc('\r', (&__sF[1])) : (putc)('\r', (&__sF[1]))); | |||
225 | putchar(ch)(!__isthreaded ? __sputc(ch, (&__sF[1])) : (putc)(ch, (& __sF[1]))); | |||
226 | } | |||
227 | exit(0); | |||
228 | } | |||
229 | ||||
230 | void | |||
231 | logerr(const char *fmt, ...) | |||
232 | { | |||
233 | va_list ap; | |||
234 | ||||
235 | va_start(ap, fmt)__builtin_va_start(ap, fmt); | |||
236 | (void) vsyslog(LOG_ERR3, fmt, ap); | |||
237 | va_end(ap)__builtin_va_end(ap); | |||
238 | exit(1); | |||
239 | } |