Bug Summary

File:src/usr.sbin/identd/identd.c
Warning:line 279, column 2
Value stored to 'argv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name identd.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/identd/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/identd/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/identd/identd.c
1/* $OpenBSD: identd.c,v 1.40 2019/07/03 03:24:03 deraadt 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/queue.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(*__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" "_identd"
50
51#define DOTNOIDENT".noident" ".noident"
52
53#define TIMEOUT_MIN4 4
54#define TIMEOUT_MAX240 240
55#define TIMEOUT_DEFAULT120 120
56#define INPUT_MAX256 256
57
58enum 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_NONE0 0
72#define E_NOUSER1 1
73#define E_UNKNOWN2 2
74#define E_HIDDEN3 3
75
76struct 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)struct { struct ident_client *sqe_next; } 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
97struct ident_resolver {
98 SIMPLEQ_ENTRY(ident_resolver)struct { struct ident_resolver *sqe_next; } entry;
99 char *buf;
100 size_t buflen;
101 u_int error;
102};
103
104struct identd_listener {
105 struct event ev, pause;
106};
107
108void parent_rd(int, short, void *);
109void parent_wr(int, short, void *);
110int parent_username(struct ident_resolver *, struct passwd *);
111int parent_uid(struct ident_resolver *, struct passwd *);
112int parent_token(struct ident_resolver *, struct passwd *);
113void parent_noident(struct ident_resolver *, struct passwd *);
114
115void child_rd(int, short, void *);
116void child_wr(int, short, void *);
117
118void identd_listen(const char *, const char *, int);
119void identd_paused(int, short, void *);
120void identd_accept(int, short, void *);
121int identd_error(struct ident_client *, const char *);
122void identd_close(struct ident_client *);
123void identd_timeout(int, short, void *);
124void identd_request(int, short, void *);
125enum ident_client_state
126 identd_parse(struct ident_client *, int);
127void identd_resolving(int, short, void *);
128void identd_response(int, short, void *);
129int fetchuid(struct ident_client *);
130
131const char *gethost(struct sockaddr_storage *);
132const char *gentoken(void);
133
134struct loggers {
135 __dead__attribute__((__noreturn__)) void (*err)(int, const char *, ...)
136 __attribute__((__format__ (printf, 2, 3)));
137 __dead__attribute__((__noreturn__)) 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
149const struct loggers conslogger = {
150 err,
151 errx,
152 warn,
153 warnx,
154 warnx, /* notice */
155 warnx /* debug */
156};
157
158__dead__attribute__((__noreturn__)) void syslog_err(int, const char *, ...)
159 __attribute__((__format__ (printf, 2, 3)));
160__dead__attribute__((__noreturn__)) void syslog_errx(int, const char *, ...)
161 __attribute__((__format__ (printf, 2, 3)));
162void syslog_warn(const char *, ...)
163 __attribute__((__format__ (printf, 1, 2)));
164void syslog_warnx(const char *, ...)
165 __attribute__((__format__ (printf, 1, 2)));
166void syslog_notice(const char *, ...)
167 __attribute__((__format__ (printf, 1, 2)));
168void syslog_debug(const char *, ...)
169 __attribute__((__format__ (printf, 1, 2)));
170void syslog_vstrerror(int, int, const char *, va_list)
171 __attribute__((__format__ (printf, 3, 0)));
172
173const struct loggers syslogger = {
174 syslog_err,
175 syslog_errx,
176 syslog_warn,
177 syslog_warnx,
178 syslog_notice,
179 syslog_debug
180};
181
182const struct loggers *logger = &conslogger;
183
184#define lerr(_e, _f...)logger->err((_e), _f...) logger->err((_e), _f)
185#define lerrx(_e, _f...)logger->errx((_e), _f...) logger->errx((_e), _f)
186#define lwarn(_f...)logger->warn(_f...) logger->warn(_f)
187#define lwarnx(_f...)logger->warnx(_f...) logger->warnx(_f)
188#define lnotice(_f...)logger->notice(_f...) logger->notice(_f)
189#define ldebug(_f...)logger->debug(_f...) logger->debug(_f)
190
191#define sa(_ss)((struct sockaddr *)(_ss)) ((struct sockaddr *)(_ss))
192
193static __dead__attribute__((__noreturn__)) void
194usage(void)
195{
196 extern char *__progname;
197 fprintf(stderr(&__sF[2]), "usage: %s [-46deHhNn] [-l address] [-t timeout]\n",
198 __progname);
199 exit(1);
200}
201
202struct timeval timeout = { TIMEOUT_DEFAULT120, 0 };
203int debug = 0;
204int noident = 0;
205int unknown_err = 0;
206int hideall = 0;
207
208int (*parent_uprintf)(struct ident_resolver *, struct passwd *) =
209 parent_username;
210
211struct event proc_rd, proc_wr;
212union {
213 struct {
214 SIMPLEQ_HEAD(, ident_resolver)struct { struct ident_resolver *sqh_first; struct ident_resolver
**sqh_last; }
replies;
215 } parent;
216 struct {
217 SIMPLEQ_HEAD(, ident_client)struct { struct ident_client *sqh_first; struct ident_client *
*sqh_last; }
pushing, popping;
218 } child;
219} sc;
220
221int
222main(int argc, char *argv[])
223{
224 extern char *__progname;
225 const char *errstr = NULL((void *)0);
226
227 int c;
228 struct passwd *pw;
229
230 char *addr = NULL((void *)0);
231 int family = AF_UNSPEC0;
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_INET2;
241 break;
242 case '6':
243 family = AF_INET624;
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_MIN4, TIMEOUT_MAX240, &errstr);
269 if (errstr != NULL((void *)0))
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;
Value stored to 'argv' is never read
280
281 if (argc != 0)
282 usage();
283
284 if (geteuid() != 0)
285 errx(1, "need root privileges");
286
287 if (socketpair(AF_UNIX1, SOCK_SEQPACKET5 | SOCK_NONBLOCK0x4000,
288 PF_UNSPEC0, pair) == -1)
289 err(1, "socketpair");
290
291 pw = getpwnam(IDENTD_USER"_identd");
292 if (pw == NULL((void *)0))
293 errx(1, "no %s user", IDENTD_USER"_identd");
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")logger->err((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_PID0x01|LOG_NDELAY0x08, LOG_DAEMON(3<<3));
320 tzset();
321 logger = &syslogger;
322 }
323
324 event_init();
325
326 if (signal(SIGPIPE13, SIG_IGN(void (*)(int))1) == SIG_ERR(void (*)(int))-1)
327 lerr(1, "signal(SIGPIPE)")logger->err((1), "signal(SIGPIPE)");
328
329 if (parent) {
330 if (pledge("stdio getpw rpath id", NULL((void *)0)) == -1)
331 err(1, "pledge");
332
333 SIMPLEQ_INIT(&sc.parent.replies)do { (&sc.parent.replies)->sqh_first = ((void *)0); (&
sc.parent.replies)->sqh_last = &(&sc.parent.replies
)->sqh_first; } while (0)
;
334
335 event_set(&proc_rd, sibling, EV_READ0x02 | EV_PERSIST0x10,
336 parent_rd, NULL((void *)0));
337 event_set(&proc_wr, sibling, EV_WRITE0x04,
338 parent_wr, NULL((void *)0));
339 } else {
340 SIMPLEQ_INIT(&sc.child.pushing)do { (&sc.child.pushing)->sqh_first = ((void *)0); (&
sc.child.pushing)->sqh_last = &(&sc.child.pushing)
->sqh_first; } while (0)
;
341 SIMPLEQ_INIT(&sc.child.popping)do { (&sc.child.popping)->sqh_first = ((void *)0); (&
sc.child.popping)->sqh_last = &(&sc.child.popping)
->sqh_first; } while (0)
;
342
343 identd_listen(addr, "auth", family);
344
345 if (chroot(pw->pw_dir) == -1)
346 lerr(1, "chroot(%s)", pw->pw_dir)logger->err((1), "chroot(%s)", pw->pw_dir);
347
348 if (chdir("/") == -1)
349 lerr(1, "chdir(%s)", pw->pw_dir)logger->err((1), "chdir(%s)", pw->pw_dir);
350
351 event_set(&proc_rd, sibling, EV_READ0x02 | EV_PERSIST0x10,
352 child_rd, NULL((void *)0));
353 event_set(&proc_wr, sibling, EV_WRITE0x04,
354 child_wr, NULL((void *)0));
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")logger->err((1), "unable to revoke privs");
361
362 if (parent) {
363 if (noident) {
364 if (pledge("stdio getpw rpath", NULL((void *)0)) == -1)
365 err(1, "pledge");
366 } else {
367 if (pledge("stdio getpw", NULL((void *)0)) == -1)
368 err(1, "pledge");
369 }
370 }
371
372 event_add(&proc_rd, NULL((void *)0));
373 event_dispatch();
374 return (0);
375}
376
377void
378parent_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(*__errno())) {
389 case EAGAIN35:
390 case EINTR4:
391 return;
392 default:
393 lerr(1, "parent read")logger->err((1), "parent read");
394 }
395 break;
396 case 0:
397 lerrx(1, "child has gone")logger->errx((1), "child has gone");
398 case sizeof(uid):
399 break;
400 default:
401 lerrx(1, "unexpected %zd data from child", n)logger->errx((1), "unexpected %zd data from child", n);
402 }
403
404 r = calloc(1, sizeof(*r));
405 if (r == NULL((void *)0))
406 lerr(1, "resolver alloc")logger->err((1), "resolver alloc");
407
408 pw = getpwuid(uid);
409 if (pw == NULL((void *)0) && !hideall) {
410 r->error = E_NOUSER1;
411 goto done;
412 }
413
414 if (noident && !hideall) {
415 parent_noident(r, pw);
416 if (r->error != E_NONE0)
417 goto done;
418 }
419
420 n = (*parent_uprintf)(r, pw);
421 if (n == -1) {
422 r->error = E_UNKNOWN2;
423 goto done;
424 }
425
426 r->buflen = n + 1;
427
428done:
429 SIMPLEQ_INSERT_TAIL(&sc.parent.replies, r, entry)do { (r)->entry.sqe_next = ((void *)0); *(&sc.parent.replies
)->sqh_last = (r); (&sc.parent.replies)->sqh_last =
&(r)->entry.sqe_next; } while (0)
;
430 event_add(&proc_wr, NULL((void *)0));
431}
432
433int
434parent_username(struct ident_resolver *r, struct passwd *pw)
435{
436 return (asprintf(&r->buf, "%s", pw->pw_name));
437}
438
439int
440parent_uid(struct ident_resolver *r, struct passwd *pw)
441{
442 return (asprintf(&r->buf, "%u", (u_int)pw->pw_uid));
443}
444
445int
446parent_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,logger->notice("token %s == uid %u (%s)", token, (u_int)pw
->pw_uid, pw->pw_name)
456 (u_int)pw->pw_uid, pw->pw_name)logger->notice("token %s == uid %u (%s)", token, (u_int)pw
->pw_uid, pw->pw_name)
;
457 else
458 lnotice("token %s == NO USER", token)logger->notice("token %s == NO USER", token);
459 }
460
461 return (rv);
462}
463
464void
465parent_noident(struct ident_resolver *r, struct passwd *pw)
466{
467 char path[PATH_MAX1024];
468 struct stat st;
469 int rv;
470
471 rv = snprintf(path, sizeof(path), "%s/%s", pw->pw_dir, DOTNOIDENT".noident");
472 if (rv < 0 || rv >= sizeof(path)) {
473 r->error = E_UNKNOWN2;
474 return;
475 }
476
477 if (stat(path, &st) == -1)
478 return;
479
480 r->error = E_HIDDEN3;
481}
482
483void
484parent_wr(int fd, short events, void *arg)
485{
486 struct ident_resolver *r = SIMPLEQ_FIRST(&sc.parent.replies)((&sc.parent.replies)->sqh_first);
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(*__errno())) {
504 case EINTR4:
505 case EAGAIN35:
506 event_add(&proc_wr, NULL((void *)0));
507 return;
508 default:
509 lerr(1, "parent write")logger->err((1), "parent write");
510 }
511 }
512
513 if (n != sizeof(r->error) + r->buflen)
514 lerrx(1, "unexpected parent write length %zd", n)logger->errx((1), "unexpected parent write length %zd", n);
515
516 SIMPLEQ_REMOVE_HEAD(&sc.parent.replies, entry)do { if (((&sc.parent.replies)->sqh_first = (&sc.parent
.replies)->sqh_first->entry.sqe_next) == ((void *)0)) (
&sc.parent.replies)->sqh_last = &(&sc.parent.replies
)->sqh_first; } while (0)
;
517
518 if (r->buflen > 0)
519 free(r->buf);
520
521 free(r);
522
523 if (!SIMPLEQ_EMPTY(&sc.parent.replies)(((&sc.parent.replies)->sqh_first) == ((void *)0)))
524 event_add(&proc_wr, NULL((void *)0));
525}
526
527void
528child_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(*__errno())) {
541 case EAGAIN35:
542 case EINTR4:
543 return;
544 default:
545 lerr(1, "child read")logger->err((1), "child read");
546 }
547 break;
548 case 0:
549 lerrx(1, "parent has gone")logger->errx((1), "parent has gone");
550 default:
551 break;
552 }
553
554 c = SIMPLEQ_FIRST(&sc.child.popping)((&sc.child.popping)->sqh_first);
555 if (c == NULL((void *)0))
556 lerrx(1, "unsolicited data from parent")logger->errx((1), "unsolicited data from parent");
557
558 SIMPLEQ_REMOVE_HEAD(&sc.child.popping, entry)do { if (((&sc.child.popping)->sqh_first = (&sc.child
.popping)->sqh_first->entry.sqe_next) == ((void *)0)) (
&sc.child.popping)->sqh_last = &(&sc.child.popping
)->sqh_first; } while (0)
;
559
560 if (n < sizeof(reply.error))
561 lerrx(1, "short data from parent")logger->errx((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_NONE0:
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_NOUSER1:
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_UNKNOWN2:
581 n = asprintf(&c->buf, "%u , %u : ERROR : UNKNOWN-ERROR\r\n",
582 c->server.port, c->client.port);
583 break;
584 case E_HIDDEN3:
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)logger->errx((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)(int)(&c->ev)->ev_fd;
597 event_del(&c->ev);
598 event_set(&c->ev, fd, EV_READ0x02 | EV_WRITE0x04 | EV_PERSIST0x10,
599 identd_response, c);
600 event_add(&c->ev, NULL((void *)0));
601 return;
602
603fail:
604 identd_close(c);
605}
606
607void
608child_wr(int fd, short events, void *arg)
609{
610 struct ident_client *c = SIMPLEQ_FIRST(&sc.child.pushing)((&sc.child.pushing)->sqh_first);
611 const char *errstr = NULL((void *)0);
612 ssize_t n;
613
614 n = write(fd, &c->uid, sizeof(c->uid));
615 switch (n) {
616 case -1:
617 switch (errno(*__errno())) {
618 case EINTR4:
619 case EAGAIN35:
620 event_add(&proc_wr, NULL((void *)0));
621 return;
622 case ENOBUFS55: /* parent has a backlog of requests */
623 errstr = "UNKNOWN-ERROR";
624 break;
625 default:
626 lerr(1, "child write")logger->err((1), "child write");
627 }
628 break;
629 case sizeof(c->uid):
630 break;
631 default:
632 lerrx(1, "unexpected child write length %zd", n)logger->errx((1), "unexpected child write length %zd", n);
633 }
634
635 SIMPLEQ_REMOVE_HEAD(&sc.child.pushing, entry)do { if (((&sc.child.pushing)->sqh_first = (&sc.child
.pushing)->sqh_first->entry.sqe_next) == ((void *)0)) (
&sc.child.pushing)->sqh_last = &(&sc.child.pushing
)->sqh_first; } while (0)
;
636 if (errstr == NULL((void *)0))
637 SIMPLEQ_INSERT_TAIL(&sc.child.popping, c, entry)do { (c)->entry.sqe_next = ((void *)0); *(&sc.child.popping
)->sqh_last = (c); (&sc.child.popping)->sqh_last = &
(c)->entry.sqe_next; } while (0)
;
638 else if (identd_error(c, errstr) == -1)
639 identd_close(c);
640
641 if (!SIMPLEQ_EMPTY(&sc.child.pushing)(((&sc.child.pushing)->sqh_first) == ((void *)0)))
642 event_add(&proc_wr, NULL((void *)0));
643}
644
645void
646identd_listen(const char *addr, const char *port, int family)
647{
648 struct identd_listener *l = NULL((void *)0);
649
650 struct addrinfo hints, *res, *res0;
651 int error, s;
652 const char *cause = NULL((void *)0);
653 int on = 1;
654
655 memset(&hints, 0, sizeof(hints));
656 hints.ai_family = family;
657 hints.ai_socktype = SOCK_STREAM1;
658 hints.ai_flags = AI_PASSIVE1;
659
660 error = getaddrinfo(addr, port, &hints, &res0);
661 if (error)
662 lerrx(1, "%s/%s: %s", addr, port, gai_strerror(error))logger->errx((1), "%s/%s: %s", addr, port, gai_strerror(error
))
;
663
664 for (res = res0; res != NULL((void *)0); res = res->ai_next) {
665 s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK0x4000,
666 res->ai_protocol);
667 if (s == -1) {
668 cause = "socket";
669 continue;
670 }
671
672 if (setsockopt(s, SOL_SOCKET0xffff, SO_REUSEADDR0x0004,
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(*__errno());
678
679 cause = "bind";
680 close(s);
681 errno(*__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((void *)0))
690 err(1, "listener ev alloc");
691
692 event_set(&l->ev, s, EV_READ0x02 | EV_PERSIST0x10, identd_accept, l);
693 event_add(&l->ev, NULL((void *)0));
694 evtimer_set(&l->pause, identd_paused, l)event_set(&l->pause, -1, 0, identd_paused, l);
695 }
696 if (l == NULL((void *)0))
697 err(1, "%s", cause);
698
699 freeaddrinfo(res0);
700}
701
702void
703identd_paused(int fd, short events, void *arg)
704{
705 struct identd_listener *l = arg;
706 event_add(&l->ev, NULL((void *)0));
707}
708
709void
710identd_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((void *)0);
716 socklen_t len;
717 int s;
718
719 len = sizeof(ss);
720 s = accept4(fd, sa(&ss)((struct sockaddr *)(&ss)), &len, SOCK_NONBLOCK0x4000);
721 if (s == -1) {
722 switch (errno(*__errno())) {
723 case EINTR4:
724 case EWOULDBLOCK35:
725 case ECONNABORTED53:
726 return;
727 case EMFILE24:
728 case ENFILE23:
729 event_del(&l->ev);
730 evtimer_add(&l->pause, &pause)event_add(&l->pause, &pause);
731 return;
732 default:
733 lerr(1, "accept")logger->err((1), "accept");
734 }
735 }
736
737 c = calloc(1, sizeof(*c));
738 if (c == NULL((void *)0)) {
739 lwarn("client alloc")logger->warn("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))logger->debug("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)((struct sockaddr *)(&c->server.ss)), &c->server.len) == -1)
751 lerr(1, "getsockname")logger->err((1), "getsockname");
752
753 event_set(&c->ev, s, EV_READ0x02 | EV_PERSIST0x10, identd_request, c);
754 event_add(&c->ev, NULL((void *)0));
755
756 evtimer_set(&c->tmo, identd_timeout, c)event_set(&c->tmo, -1, 0, identd_timeout, c);
757 evtimer_add(&c->tmo, &timeout)event_add(&c->tmo, &timeout);
758}
759
760void
761identd_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
775void
776identd_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(*__errno())) {
787 case EINTR4:
788 case EAGAIN35:
789 return;
790 default:
791 lwarn("%s read", gethost(&c->client.ss))logger->warn("%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))logger->debug("%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_MAX256)
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)do { (c)->entry.sqe_next = ((void *)0); *(&sc.child.pushing
)->sqh_last = (c); (&sc.child.pushing)->sqh_last = &
(c)->entry.sqe_next; } while (0)
;
824 c->state = S_QUEUED;
825
826 event_del(&c->ev);
827 event_set(&c->ev, fd, EV_READ0x02 | EV_PERSIST0x10, identd_resolving, c);
828 event_add(&c->ev, NULL((void *)0));
829
830 event_add(&proc_wr, NULL((void *)0));
831 return;
832
833error:
834 if (identd_error(c, errstr) == -1)
835 goto fail;
836
837 return;
838
839fail:
840 identd_close(c);
841}
842
843int
844identd_error(struct ident_client *c, const char *errstr)
845{
846 int fd = EVENT_FD(&c->ev)(int)(&c->ev)->ev_fd;
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_READ0x02 | EV_WRITE0x04 | EV_PERSIST0x10,
858 identd_response, c);
859 event_add(&c->ev, NULL((void *)0));
860
861 return (0);
862}
863
864void
865identd_close(struct ident_client *c)
866{
867 int fd = EVENT_FD(&c->ev)(int)(&c->ev)->ev_fd;
868
869 evtimer_del(&c->tmo)event_del(&c->tmo);
870 event_del(&c->ev);
871 close(fd);
872 free(c->buf);
873 free(c);
874}
875
876void
877identd_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(*__errno())) {
892 case EINTR4:
893 case EAGAIN35:
894 return;
895 default:
896 lwarn("resolving read")logger->warn("resolving read");
897 break;
898 }
899 break;
900 case 0:
901 ldebug("%s closed connection during resolving",logger->debug("%s closed connection during resolving", gethost
(&c->client.ss))
902 gethost(&c->client.ss))logger->debug("%s closed connection during resolving", gethost
(&c->client.ss))
;
903 break;
904 default:
905 c->rxbytes += n;
906 if (c->rxbytes >= INPUT_MAX256)
907 break;
908
909 /* ignore extra input */
910 return;
911 }
912
913 evtimer_del(&c->tmo)event_del(&c->tmo);
914 event_del(&c->ev);
915 close(fd);
916 c->state = S_DEAD; /* on the resolving queue */
917}
918
919enum ident_client_state
920identd_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
1003void
1004identd_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_READ0x02) {
1011 n = read(fd, buf, sizeof(buf));
1012 switch (n) {
1013 case -1:
1014 switch (errno(*__errno())) {
1015 case EINTR4:
1016 case EAGAIN35:
1017 /* meh, try a write */
1018 break;
1019 default:
1020 lwarn("response read")logger->warn("response read");
1021 goto done;
1022 }
1023 break;
1024 case 0:
1025 ldebug("%s closed connection during response",logger->debug("%s closed connection during response", gethost
(&c->client.ss))
1026 gethost(&c->client.ss))logger->debug("%s closed connection during response", gethost
(&c->client.ss))
;
1027 goto done;
1028 default:
1029 c->rxbytes += n;
1030 if (c->rxbytes >= INPUT_MAX256)
1031 goto done;
1032
1033 /* ignore extra input */
1034 break;
1035 }
1036 }
1037
1038 if (!(events & EV_WRITE0x04))
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(*__errno())) {
1044 case EINTR4:
1045 case EAGAIN35:
1046 return; /* try again later */
1047 case EPIPE32:
1048 goto done;
1049 default:
1050 lwarn("response write")logger->warn("response write");
1051 goto done;
1052 }
1053 }
1054
1055 c->bufoff += n;
1056 if (c->bufoff != c->buflen)
1057 return; /* try again later */
1058
1059done:
1060 identd_close(c);
1061}
1062
1063void
1064syslog_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_EMERG0, "unable to alloc in syslog_vstrerror");
1070 exit(1);
1071 }
1072 syslog(priority, "%s: %s", s, strerror(e));
1073 free(s);
1074}
1075
1076void
1077syslog_err(int ecode, const char *fmt, ...)
1078{
1079 va_list ap;
1080
1081 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1082 syslog_vstrerror(errno(*__errno()), LOG_CRIT2, fmt, ap);
1083 va_end(ap)__builtin_va_end(ap);
1084 exit(ecode);
1085}
1086
1087void
1088syslog_errx(int ecode, const char *fmt, ...)
1089{
1090 va_list ap;
1091
1092 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1093 vsyslog(LOG_CRIT2, fmt, ap);
1094 va_end(ap)__builtin_va_end(ap);
1095 exit(ecode);
1096}
1097
1098void
1099syslog_warn(const char *fmt, ...)
1100{
1101 va_list ap;
1102
1103 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1104 syslog_vstrerror(errno(*__errno()), LOG_ERR3, fmt, ap);
1105 va_end(ap)__builtin_va_end(ap);
1106}
1107
1108void
1109syslog_warnx(const char *fmt, ...)
1110{
1111 va_list ap;
1112
1113 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1114 vsyslog(LOG_ERR3, fmt, ap);
1115 va_end(ap)__builtin_va_end(ap);
1116}
1117
1118void
1119syslog_notice(const char *fmt, ...)
1120{
1121 va_list ap;
1122
1123 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1124 vsyslog(LOG_NOTICE5, fmt, ap);
1125 va_end(ap)__builtin_va_end(ap);
1126}
1127
1128void
1129syslog_debug(const char *fmt, ...)
1130{
1131 va_list ap;
1132
1133 if (!debug)
1134 return;
1135
1136 va_start(ap, fmt)__builtin_va_start(ap, fmt);
1137 vsyslog(LOG_DEBUG7, fmt, ap);
1138 va_end(ap)__builtin_va_end(ap);
1139}
1140
1141const char *
1142gethost(struct sockaddr_storage *ss)
1143{
1144 struct sockaddr *sa = (struct sockaddr *)ss;
1145 static char buf[NI_MAXHOST256];
1146
1147 if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf),
1148 NULL((void *)0), 0, NI_NUMERICHOST1) != 0)
1149 return ("(unknown)");
1150
1151 return (buf);
1152}
1153
1154const char *
1155gentoken(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
1171int
1172fetchuid(struct ident_client *c)
1173{
1174 struct tcp_ident_mapping tir;
1175 int mib[] = { CTL_NET4, PF_INET2, IPPROTO_TCP6, TCPCTL_IDENT9 };
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_INET2:
1187 s4 = (struct sockaddr_in *)&tir.faddr;
1188 s4->sin_port = htons(c->client.port)(__uint16_t)(__builtin_constant_p(c->client.port) ? (__uint16_t
)(((__uint16_t)(c->client.port) & 0xffU) << 8 | (
(__uint16_t)(c->client.port) & 0xff00U) >> 8) : __swap16md
(c->client.port))
;
1189
1190 s4 = (struct sockaddr_in *)&tir.laddr;
1191 s4->sin_port = htons(c->server.port)(__uint16_t)(__builtin_constant_p(c->server.port) ? (__uint16_t
)(((__uint16_t)(c->server.port) & 0xffU) << 8 | (
(__uint16_t)(c->server.port) & 0xff00U) >> 8) : __swap16md
(c->server.port))
;
1192 break;
1193 case AF_INET624:
1194 s6 = (struct sockaddr_in6 *)&tir.faddr;
1195 s6->sin6_port = htons(c->client.port)(__uint16_t)(__builtin_constant_p(c->client.port) ? (__uint16_t
)(((__uint16_t)(c->client.port) & 0xffU) << 8 | (
(__uint16_t)(c->client.port) & 0xff00U) >> 8) : __swap16md
(c->client.port))
;
1196
1197 s6 = (struct sockaddr_in6 *)&tir.laddr;
1198 s6->sin6_port = htons(c->server.port)(__uint16_t)(__builtin_constant_p(c->server.port) ? (__uint16_t
)(((__uint16_t)(c->server.port) & 0xffU) << 8 | (
(__uint16_t)(c->server.port) & 0xff00U) >> 8) : __swap16md
(c->server.port))
;
1199 break;
1200 default:
1201 lerrx(1, "unexpected family %d", c->server.ss.ss_family)logger->errx((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((void *)0), 0);
1206 if (err == -1)
1207 lerr(1, "sysctl")logger->err((1), "sysctl");
1208
1209 if (tir.ruid == -1)
1210 return (-1);
1211
1212 c->uid = tir.ruid;
1213 return (0);
1214}