1 |
|
|
/* $OpenBSD: identd.c,v 1.38 2017/07/04 01:09:42 dlg Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2013 David Gwynne <dlg@openbsd.org> |
5 |
|
|
* |
6 |
|
|
* Permission to use, copy, modify, and distribute this software for any |
7 |
|
|
* purpose with or without fee is hereby granted, provided that the above |
8 |
|
|
* copyright notice and this permission notice appear in all copies. |
9 |
|
|
* |
10 |
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
11 |
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
12 |
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
13 |
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
14 |
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 |
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 |
|
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 |
|
|
*/ |
18 |
|
|
|
19 |
|
|
#include <sys/types.h> |
20 |
|
|
#include <sys/ioctl.h> |
21 |
|
|
#include <sys/socket.h> |
22 |
|
|
#include <sys/socketvar.h> |
23 |
|
|
#include <sys/stat.h> |
24 |
|
|
#include <sys/sysctl.h> |
25 |
|
|
#include <sys/uio.h> |
26 |
|
|
|
27 |
|
|
#include <netinet/in.h> |
28 |
|
|
#include <netinet/tcp.h> |
29 |
|
|
#include <netinet/tcp_timer.h> |
30 |
|
|
#include <netinet/tcp_var.h> |
31 |
|
|
|
32 |
|
|
#include <netdb.h> |
33 |
|
|
|
34 |
|
|
#include <err.h> |
35 |
|
|
#include <ctype.h> |
36 |
|
|
#include <errno.h> |
37 |
|
|
#include <event.h> |
38 |
|
|
#include <fcntl.h> |
39 |
|
|
#include <pwd.h> |
40 |
|
|
#include <stdio.h> |
41 |
|
|
#include <limits.h> |
42 |
|
|
#include <stdlib.h> |
43 |
|
|
#include <stdarg.h> |
44 |
|
|
#include <string.h> |
45 |
|
|
#include <signal.h> |
46 |
|
|
#include <syslog.h> |
47 |
|
|
#include <unistd.h> |
48 |
|
|
|
49 |
|
|
#define IDENTD_USER "_identd" |
50 |
|
|
|
51 |
|
|
#define DOTNOIDENT ".noident" |
52 |
|
|
|
53 |
|
|
#define TIMEOUT_MIN 4 |
54 |
|
|
#define TIMEOUT_MAX 240 |
55 |
|
|
#define TIMEOUT_DEFAULT 120 |
56 |
|
|
#define INPUT_MAX 256 |
57 |
|
|
|
58 |
|
|
enum ident_client_state { |
59 |
|
|
S_BEGINNING = 0, |
60 |
|
|
S_SERVER_PORT, |
61 |
|
|
S_PRE_COMMA, |
62 |
|
|
S_POST_COMMA, |
63 |
|
|
S_CLIENT_PORT, |
64 |
|
|
S_PRE_EOL, |
65 |
|
|
S_EOL, |
66 |
|
|
|
67 |
|
|
S_DEAD, |
68 |
|
|
S_QUEUED |
69 |
|
|
}; |
70 |
|
|
|
71 |
|
|
#define E_NONE 0 |
72 |
|
|
#define E_NOUSER 1 |
73 |
|
|
#define E_UNKNOWN 2 |
74 |
|
|
#define E_HIDDEN 3 |
75 |
|
|
|
76 |
|
|
struct ident_client { |
77 |
|
|
struct { |
78 |
|
|
/* from the socket */ |
79 |
|
|
struct sockaddr_storage ss; |
80 |
|
|
socklen_t len; |
81 |
|
|
|
82 |
|
|
/* from the request */ |
83 |
|
|
u_int port; |
84 |
|
|
} client, server; |
85 |
|
|
SIMPLEQ_ENTRY(ident_client) entry; |
86 |
|
|
enum ident_client_state state; |
87 |
|
|
struct event ev; |
88 |
|
|
struct event tmo; |
89 |
|
|
size_t rxbytes; |
90 |
|
|
|
91 |
|
|
char *buf; |
92 |
|
|
size_t buflen; |
93 |
|
|
size_t bufoff; |
94 |
|
|
uid_t uid; |
95 |
|
|
}; |
96 |
|
|
|
97 |
|
|
struct ident_resolver { |
98 |
|
|
SIMPLEQ_ENTRY(ident_resolver) entry; |
99 |
|
|
char *buf; |
100 |
|
|
size_t buflen; |
101 |
|
|
u_int error; |
102 |
|
|
}; |
103 |
|
|
|
104 |
|
|
struct identd_listener { |
105 |
|
|
struct event ev, pause; |
106 |
|
|
}; |
107 |
|
|
|
108 |
|
|
void parent_rd(int, short, void *); |
109 |
|
|
void parent_wr(int, short, void *); |
110 |
|
|
int parent_username(struct ident_resolver *, struct passwd *); |
111 |
|
|
int parent_uid(struct ident_resolver *, struct passwd *); |
112 |
|
|
int parent_token(struct ident_resolver *, struct passwd *); |
113 |
|
|
void parent_noident(struct ident_resolver *, struct passwd *); |
114 |
|
|
|
115 |
|
|
void child_rd(int, short, void *); |
116 |
|
|
void child_wr(int, short, void *); |
117 |
|
|
|
118 |
|
|
void identd_listen(const char *, const char *, int); |
119 |
|
|
void identd_paused(int, short, void *); |
120 |
|
|
void identd_accept(int, short, void *); |
121 |
|
|
int identd_error(struct ident_client *, const char *); |
122 |
|
|
void identd_close(struct ident_client *); |
123 |
|
|
void identd_timeout(int, short, void *); |
124 |
|
|
void identd_request(int, short, void *); |
125 |
|
|
enum ident_client_state |
126 |
|
|
identd_parse(struct ident_client *, int); |
127 |
|
|
void identd_resolving(int, short, void *); |
128 |
|
|
void identd_response(int, short, void *); |
129 |
|
|
int fetchuid(struct ident_client *); |
130 |
|
|
|
131 |
|
|
const char *gethost(struct sockaddr_storage *); |
132 |
|
|
const char *gentoken(void); |
133 |
|
|
|
134 |
|
|
struct loggers { |
135 |
|
|
__dead void (*err)(int, const char *, ...) |
136 |
|
|
__attribute__((__format__ (printf, 2, 3))); |
137 |
|
|
__dead void (*errx)(int, const char *, ...) |
138 |
|
|
__attribute__((__format__ (printf, 2, 3))); |
139 |
|
|
void (*warn)(const char *, ...) |
140 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
141 |
|
|
void (*warnx)(const char *, ...) |
142 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
143 |
|
|
void (*notice)(const char *, ...) |
144 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
145 |
|
|
void (*debug)(const char *, ...) |
146 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
147 |
|
|
}; |
148 |
|
|
|
149 |
|
|
const struct loggers conslogger = { |
150 |
|
|
err, |
151 |
|
|
errx, |
152 |
|
|
warn, |
153 |
|
|
warnx, |
154 |
|
|
warnx, /* notice */ |
155 |
|
|
warnx /* debug */ |
156 |
|
|
}; |
157 |
|
|
|
158 |
|
|
__dead void syslog_err(int, const char *, ...) |
159 |
|
|
__attribute__((__format__ (printf, 2, 3))); |
160 |
|
|
__dead void syslog_errx(int, const char *, ...) |
161 |
|
|
__attribute__((__format__ (printf, 2, 3))); |
162 |
|
|
void syslog_warn(const char *, ...) |
163 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
164 |
|
|
void syslog_warnx(const char *, ...) |
165 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
166 |
|
|
void syslog_notice(const char *, ...) |
167 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
168 |
|
|
void syslog_debug(const char *, ...) |
169 |
|
|
__attribute__((__format__ (printf, 1, 2))); |
170 |
|
|
void syslog_vstrerror(int, int, const char *, va_list) |
171 |
|
|
__attribute__((__format__ (printf, 3, 0))); |
172 |
|
|
|
173 |
|
|
const struct loggers syslogger = { |
174 |
|
|
syslog_err, |
175 |
|
|
syslog_errx, |
176 |
|
|
syslog_warn, |
177 |
|
|
syslog_warnx, |
178 |
|
|
syslog_notice, |
179 |
|
|
syslog_debug |
180 |
|
|
}; |
181 |
|
|
|
182 |
|
|
const struct loggers *logger = &conslogger; |
183 |
|
|
|
184 |
|
|
#define lerr(_e, _f...) logger->err((_e), _f) |
185 |
|
|
#define lerrx(_e, _f...) logger->errx((_e), _f) |
186 |
|
|
#define lwarn(_f...) logger->warn(_f) |
187 |
|
|
#define lwarnx(_f...) logger->warnx(_f) |
188 |
|
|
#define lnotice(_f...) logger->notice(_f) |
189 |
|
|
#define ldebug(_f...) logger->debug(_f) |
190 |
|
|
|
191 |
|
|
#define sa(_ss) ((struct sockaddr *)(_ss)) |
192 |
|
|
|
193 |
|
|
static __dead void |
194 |
|
|
usage(void) |
195 |
|
|
{ |
196 |
|
|
extern char *__progname; |
197 |
|
|
fprintf(stderr, "usage: %s [-46deHhNn] [-l address] [-t timeout]\n", |
198 |
|
|
__progname); |
199 |
|
|
exit(1); |
200 |
|
|
} |
201 |
|
|
|
202 |
|
|
struct timeval timeout = { TIMEOUT_DEFAULT, 0 }; |
203 |
|
|
int debug = 0; |
204 |
|
|
int noident = 0; |
205 |
|
|
int unknown_err = 0; |
206 |
|
|
int hideall = 0; |
207 |
|
|
|
208 |
|
|
int (*parent_uprintf)(struct ident_resolver *, struct passwd *) = |
209 |
|
|
parent_username; |
210 |
|
|
|
211 |
|
|
struct event proc_rd, proc_wr; |
212 |
|
|
union { |
213 |
|
|
struct { |
214 |
|
|
SIMPLEQ_HEAD(, ident_resolver) replies; |
215 |
|
|
} parent; |
216 |
|
|
struct { |
217 |
|
|
SIMPLEQ_HEAD(, ident_client) pushing, popping; |
218 |
|
|
} child; |
219 |
|
|
} sc; |
220 |
|
|
|
221 |
|
|
int |
222 |
|
|
main(int argc, char *argv[]) |
223 |
|
|
{ |
224 |
|
|
extern char *__progname; |
225 |
|
|
const char *errstr = NULL; |
226 |
|
|
|
227 |
|
|
int c; |
228 |
|
|
struct passwd *pw; |
229 |
|
|
|
230 |
|
|
char *addr = NULL; |
231 |
|
|
int family = AF_UNSPEC; |
232 |
|
|
|
233 |
|
|
int pair[2]; |
234 |
|
|
pid_t parent; |
235 |
|
|
int sibling; |
236 |
|
|
|
237 |
|
|
while ((c = getopt(argc, argv, "46deHhl:Nnt:")) != -1) { |
238 |
|
|
switch (c) { |
239 |
|
|
case '4': |
240 |
|
|
family = AF_INET; |
241 |
|
|
break; |
242 |
|
|
case '6': |
243 |
|
|
family = AF_INET6; |
244 |
|
|
break; |
245 |
|
|
case 'd': |
246 |
|
|
debug = 1; |
247 |
|
|
break; |
248 |
|
|
case 'e': |
249 |
|
|
unknown_err = 1; |
250 |
|
|
break; |
251 |
|
|
case 'H': |
252 |
|
|
hideall = 1; |
253 |
|
|
/* FALLTHROUGH */ |
254 |
|
|
case 'h': |
255 |
|
|
parent_uprintf = parent_token; |
256 |
|
|
break; |
257 |
|
|
case 'l': |
258 |
|
|
addr = optarg; |
259 |
|
|
break; |
260 |
|
|
case 'N': |
261 |
|
|
noident = 1; |
262 |
|
|
break; |
263 |
|
|
case 'n': |
264 |
|
|
parent_uprintf = parent_uid; |
265 |
|
|
break; |
266 |
|
|
case 't': |
267 |
|
|
timeout.tv_sec = strtonum(optarg, |
268 |
|
|
TIMEOUT_MIN, TIMEOUT_MAX, &errstr); |
269 |
|
|
if (errstr != NULL) |
270 |
|
|
errx(1, "timeout %s is %s", optarg, errstr); |
271 |
|
|
break; |
272 |
|
|
default: |
273 |
|
|
usage(); |
274 |
|
|
/* NOTREACHED */ |
275 |
|
|
} |
276 |
|
|
} |
277 |
|
|
|
278 |
|
|
argc -= optind; |
279 |
|
|
argv += optind; |
280 |
|
|
|
281 |
|
|
if (argc != 0) |
282 |
|
|
usage(); |
283 |
|
|
|
284 |
|
|
if (geteuid() != 0) |
285 |
|
|
errx(1, "need root privileges"); |
286 |
|
|
|
287 |
|
|
if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, |
288 |
|
|
PF_UNSPEC, pair) == -1) |
289 |
|
|
err(1, "socketpair"); |
290 |
|
|
|
291 |
|
|
pw = getpwnam(IDENTD_USER); |
292 |
|
|
if (pw == NULL) |
293 |
|
|
errx(1, "no %s user", IDENTD_USER); |
294 |
|
|
|
295 |
|
|
if (!debug && daemon(1, 0) == -1) |
296 |
|
|
err(1, "daemon"); |
297 |
|
|
|
298 |
|
|
parent = fork(); |
299 |
|
|
switch (parent) { |
300 |
|
|
case -1: |
301 |
|
|
lerr(1, "fork"); |
302 |
|
|
|
303 |
|
|
case 0: |
304 |
|
|
/* child */ |
305 |
|
|
setproctitle("listener"); |
306 |
|
|
close(pair[1]); |
307 |
|
|
sibling = pair[0]; |
308 |
|
|
break; |
309 |
|
|
|
310 |
|
|
default: |
311 |
|
|
/* parent */ |
312 |
|
|
setproctitle("resolver"); |
313 |
|
|
close(pair[0]); |
314 |
|
|
sibling = pair[1]; |
315 |
|
|
break; |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
if (!debug) { |
319 |
|
|
openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON); |
320 |
|
|
tzset(); |
321 |
|
|
logger = &syslogger; |
322 |
|
|
} |
323 |
|
|
|
324 |
|
|
event_init(); |
325 |
|
|
|
326 |
|
|
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) |
327 |
|
|
lerr(1, "signal(SIGPIPE)"); |
328 |
|
|
|
329 |
|
|
if (parent) { |
330 |
|
|
if (pledge("stdio getpw rpath id flock cpath wpath", NULL) == -1) |
331 |
|
|
err(1, "pledge"); |
332 |
|
|
|
333 |
|
|
SIMPLEQ_INIT(&sc.parent.replies); |
334 |
|
|
|
335 |
|
|
event_set(&proc_rd, sibling, EV_READ | EV_PERSIST, |
336 |
|
|
parent_rd, NULL); |
337 |
|
|
event_set(&proc_wr, sibling, EV_WRITE, |
338 |
|
|
parent_wr, NULL); |
339 |
|
|
} else { |
340 |
|
|
SIMPLEQ_INIT(&sc.child.pushing); |
341 |
|
|
SIMPLEQ_INIT(&sc.child.popping); |
342 |
|
|
|
343 |
|
|
identd_listen(addr, "auth", family); |
344 |
|
|
|
345 |
|
|
if (chroot(pw->pw_dir) == -1) |
346 |
|
|
lerr(1, "chroot(%s)", pw->pw_dir); |
347 |
|
|
|
348 |
|
|
if (chdir("/") == -1) |
349 |
|
|
lerr(1, "chdir(%s)", pw->pw_dir); |
350 |
|
|
|
351 |
|
|
event_set(&proc_rd, sibling, EV_READ | EV_PERSIST, |
352 |
|
|
child_rd, NULL); |
353 |
|
|
event_set(&proc_wr, sibling, EV_WRITE, |
354 |
|
|
child_wr, NULL); |
355 |
|
|
} |
356 |
|
|
|
357 |
|
|
if (setgroups(1, &pw->pw_gid) || |
358 |
|
|
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || |
359 |
|
|
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) |
360 |
|
|
lerr(1, "unable to revoke privs"); |
361 |
|
|
|
362 |
|
|
if (parent) { |
363 |
|
|
if (noident) { |
364 |
|
|
if (pledge("stdio getpw rpath flock cpath wpath", NULL) == -1) |
365 |
|
|
err(1, "pledge"); |
366 |
|
|
} else { |
367 |
|
|
if (pledge("stdio getpw flock rpath cpath wpath", NULL) == -1) |
368 |
|
|
err(1, "pledge"); |
369 |
|
|
} |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
event_add(&proc_rd, NULL); |
373 |
|
|
event_dispatch(); |
374 |
|
|
return (0); |
375 |
|
|
} |
376 |
|
|
|
377 |
|
|
void |
378 |
|
|
parent_rd(int fd, short events, void *arg) |
379 |
|
|
{ |
380 |
|
|
struct ident_resolver *r; |
381 |
|
|
struct passwd *pw; |
382 |
|
|
ssize_t n; |
383 |
|
|
uid_t uid; |
384 |
|
|
|
385 |
|
|
n = read(fd, &uid, sizeof(uid)); |
386 |
|
|
switch (n) { |
387 |
|
|
case -1: |
388 |
|
|
switch (errno) { |
389 |
|
|
case EAGAIN: |
390 |
|
|
case EINTR: |
391 |
|
|
return; |
392 |
|
|
default: |
393 |
|
|
lerr(1, "parent read"); |
394 |
|
|
} |
395 |
|
|
break; |
396 |
|
|
case 0: |
397 |
|
|
lerrx(1, "child has gone"); |
398 |
|
|
case sizeof(uid): |
399 |
|
|
break; |
400 |
|
|
default: |
401 |
|
|
lerrx(1, "unexpected %zd data from child", n); |
402 |
|
|
} |
403 |
|
|
|
404 |
|
|
r = calloc(1, sizeof(*r)); |
405 |
|
|
if (r == NULL) |
406 |
|
|
lerr(1, "resolver alloc"); |
407 |
|
|
|
408 |
|
|
pw = getpwuid(uid); |
409 |
|
|
if (pw == NULL && !hideall) { |
410 |
|
|
r->error = E_NOUSER; |
411 |
|
|
goto done; |
412 |
|
|
} |
413 |
|
|
|
414 |
|
|
if (noident && !hideall) { |
415 |
|
|
parent_noident(r, pw); |
416 |
|
|
if (r->error != E_NONE) |
417 |
|
|
goto done; |
418 |
|
|
} |
419 |
|
|
|
420 |
|
|
n = (*parent_uprintf)(r, pw); |
421 |
|
|
if (n == -1) { |
422 |
|
|
r->error = E_UNKNOWN; |
423 |
|
|
goto done; |
424 |
|
|
} |
425 |
|
|
|
426 |
|
|
r->buflen = n + 1; |
427 |
|
|
|
428 |
|
|
done: |
429 |
|
|
SIMPLEQ_INSERT_TAIL(&sc.parent.replies, r, entry); |
430 |
|
|
event_add(&proc_wr, NULL); |
431 |
|
|
} |
432 |
|
|
|
433 |
|
|
int |
434 |
|
|
parent_username(struct ident_resolver *r, struct passwd *pw) |
435 |
|
|
{ |
436 |
|
|
return (asprintf(&r->buf, "%s", pw->pw_name)); |
437 |
|
|
} |
438 |
|
|
|
439 |
|
|
int |
440 |
|
|
parent_uid(struct ident_resolver *r, struct passwd *pw) |
441 |
|
|
{ |
442 |
|
|
return (asprintf(&r->buf, "%u", (u_int)pw->pw_uid)); |
443 |
|
|
} |
444 |
|
|
|
445 |
|
|
int |
446 |
|
|
parent_token(struct ident_resolver *r, struct passwd *pw) |
447 |
|
|
{ |
448 |
|
|
const char *token; |
449 |
|
|
int rv; |
450 |
|
|
|
451 |
|
|
token = gentoken(); |
452 |
|
|
rv = asprintf(&r->buf, "%s", token); |
453 |
|
|
if (rv != -1) { |
454 |
|
|
if (pw) |
455 |
|
|
lnotice("token %s == uid %u (%s)", token, |
456 |
|
|
(u_int)pw->pw_uid, pw->pw_name); |
457 |
|
|
else |
458 |
|
|
lnotice("token %s == NO USER", token); |
459 |
|
|
} |
460 |
|
|
|
461 |
|
|
return (rv); |
462 |
|
|
} |
463 |
|
|
|
464 |
|
|
void |
465 |
|
|
parent_noident(struct ident_resolver *r, struct passwd *pw) |
466 |
|
|
{ |
467 |
|
|
char path[PATH_MAX]; |
468 |
|
|
struct stat st; |
469 |
|
|
int rv; |
470 |
|
|
|
471 |
|
|
rv = snprintf(path, sizeof(path), "%s/%s", pw->pw_dir, DOTNOIDENT); |
472 |
|
|
if (rv == -1 || rv >= sizeof(path)) { |
473 |
|
|
r->error = E_UNKNOWN; |
474 |
|
|
return; |
475 |
|
|
} |
476 |
|
|
|
477 |
|
|
if (stat(path, &st) == -1) |
478 |
|
|
return; |
479 |
|
|
|
480 |
|
|
r->error = E_HIDDEN; |
481 |
|
|
} |
482 |
|
|
|
483 |
|
|
void |
484 |
|
|
parent_wr(int fd, short events, void *arg) |
485 |
|
|
{ |
486 |
|
|
struct ident_resolver *r = SIMPLEQ_FIRST(&sc.parent.replies); |
487 |
|
|
struct iovec iov[2]; |
488 |
|
|
int iovcnt = 0; |
489 |
|
|
ssize_t n; |
490 |
|
|
|
491 |
|
|
iov[iovcnt].iov_base = &r->error; |
492 |
|
|
iov[iovcnt].iov_len = sizeof(r->error); |
493 |
|
|
iovcnt++; |
494 |
|
|
|
495 |
|
|
if (r->buflen > 0) { |
496 |
|
|
iov[iovcnt].iov_base = r->buf; |
497 |
|
|
iov[iovcnt].iov_len = r->buflen; |
498 |
|
|
iovcnt++; |
499 |
|
|
} |
500 |
|
|
|
501 |
|
|
n = writev(fd, iov, iovcnt); |
502 |
|
|
if (n == -1) { |
503 |
|
|
switch (errno) { |
504 |
|
|
case EINTR: |
505 |
|
|
case EAGAIN: |
506 |
|
|
event_add(&proc_wr, NULL); |
507 |
|
|
return; |
508 |
|
|
default: |
509 |
|
|
lerr(1, "parent write"); |
510 |
|
|
} |
511 |
|
|
} |
512 |
|
|
|
513 |
|
|
if (n != sizeof(r->error) + r->buflen) |
514 |
|
|
lerrx(1, "unexpected parent write length %zd", n); |
515 |
|
|
|
516 |
|
|
SIMPLEQ_REMOVE_HEAD(&sc.parent.replies, entry); |
517 |
|
|
|
518 |
|
|
if (r->buflen > 0) |
519 |
|
|
free(r->buf); |
520 |
|
|
|
521 |
|
|
free(r); |
522 |
|
|
|
523 |
|
|
if (!SIMPLEQ_EMPTY(&sc.parent.replies)) |
524 |
|
|
event_add(&proc_wr, NULL); |
525 |
|
|
} |
526 |
|
|
|
527 |
|
|
void |
528 |
|
|
child_rd(int fd, short events, void *arg) |
529 |
|
|
{ |
530 |
|
|
struct ident_client *c; |
531 |
|
|
struct { |
532 |
|
|
u_int error; |
533 |
|
|
char buf[512]; |
534 |
|
|
} reply; |
535 |
|
|
ssize_t n; |
536 |
|
|
|
537 |
|
|
n = read(fd, &reply, sizeof(reply)); |
538 |
|
|
switch (n) { |
539 |
|
|
case -1: |
540 |
|
|
switch (errno) { |
541 |
|
|
case EAGAIN: |
542 |
|
|
case EINTR: |
543 |
|
|
return; |
544 |
|
|
default: |
545 |
|
|
lerr(1, "child read"); |
546 |
|
|
} |
547 |
|
|
break; |
548 |
|
|
case 0: |
549 |
|
|
lerrx(1, "parent has gone"); |
550 |
|
|
default: |
551 |
|
|
break; |
552 |
|
|
} |
553 |
|
|
|
554 |
|
|
c = SIMPLEQ_FIRST(&sc.child.popping); |
555 |
|
|
if (c == NULL) |
556 |
|
|
lerrx(1, "unsolicited data from parent"); |
557 |
|
|
|
558 |
|
|
SIMPLEQ_REMOVE_HEAD(&sc.child.popping, entry); |
559 |
|
|
|
560 |
|
|
if (n < sizeof(reply.error)) |
561 |
|
|
lerrx(1, "short data from parent"); |
562 |
|
|
|
563 |
|
|
/* check if something went wrong while the parent was working */ |
564 |
|
|
if (c->state == S_DEAD) { |
565 |
|
|
free(c); |
566 |
|
|
return; |
567 |
|
|
} |
568 |
|
|
c->state = S_DEAD; |
569 |
|
|
|
570 |
|
|
switch (reply.error) { |
571 |
|
|
case E_NONE: |
572 |
|
|
n = asprintf(&c->buf, "%u , %u : USERID : UNIX : %s\r\n", |
573 |
|
|
c->server.port, c->client.port, reply.buf); |
574 |
|
|
break; |
575 |
|
|
case E_NOUSER: |
576 |
|
|
n = asprintf(&c->buf, "%u , %u : ERROR : %s\r\n", |
577 |
|
|
c->server.port, c->client.port, |
578 |
|
|
unknown_err ? "UNKNOWN-ERROR" : "NO-USER"); |
579 |
|
|
break; |
580 |
|
|
case E_UNKNOWN: |
581 |
|
|
n = asprintf(&c->buf, "%u , %u : ERROR : UNKNOWN-ERROR\r\n", |
582 |
|
|
c->server.port, c->client.port); |
583 |
|
|
break; |
584 |
|
|
case E_HIDDEN: |
585 |
|
|
n = asprintf(&c->buf, "%u , %u : ERROR : HIDDEN-USER\r\n", |
586 |
|
|
c->server.port, c->client.port); |
587 |
|
|
break; |
588 |
|
|
default: |
589 |
|
|
lerrx(1, "unexpected error from parent %u", reply.error); |
590 |
|
|
} |
591 |
|
|
if (n == -1) |
592 |
|
|
goto fail; |
593 |
|
|
|
594 |
|
|
c->buflen = n; |
595 |
|
|
|
596 |
|
|
fd = EVENT_FD(&c->ev); |
597 |
|
|
event_del(&c->ev); |
598 |
|
|
event_set(&c->ev, fd, EV_READ | EV_WRITE | EV_PERSIST, |
599 |
|
|
identd_response, c); |
600 |
|
|
event_add(&c->ev, NULL); |
601 |
|
|
return; |
602 |
|
|
|
603 |
|
|
fail: |
604 |
|
|
identd_close(c); |
605 |
|
|
} |
606 |
|
|
|
607 |
|
|
void |
608 |
|
|
child_wr(int fd, short events, void *arg) |
609 |
|
|
{ |
610 |
|
|
struct ident_client *c = SIMPLEQ_FIRST(&sc.child.pushing); |
611 |
|
|
const char *errstr = NULL; |
612 |
|
|
ssize_t n; |
613 |
|
|
|
614 |
|
|
n = write(fd, &c->uid, sizeof(c->uid)); |
615 |
|
|
switch (n) { |
616 |
|
|
case -1: |
617 |
|
|
switch (errno) { |
618 |
|
|
case EINTR: |
619 |
|
|
case EAGAIN: |
620 |
|
|
event_add(&proc_wr, NULL); |
621 |
|
|
return; |
622 |
|
|
case ENOBUFS: /* parent has a backlog of requests */ |
623 |
|
|
errstr = "UNKNOWN-ERROR"; |
624 |
|
|
break; |
625 |
|
|
default: |
626 |
|
|
lerr(1, "child write"); |
627 |
|
|
} |
628 |
|
|
break; |
629 |
|
|
case sizeof(c->uid): |
630 |
|
|
break; |
631 |
|
|
default: |
632 |
|
|
lerrx(1, "unexpected child write length %zd", n); |
633 |
|
|
} |
634 |
|
|
|
635 |
|
|
SIMPLEQ_REMOVE_HEAD(&sc.child.pushing, entry); |
636 |
|
|
if (errstr == NULL) |
637 |
|
|
SIMPLEQ_INSERT_TAIL(&sc.child.popping, c, entry); |
638 |
|
|
else if (identd_error(c, errstr) == -1) |
639 |
|
|
identd_close(c); |
640 |
|
|
|
641 |
|
|
if (!SIMPLEQ_EMPTY(&sc.child.pushing)) |
642 |
|
|
event_add(&proc_wr, NULL); |
643 |
|
|
} |
644 |
|
|
|
645 |
|
|
void |
646 |
|
|
identd_listen(const char *addr, const char *port, int family) |
647 |
|
|
{ |
648 |
|
|
struct identd_listener *l = NULL; |
649 |
|
|
|
650 |
|
|
struct addrinfo hints, *res, *res0; |
651 |
|
|
int error, s; |
652 |
|
|
const char *cause = NULL; |
653 |
|
|
int on = 1; |
654 |
|
|
|
655 |
|
|
memset(&hints, 0, sizeof(hints)); |
656 |
|
|
hints.ai_family = family; |
657 |
|
|
hints.ai_socktype = SOCK_STREAM; |
658 |
|
|
hints.ai_flags = AI_PASSIVE; |
659 |
|
|
|
660 |
|
|
error = getaddrinfo(addr, port, &hints, &res0); |
661 |
|
|
if (error) |
662 |
|
|
lerrx(1, "%s/%s: %s", addr, port, gai_strerror(error)); |
663 |
|
|
|
664 |
|
|
for (res = res0; res != NULL; res = res->ai_next) { |
665 |
|
|
s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK, |
666 |
|
|
res->ai_protocol); |
667 |
|
|
if (s == -1) { |
668 |
|
|
cause = "socket"; |
669 |
|
|
continue; |
670 |
|
|
} |
671 |
|
|
|
672 |
|
|
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
673 |
|
|
&on, sizeof(on)) == -1) |
674 |
|
|
err(1, "listener setsockopt(SO_REUSEADDR)"); |
675 |
|
|
|
676 |
|
|
if (bind(s, res->ai_addr, res->ai_addrlen) == -1) { |
677 |
|
|
int serrno = errno; |
678 |
|
|
|
679 |
|
|
cause = "bind"; |
680 |
|
|
close(s); |
681 |
|
|
errno = serrno; |
682 |
|
|
continue; |
683 |
|
|
} |
684 |
|
|
|
685 |
|
|
if (listen(s, 5) == -1) |
686 |
|
|
err(1, "listen"); |
687 |
|
|
|
688 |
|
|
l = calloc(1, sizeof(*l)); |
689 |
|
|
if (l == NULL) |
690 |
|
|
err(1, "listener ev alloc"); |
691 |
|
|
|
692 |
|
|
event_set(&l->ev, s, EV_READ | EV_PERSIST, identd_accept, l); |
693 |
|
|
event_add(&l->ev, NULL); |
694 |
|
|
evtimer_set(&l->pause, identd_paused, l); |
695 |
|
|
} |
696 |
|
|
if (l == NULL) |
697 |
|
|
err(1, "%s", cause); |
698 |
|
|
|
699 |
|
|
freeaddrinfo(res0); |
700 |
|
|
} |
701 |
|
|
|
702 |
|
|
void |
703 |
|
|
identd_paused(int fd, short events, void *arg) |
704 |
|
|
{ |
705 |
|
|
struct identd_listener *l = arg; |
706 |
|
|
event_add(&l->ev, NULL); |
707 |
|
|
} |
708 |
|
|
|
709 |
|
|
void |
710 |
|
|
identd_accept(int fd, short events, void *arg) |
711 |
|
|
{ |
712 |
|
|
struct identd_listener *l = arg; |
713 |
|
|
struct sockaddr_storage ss; |
714 |
|
|
struct timeval pause = { 1, 0 }; |
715 |
|
|
struct ident_client *c = NULL; |
716 |
|
|
socklen_t len; |
717 |
|
|
int s; |
718 |
|
|
|
719 |
|
|
len = sizeof(ss); |
720 |
|
|
s = accept4(fd, sa(&ss), &len, SOCK_NONBLOCK); |
721 |
|
|
if (s == -1) { |
722 |
|
|
switch (errno) { |
723 |
|
|
case EINTR: |
724 |
|
|
case EWOULDBLOCK: |
725 |
|
|
case ECONNABORTED: |
726 |
|
|
return; |
727 |
|
|
case EMFILE: |
728 |
|
|
case ENFILE: |
729 |
|
|
event_del(&l->ev); |
730 |
|
|
evtimer_add(&l->pause, &pause); |
731 |
|
|
return; |
732 |
|
|
default: |
733 |
|
|
lerr(1, "accept"); |
734 |
|
|
} |
735 |
|
|
} |
736 |
|
|
|
737 |
|
|
c = calloc(1, sizeof(*c)); |
738 |
|
|
if (c == NULL) { |
739 |
|
|
lwarn("client alloc"); |
740 |
|
|
close(fd); |
741 |
|
|
return; |
742 |
|
|
} |
743 |
|
|
|
744 |
|
|
memcpy(&c->client.ss, &ss, len); |
745 |
|
|
c->client.len = len; |
746 |
|
|
ldebug("client: %s", gethost(&ss)); |
747 |
|
|
|
748 |
|
|
/* lookup the local ip it connected to */ |
749 |
|
|
c->server.len = sizeof(c->server.ss); |
750 |
|
|
if (getsockname(s, sa(&c->server.ss), &c->server.len) == -1) |
751 |
|
|
lerr(1, "getsockname"); |
752 |
|
|
|
753 |
|
|
event_set(&c->ev, s, EV_READ | EV_PERSIST, identd_request, c); |
754 |
|
|
event_add(&c->ev, NULL); |
755 |
|
|
|
756 |
|
|
evtimer_set(&c->tmo, identd_timeout, c); |
757 |
|
|
evtimer_add(&c->tmo, &timeout); |
758 |
|
|
} |
759 |
|
|
|
760 |
|
|
void |
761 |
|
|
identd_timeout(int fd, short events, void *arg) |
762 |
|
|
{ |
763 |
|
|
struct ident_client *c = arg; |
764 |
|
|
|
765 |
|
|
event_del(&c->ev); |
766 |
|
|
close(fd); |
767 |
|
|
free(c->buf); |
768 |
|
|
|
769 |
|
|
if (c->state == S_QUEUED) /* it is queued for resolving */ |
770 |
|
|
c->state = S_DEAD; |
771 |
|
|
else |
772 |
|
|
free(c); |
773 |
|
|
} |
774 |
|
|
|
775 |
|
|
void |
776 |
|
|
identd_request(int fd, short events, void *arg) |
777 |
|
|
{ |
778 |
|
|
struct ident_client *c = arg; |
779 |
|
|
unsigned char buf[64]; |
780 |
|
|
ssize_t n, i; |
781 |
|
|
char *errstr = unknown_err ? "UNKNOWN-ERROR" : "INVALID-PORT"; |
782 |
|
|
|
783 |
|
|
n = read(fd, buf, sizeof(buf)); |
784 |
|
|
switch (n) { |
785 |
|
|
case -1: |
786 |
|
|
switch (errno) { |
787 |
|
|
case EINTR: |
788 |
|
|
case EAGAIN: |
789 |
|
|
return; |
790 |
|
|
default: |
791 |
|
|
lwarn("%s read", gethost(&c->client.ss)); |
792 |
|
|
goto fail; |
793 |
|
|
} |
794 |
|
|
break; |
795 |
|
|
|
796 |
|
|
case 0: |
797 |
|
|
ldebug("%s closed connection", gethost(&c->client.ss)); |
798 |
|
|
goto fail; |
799 |
|
|
default: |
800 |
|
|
break; |
801 |
|
|
} |
802 |
|
|
|
803 |
|
|
c->rxbytes += n; |
804 |
|
|
if (c->rxbytes >= INPUT_MAX) |
805 |
|
|
goto fail; |
806 |
|
|
|
807 |
|
|
for (i = 0; c->state < S_EOL && i < n; i++) |
808 |
|
|
c->state = identd_parse(c, buf[i]); |
809 |
|
|
|
810 |
|
|
if (c->state == S_DEAD) |
811 |
|
|
goto error; |
812 |
|
|
if (c->state != S_EOL) |
813 |
|
|
return; |
814 |
|
|
|
815 |
|
|
if (c->server.port < 1 || c->client.port < 1) |
816 |
|
|
goto error; |
817 |
|
|
|
818 |
|
|
if (fetchuid(c) == -1) { |
819 |
|
|
errstr = unknown_err ? "UNKNOWN-ERROR" : "NO-USER"; |
820 |
|
|
goto error; |
821 |
|
|
} |
822 |
|
|
|
823 |
|
|
SIMPLEQ_INSERT_TAIL(&sc.child.pushing, c, entry); |
824 |
|
|
c->state = S_QUEUED; |
825 |
|
|
|
826 |
|
|
event_del(&c->ev); |
827 |
|
|
event_set(&c->ev, fd, EV_READ | EV_PERSIST, identd_resolving, c); |
828 |
|
|
event_add(&c->ev, NULL); |
829 |
|
|
|
830 |
|
|
event_add(&proc_wr, NULL); |
831 |
|
|
return; |
832 |
|
|
|
833 |
|
|
error: |
834 |
|
|
if (identd_error(c, errstr) == -1) |
835 |
|
|
goto fail; |
836 |
|
|
|
837 |
|
|
return; |
838 |
|
|
|
839 |
|
|
fail: |
840 |
|
|
identd_close(c); |
841 |
|
|
} |
842 |
|
|
|
843 |
|
|
int |
844 |
|
|
identd_error(struct ident_client *c, const char *errstr) |
845 |
|
|
{ |
846 |
|
|
int fd = EVENT_FD(&c->ev); |
847 |
|
|
ssize_t n; |
848 |
|
|
|
849 |
|
|
n = asprintf(&c->buf, "%u , %u : ERROR : %s\r\n", |
850 |
|
|
c->server.port, c->client.port, errstr); |
851 |
|
|
if (n == -1) |
852 |
|
|
return (-1); |
853 |
|
|
|
854 |
|
|
c->buflen = n; |
855 |
|
|
|
856 |
|
|
event_del(&c->ev); |
857 |
|
|
event_set(&c->ev, fd, EV_READ | EV_WRITE | EV_PERSIST, |
858 |
|
|
identd_response, c); |
859 |
|
|
event_add(&c->ev, NULL); |
860 |
|
|
|
861 |
|
|
return (0); |
862 |
|
|
} |
863 |
|
|
|
864 |
|
|
void |
865 |
|
|
identd_close(struct ident_client *c) |
866 |
|
|
{ |
867 |
|
|
int fd = EVENT_FD(&c->ev); |
868 |
|
|
|
869 |
|
|
evtimer_del(&c->tmo); |
870 |
|
|
event_del(&c->ev); |
871 |
|
|
close(fd); |
872 |
|
|
free(c->buf); |
873 |
|
|
free(c); |
874 |
|
|
} |
875 |
|
|
|
876 |
|
|
void |
877 |
|
|
identd_resolving(int fd, short events, void *arg) |
878 |
|
|
{ |
879 |
|
|
struct ident_client *c = arg; |
880 |
|
|
char buf[64]; |
881 |
|
|
ssize_t n; |
882 |
|
|
|
883 |
|
|
/* |
884 |
|
|
* something happened while we're waiting for the parent to lookup |
885 |
|
|
* the user. |
886 |
|
|
*/ |
887 |
|
|
|
888 |
|
|
n = read(fd, buf, sizeof(buf)); |
889 |
|
|
switch (n) { |
890 |
|
|
case -1: |
891 |
|
|
switch (errno) { |
892 |
|
|
case EINTR: |
893 |
|
|
case EAGAIN: |
894 |
|
|
return; |
895 |
|
|
default: |
896 |
|
|
lwarn("resolving read"); |
897 |
|
|
break; |
898 |
|
|
} |
899 |
|
|
break; |
900 |
|
|
case 0: |
901 |
|
|
ldebug("%s closed connection during resolving", |
902 |
|
|
gethost(&c->client.ss)); |
903 |
|
|
break; |
904 |
|
|
default: |
905 |
|
|
c->rxbytes += n; |
906 |
|
|
if (c->rxbytes >= INPUT_MAX) |
907 |
|
|
break; |
908 |
|
|
|
909 |
|
|
/* ignore extra input */ |
910 |
|
|
return; |
911 |
|
|
} |
912 |
|
|
|
913 |
|
|
evtimer_del(&c->tmo); |
914 |
|
|
event_del(&c->ev); |
915 |
|
|
close(fd); |
916 |
|
|
c->state = S_DEAD; /* on the resolving queue */ |
917 |
|
|
} |
918 |
|
|
|
919 |
|
|
enum ident_client_state |
920 |
|
|
identd_parse(struct ident_client *c, int ch) |
921 |
|
|
{ |
922 |
|
|
enum ident_client_state s = c->state; |
923 |
|
|
|
924 |
|
|
switch (s) { |
925 |
|
|
case S_BEGINNING: |
926 |
|
|
/* ignore leading space */ |
927 |
|
|
if (ch == '\t' || ch == ' ') |
928 |
|
|
return (s); |
929 |
|
|
|
930 |
|
|
if (ch == '0' || !isdigit(ch)) |
931 |
|
|
return (S_DEAD); |
932 |
|
|
|
933 |
|
|
c->server.port = ch - '0'; |
934 |
|
|
return (S_SERVER_PORT); |
935 |
|
|
|
936 |
|
|
case S_SERVER_PORT: |
937 |
|
|
if (ch == '\t' || ch == ' ') |
938 |
|
|
return (S_PRE_COMMA); |
939 |
|
|
if (ch == ',') |
940 |
|
|
return (S_POST_COMMA); |
941 |
|
|
|
942 |
|
|
if (!isdigit(ch)) |
943 |
|
|
return (S_DEAD); |
944 |
|
|
|
945 |
|
|
c->server.port *= 10; |
946 |
|
|
c->server.port += ch - '0'; |
947 |
|
|
if (c->server.port > 65535) |
948 |
|
|
return (S_DEAD); |
949 |
|
|
|
950 |
|
|
return (s); |
951 |
|
|
|
952 |
|
|
case S_PRE_COMMA: |
953 |
|
|
if (ch == '\t' || ch == ' ') |
954 |
|
|
return (s); |
955 |
|
|
if (ch == ',') |
956 |
|
|
return (S_POST_COMMA); |
957 |
|
|
|
958 |
|
|
return (S_DEAD); |
959 |
|
|
|
960 |
|
|
case S_POST_COMMA: |
961 |
|
|
if (ch == '\t' || ch == ' ') |
962 |
|
|
return (s); |
963 |
|
|
|
964 |
|
|
if (ch == '0' || !isdigit(ch)) |
965 |
|
|
return (S_DEAD); |
966 |
|
|
|
967 |
|
|
c->client.port = ch - '0'; |
968 |
|
|
return (S_CLIENT_PORT); |
969 |
|
|
|
970 |
|
|
case S_CLIENT_PORT: |
971 |
|
|
if (ch == '\t' || ch == ' ') |
972 |
|
|
return (S_PRE_EOL); |
973 |
|
|
if (ch == '\r' || ch == '\n') |
974 |
|
|
return (S_EOL); |
975 |
|
|
|
976 |
|
|
if (!isdigit(ch)) |
977 |
|
|
return (S_DEAD); |
978 |
|
|
|
979 |
|
|
c->client.port *= 10; |
980 |
|
|
c->client.port += ch - '0'; |
981 |
|
|
if (c->client.port > 65535) |
982 |
|
|
return (S_DEAD); |
983 |
|
|
|
984 |
|
|
return (s); |
985 |
|
|
|
986 |
|
|
case S_PRE_EOL: |
987 |
|
|
if (ch == '\t' || ch == ' ') |
988 |
|
|
return (s); |
989 |
|
|
if (ch == '\r' || ch == '\n') |
990 |
|
|
return (S_EOL); |
991 |
|
|
|
992 |
|
|
return (S_DEAD); |
993 |
|
|
|
994 |
|
|
case S_EOL: |
995 |
|
|
/* ignore trailing garbage */ |
996 |
|
|
return (s); |
997 |
|
|
|
998 |
|
|
default: |
999 |
|
|
return (S_DEAD); |
1000 |
|
|
} |
1001 |
|
|
} |
1002 |
|
|
|
1003 |
|
|
void |
1004 |
|
|
identd_response(int fd, short events, void *arg) |
1005 |
|
|
{ |
1006 |
|
|
struct ident_client *c = arg; |
1007 |
|
|
char buf[64]; |
1008 |
|
|
ssize_t n; |
1009 |
|
|
|
1010 |
|
|
if (events & EV_READ) { |
1011 |
|
|
n = read(fd, buf, sizeof(buf)); |
1012 |
|
|
switch (n) { |
1013 |
|
|
case -1: |
1014 |
|
|
switch (errno) { |
1015 |
|
|
case EINTR: |
1016 |
|
|
case EAGAIN: |
1017 |
|
|
/* meh, try a write */ |
1018 |
|
|
break; |
1019 |
|
|
default: |
1020 |
|
|
lwarn("response read"); |
1021 |
|
|
goto done; |
1022 |
|
|
} |
1023 |
|
|
break; |
1024 |
|
|
case 0: |
1025 |
|
|
ldebug("%s closed connection during response", |
1026 |
|
|
gethost(&c->client.ss)); |
1027 |
|
|
goto done; |
1028 |
|
|
default: |
1029 |
|
|
c->rxbytes += n; |
1030 |
|
|
if (c->rxbytes >= INPUT_MAX) |
1031 |
|
|
goto done; |
1032 |
|
|
|
1033 |
|
|
/* ignore extra input */ |
1034 |
|
|
break; |
1035 |
|
|
} |
1036 |
|
|
} |
1037 |
|
|
|
1038 |
|
|
if (!(events & EV_WRITE)) |
1039 |
|
|
return; /* try again later */ |
1040 |
|
|
|
1041 |
|
|
n = write(fd, c->buf + c->bufoff, c->buflen - c->bufoff); |
1042 |
|
|
if (n == -1) { |
1043 |
|
|
switch (errno) { |
1044 |
|
|
case EINTR: |
1045 |
|
|
case EAGAIN: |
1046 |
|
|
return; /* try again later */ |
1047 |
|
|
case EPIPE: |
1048 |
|
|
goto done; |
1049 |
|
|
default: |
1050 |
|
|
lwarn("response write"); |
1051 |
|
|
goto done; |
1052 |
|
|
} |
1053 |
|
|
} |
1054 |
|
|
|
1055 |
|
|
c->bufoff += n; |
1056 |
|
|
if (c->bufoff != c->buflen) |
1057 |
|
|
return; /* try again later */ |
1058 |
|
|
|
1059 |
|
|
done: |
1060 |
|
|
identd_close(c); |
1061 |
|
|
} |
1062 |
|
|
|
1063 |
|
|
void |
1064 |
|
|
syslog_vstrerror(int e, int priority, const char *fmt, va_list ap) |
1065 |
|
|
{ |
1066 |
|
|
char *s; |
1067 |
|
|
|
1068 |
|
|
if (vasprintf(&s, fmt, ap) == -1) { |
1069 |
|
|
syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror"); |
1070 |
|
|
exit(1); |
1071 |
|
|
} |
1072 |
|
|
syslog(priority, "%s: %s", s, strerror(e)); |
1073 |
|
|
free(s); |
1074 |
|
|
} |
1075 |
|
|
|
1076 |
|
|
void |
1077 |
|
|
syslog_err(int ecode, const char *fmt, ...) |
1078 |
|
|
{ |
1079 |
|
|
va_list ap; |
1080 |
|
|
|
1081 |
|
|
va_start(ap, fmt); |
1082 |
|
|
syslog_vstrerror(errno, LOG_CRIT, fmt, ap); |
1083 |
|
|
va_end(ap); |
1084 |
|
|
exit(ecode); |
1085 |
|
|
} |
1086 |
|
|
|
1087 |
|
|
void |
1088 |
|
|
syslog_errx(int ecode, const char *fmt, ...) |
1089 |
|
|
{ |
1090 |
|
|
va_list ap; |
1091 |
|
|
|
1092 |
|
|
va_start(ap, fmt); |
1093 |
|
|
vsyslog(LOG_CRIT, fmt, ap); |
1094 |
|
|
va_end(ap); |
1095 |
|
|
exit(ecode); |
1096 |
|
|
} |
1097 |
|
|
|
1098 |
|
|
void |
1099 |
|
|
syslog_warn(const char *fmt, ...) |
1100 |
|
|
{ |
1101 |
|
|
va_list ap; |
1102 |
|
|
|
1103 |
|
|
va_start(ap, fmt); |
1104 |
|
|
syslog_vstrerror(errno, LOG_ERR, fmt, ap); |
1105 |
|
|
va_end(ap); |
1106 |
|
|
} |
1107 |
|
|
|
1108 |
|
|
void |
1109 |
|
|
syslog_warnx(const char *fmt, ...) |
1110 |
|
|
{ |
1111 |
|
|
va_list ap; |
1112 |
|
|
|
1113 |
|
|
va_start(ap, fmt); |
1114 |
|
|
vsyslog(LOG_ERR, fmt, ap); |
1115 |
|
|
va_end(ap); |
1116 |
|
|
} |
1117 |
|
|
|
1118 |
|
|
void |
1119 |
|
|
syslog_notice(const char *fmt, ...) |
1120 |
|
|
{ |
1121 |
|
|
va_list ap; |
1122 |
|
|
|
1123 |
|
|
va_start(ap, fmt); |
1124 |
|
|
vsyslog(LOG_NOTICE, fmt, ap); |
1125 |
|
|
va_end(ap); |
1126 |
|
|
} |
1127 |
|
|
|
1128 |
|
|
void |
1129 |
|
|
syslog_debug(const char *fmt, ...) |
1130 |
|
|
{ |
1131 |
|
|
va_list ap; |
1132 |
|
|
|
1133 |
|
|
if (!debug) |
1134 |
|
|
return; |
1135 |
|
|
|
1136 |
|
|
va_start(ap, fmt); |
1137 |
|
|
vsyslog(LOG_DEBUG, fmt, ap); |
1138 |
|
|
va_end(ap); |
1139 |
|
|
} |
1140 |
|
|
|
1141 |
|
|
const char * |
1142 |
|
|
gethost(struct sockaddr_storage *ss) |
1143 |
|
|
{ |
1144 |
|
|
struct sockaddr *sa = (struct sockaddr *)ss; |
1145 |
|
|
static char buf[NI_MAXHOST]; |
1146 |
|
|
|
1147 |
|
|
if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), |
1148 |
|
|
NULL, 0, NI_NUMERICHOST) != 0) |
1149 |
|
|
return ("(unknown)"); |
1150 |
|
|
|
1151 |
|
|
return (buf); |
1152 |
|
|
} |
1153 |
|
|
|
1154 |
|
|
const char * |
1155 |
|
|
gentoken(void) |
1156 |
|
|
{ |
1157 |
|
|
static char buf[21]; |
1158 |
|
|
u_int32_t r; |
1159 |
|
|
int i; |
1160 |
|
|
|
1161 |
|
|
buf[0] = 'a' + arc4random_uniform(26); |
1162 |
|
|
for (i = 1; i < sizeof(buf) - 1; i++) { |
1163 |
|
|
r = arc4random_uniform(36); |
1164 |
|
|
buf[i] = (r < 26 ? 'a' : '0' - 26) + r; |
1165 |
|
|
} |
1166 |
|
|
buf[i] = '\0'; |
1167 |
|
|
|
1168 |
|
|
return (buf); |
1169 |
|
|
} |
1170 |
|
|
|
1171 |
|
|
int |
1172 |
|
|
fetchuid(struct ident_client *c) |
1173 |
|
|
{ |
1174 |
|
|
struct tcp_ident_mapping tir; |
1175 |
|
|
int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT }; |
1176 |
|
|
struct sockaddr_in *s4; |
1177 |
|
|
struct sockaddr_in6 *s6; |
1178 |
|
|
int err = 0; |
1179 |
|
|
size_t len; |
1180 |
|
|
|
1181 |
|
|
memset(&tir, 0, sizeof(tir)); |
1182 |
|
|
memcpy(&tir.faddr, &c->client.ss, sizeof(tir.faddr)); |
1183 |
|
|
memcpy(&tir.laddr, &c->server.ss, sizeof(tir.laddr)); |
1184 |
|
|
|
1185 |
|
|
switch (c->server.ss.ss_family) { |
1186 |
|
|
case AF_INET: |
1187 |
|
|
s4 = (struct sockaddr_in *)&tir.faddr; |
1188 |
|
|
s4->sin_port = htons(c->client.port); |
1189 |
|
|
|
1190 |
|
|
s4 = (struct sockaddr_in *)&tir.laddr; |
1191 |
|
|
s4->sin_port = htons(c->server.port); |
1192 |
|
|
break; |
1193 |
|
|
case AF_INET6: |
1194 |
|
|
s6 = (struct sockaddr_in6 *)&tir.faddr; |
1195 |
|
|
s6->sin6_port = htons(c->client.port); |
1196 |
|
|
|
1197 |
|
|
s6 = (struct sockaddr_in6 *)&tir.laddr; |
1198 |
|
|
s6->sin6_port = htons(c->server.port); |
1199 |
|
|
break; |
1200 |
|
|
default: |
1201 |
|
|
lerrx(1, "unexpected family %d", c->server.ss.ss_family); |
1202 |
|
|
} |
1203 |
|
|
|
1204 |
|
|
len = sizeof(tir); |
1205 |
|
|
err = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &tir, &len, NULL, 0); |
1206 |
|
|
if (err == -1) |
1207 |
|
|
lerr(1, "sysctl"); |
1208 |
|
|
|
1209 |
|
|
if (tir.ruid == -1) |
1210 |
|
|
return (-1); |
1211 |
|
|
|
1212 |
|
|
c->uid = tir.ruid; |
1213 |
|
|
return (0); |
1214 |
|
|
} |