1*515e489cSderaadt /* $OpenBSD: identd.c,v 1.40 2019/07/03 03:24:03 deraadt Exp $ */
2c32efdd3Sdlg
3c32efdd3Sdlg /*
4c32efdd3Sdlg * Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
5c32efdd3Sdlg *
6c32efdd3Sdlg * Permission to use, copy, modify, and distribute this software for any
7c32efdd3Sdlg * purpose with or without fee is hereby granted, provided that the above
8c32efdd3Sdlg * copyright notice and this permission notice appear in all copies.
9c32efdd3Sdlg *
10c32efdd3Sdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11c32efdd3Sdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12c32efdd3Sdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13c32efdd3Sdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14c32efdd3Sdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15c32efdd3Sdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16c32efdd3Sdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17c32efdd3Sdlg */
18c32efdd3Sdlg
19c32efdd3Sdlg #include <sys/types.h>
2053ea3549Sderaadt #include <sys/ioctl.h>
21c32efdd3Sdlg #include <sys/socket.h>
22ce704e6aSmpi #include <sys/queue.h>
234298a39aSdlg #include <sys/stat.h>
24c32efdd3Sdlg #include <sys/sysctl.h>
25c32efdd3Sdlg #include <sys/uio.h>
26c32efdd3Sdlg
27c32efdd3Sdlg #include <netinet/in.h>
28c32efdd3Sdlg #include <netinet/tcp.h>
29c32efdd3Sdlg #include <netinet/tcp_timer.h>
30c32efdd3Sdlg #include <netinet/tcp_var.h>
31c32efdd3Sdlg
32c32efdd3Sdlg #include <netdb.h>
33c32efdd3Sdlg
34c32efdd3Sdlg #include <err.h>
35c32efdd3Sdlg #include <ctype.h>
36c32efdd3Sdlg #include <errno.h>
37c32efdd3Sdlg #include <event.h>
384fe4baadSdlg #include <fcntl.h>
39c32efdd3Sdlg #include <pwd.h>
40c32efdd3Sdlg #include <stdio.h>
41b9fc9a72Sderaadt #include <limits.h>
42c32efdd3Sdlg #include <stdlib.h>
43be9b181dSdlg #include <stdarg.h>
44c32efdd3Sdlg #include <string.h>
4554ea7419Sdlg #include <signal.h>
46c32efdd3Sdlg #include <syslog.h>
47c32efdd3Sdlg #include <unistd.h>
48c32efdd3Sdlg
49c32efdd3Sdlg #define IDENTD_USER "_identd"
50c32efdd3Sdlg
514fe4baadSdlg #define DOTNOIDENT ".noident"
524fe4baadSdlg
53c32efdd3Sdlg #define TIMEOUT_MIN 4
54c32efdd3Sdlg #define TIMEOUT_MAX 240
55c32efdd3Sdlg #define TIMEOUT_DEFAULT 120
56acc4509dSdlg #define INPUT_MAX 256
57c32efdd3Sdlg
58c32efdd3Sdlg enum ident_client_state {
59c32efdd3Sdlg S_BEGINNING = 0,
60c32efdd3Sdlg S_SERVER_PORT,
61c32efdd3Sdlg S_PRE_COMMA,
62c32efdd3Sdlg S_POST_COMMA,
63c32efdd3Sdlg S_CLIENT_PORT,
64c32efdd3Sdlg S_PRE_EOL,
65c32efdd3Sdlg S_EOL,
66c32efdd3Sdlg
67c32efdd3Sdlg S_DEAD,
689a4217c3Sdlg S_QUEUED
69c32efdd3Sdlg };
70c32efdd3Sdlg
71c32efdd3Sdlg #define E_NONE 0
72c32efdd3Sdlg #define E_NOUSER 1
73c32efdd3Sdlg #define E_UNKNOWN 2
74c32efdd3Sdlg #define E_HIDDEN 3
75c32efdd3Sdlg
76c32efdd3Sdlg struct ident_client {
77c32efdd3Sdlg struct {
78c32efdd3Sdlg /* from the socket */
79c32efdd3Sdlg struct sockaddr_storage ss;
80c32efdd3Sdlg socklen_t len;
81c32efdd3Sdlg
82c32efdd3Sdlg /* from the request */
83c32efdd3Sdlg u_int port;
84c32efdd3Sdlg } client, server;
85c32efdd3Sdlg SIMPLEQ_ENTRY(ident_client) entry;
86c32efdd3Sdlg enum ident_client_state state;
87c32efdd3Sdlg struct event ev;
889a4217c3Sdlg struct event tmo;
89acc4509dSdlg size_t rxbytes;
90c32efdd3Sdlg
91c32efdd3Sdlg char *buf;
92c32efdd3Sdlg size_t buflen;
93c32efdd3Sdlg size_t bufoff;
94c32efdd3Sdlg uid_t uid;
95c32efdd3Sdlg };
96c32efdd3Sdlg
97c32efdd3Sdlg struct ident_resolver {
98c32efdd3Sdlg SIMPLEQ_ENTRY(ident_resolver) entry;
99c32efdd3Sdlg char *buf;
100c32efdd3Sdlg size_t buflen;
101c32efdd3Sdlg u_int error;
102c32efdd3Sdlg };
103c32efdd3Sdlg
104ff28ff65Sdlg struct identd_listener {
105ff28ff65Sdlg struct event ev, pause;
106ff28ff65Sdlg };
107ff28ff65Sdlg
108c32efdd3Sdlg void parent_rd(int, short, void *);
109c32efdd3Sdlg void parent_wr(int, short, void *);
11053389e0dSdlg int parent_username(struct ident_resolver *, struct passwd *);
11153389e0dSdlg int parent_uid(struct ident_resolver *, struct passwd *);
1123f52e118Sdlg int parent_token(struct ident_resolver *, struct passwd *);
1134fe4baadSdlg void parent_noident(struct ident_resolver *, struct passwd *);
114c32efdd3Sdlg
115c32efdd3Sdlg void child_rd(int, short, void *);
116c32efdd3Sdlg void child_wr(int, short, void *);
117c32efdd3Sdlg
118c32efdd3Sdlg void identd_listen(const char *, const char *, int);
119ff28ff65Sdlg void identd_paused(int, short, void *);
120c32efdd3Sdlg void identd_accept(int, short, void *);
121181dd5c9Sdlg int identd_error(struct ident_client *, const char *);
122181dd5c9Sdlg void identd_close(struct ident_client *);
1239a4217c3Sdlg void identd_timeout(int, short, void *);
124c32efdd3Sdlg void identd_request(int, short, void *);
125c32efdd3Sdlg enum ident_client_state
126c32efdd3Sdlg identd_parse(struct ident_client *, int);
127c32efdd3Sdlg void identd_resolving(int, short, void *);
128c32efdd3Sdlg void identd_response(int, short, void *);
129c32efdd3Sdlg int fetchuid(struct ident_client *);
130c32efdd3Sdlg
131c32efdd3Sdlg const char *gethost(struct sockaddr_storage *);
1323f52e118Sdlg const char *gentoken(void);
133c32efdd3Sdlg
134c32efdd3Sdlg struct loggers {
135f7986388Sflorian __dead void (*err)(int, const char *, ...)
136f7986388Sflorian __attribute__((__format__ (printf, 2, 3)));
137f7986388Sflorian __dead void (*errx)(int, const char *, ...)
138f7986388Sflorian __attribute__((__format__ (printf, 2, 3)));
139f7986388Sflorian void (*warn)(const char *, ...)
140f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
141f7986388Sflorian void (*warnx)(const char *, ...)
142f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
143f7986388Sflorian void (*notice)(const char *, ...)
144f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
145f7986388Sflorian void (*debug)(const char *, ...)
146f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
147c32efdd3Sdlg };
148c32efdd3Sdlg
149c32efdd3Sdlg const struct loggers conslogger = {
150c32efdd3Sdlg err,
151c32efdd3Sdlg errx,
152c32efdd3Sdlg warn,
153c32efdd3Sdlg warnx,
1543f52e118Sdlg warnx, /* notice */
155c32efdd3Sdlg warnx /* debug */
156c32efdd3Sdlg };
157c32efdd3Sdlg
158f7986388Sflorian __dead void syslog_err(int, const char *, ...)
159f7986388Sflorian __attribute__((__format__ (printf, 2, 3)));
160f7986388Sflorian __dead void syslog_errx(int, const char *, ...)
161f7986388Sflorian __attribute__((__format__ (printf, 2, 3)));
162f7986388Sflorian void syslog_warn(const char *, ...)
163f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
164f7986388Sflorian void syslog_warnx(const char *, ...)
165f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
166f7986388Sflorian void syslog_notice(const char *, ...)
167f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
168f7986388Sflorian void syslog_debug(const char *, ...)
169f7986388Sflorian __attribute__((__format__ (printf, 1, 2)));
170f7986388Sflorian void syslog_vstrerror(int, int, const char *, va_list)
171f7986388Sflorian __attribute__((__format__ (printf, 3, 0)));
172c32efdd3Sdlg
173c32efdd3Sdlg const struct loggers syslogger = {
174c32efdd3Sdlg syslog_err,
175c32efdd3Sdlg syslog_errx,
176c32efdd3Sdlg syslog_warn,
177c32efdd3Sdlg syslog_warnx,
1783f52e118Sdlg syslog_notice,
179c32efdd3Sdlg syslog_debug
180c32efdd3Sdlg };
181c32efdd3Sdlg
182c32efdd3Sdlg const struct loggers *logger = &conslogger;
183c32efdd3Sdlg
184c32efdd3Sdlg #define lerr(_e, _f...) logger->err((_e), _f)
185c32efdd3Sdlg #define lerrx(_e, _f...) logger->errx((_e), _f)
186c32efdd3Sdlg #define lwarn(_f...) logger->warn(_f)
187c32efdd3Sdlg #define lwarnx(_f...) logger->warnx(_f)
1883f52e118Sdlg #define lnotice(_f...) logger->notice(_f)
189c32efdd3Sdlg #define ldebug(_f...) logger->debug(_f)
190c32efdd3Sdlg
191c32efdd3Sdlg #define sa(_ss) ((struct sockaddr *)(_ss))
192c32efdd3Sdlg
193ffa0ebfeSderaadt static __dead void
usage(void)194c32efdd3Sdlg usage(void)
195c32efdd3Sdlg {
196c32efdd3Sdlg extern char *__progname;
1974cc355a6Sokan fprintf(stderr, "usage: %s [-46deHhNn] [-l address] [-t timeout]\n",
1986cde5dafSdlg __progname);
199c32efdd3Sdlg exit(1);
200c32efdd3Sdlg }
201c32efdd3Sdlg
202c32efdd3Sdlg struct timeval timeout = { TIMEOUT_DEFAULT, 0 };
203c32efdd3Sdlg int debug = 0;
2044fe4baadSdlg int noident = 0;
2056b9316d1Ssthen int unknown_err = 0;
2064cc355a6Sokan int hideall = 0;
207c32efdd3Sdlg
20853389e0dSdlg int (*parent_uprintf)(struct ident_resolver *, struct passwd *) =
20953389e0dSdlg parent_username;
21053389e0dSdlg
211c32efdd3Sdlg struct event proc_rd, proc_wr;
212c32efdd3Sdlg union {
213c32efdd3Sdlg struct {
214c32efdd3Sdlg SIMPLEQ_HEAD(, ident_resolver) replies;
215c32efdd3Sdlg } parent;
216c32efdd3Sdlg struct {
217c32efdd3Sdlg SIMPLEQ_HEAD(, ident_client) pushing, popping;
218c32efdd3Sdlg } child;
219c32efdd3Sdlg } sc;
220c32efdd3Sdlg
221c32efdd3Sdlg int
main(int argc,char * argv[])222c32efdd3Sdlg main(int argc, char *argv[])
223c32efdd3Sdlg {
224c32efdd3Sdlg extern char *__progname;
225c32efdd3Sdlg const char *errstr = NULL;
226c32efdd3Sdlg
227c32efdd3Sdlg int c;
228c32efdd3Sdlg struct passwd *pw;
229c32efdd3Sdlg
230c32efdd3Sdlg char *addr = NULL;
231c32efdd3Sdlg int family = AF_UNSPEC;
232c32efdd3Sdlg
233c32efdd3Sdlg int pair[2];
234c32efdd3Sdlg pid_t parent;
235c32efdd3Sdlg int sibling;
236c32efdd3Sdlg
237cb94ec52Stobias while ((c = getopt(argc, argv, "46deHhl:Nnt:")) != -1) {
238c32efdd3Sdlg switch (c) {
239c32efdd3Sdlg case '4':
240c32efdd3Sdlg family = AF_INET;
241c32efdd3Sdlg break;
242c32efdd3Sdlg case '6':
243c32efdd3Sdlg family = AF_INET6;
244c32efdd3Sdlg break;
245c32efdd3Sdlg case 'd':
246c32efdd3Sdlg debug = 1;
247c32efdd3Sdlg break;
2486b9316d1Ssthen case 'e':
2496b9316d1Ssthen unknown_err = 1;
2506b9316d1Ssthen break;
2514cc355a6Sokan case 'H':
2524cc355a6Sokan hideall = 1;
2534cc355a6Sokan /* FALLTHROUGH */
2543f52e118Sdlg case 'h':
2553f52e118Sdlg parent_uprintf = parent_token;
2563f52e118Sdlg break;
257c32efdd3Sdlg case 'l':
258c32efdd3Sdlg addr = optarg;
259c32efdd3Sdlg break;
2604fe4baadSdlg case 'N':
2614fe4baadSdlg noident = 1;
2624fe4baadSdlg break;
26353389e0dSdlg case 'n':
26453389e0dSdlg parent_uprintf = parent_uid;
26553389e0dSdlg break;
266c32efdd3Sdlg case 't':
267c32efdd3Sdlg timeout.tv_sec = strtonum(optarg,
268c32efdd3Sdlg TIMEOUT_MIN, TIMEOUT_MAX, &errstr);
269c32efdd3Sdlg if (errstr != NULL)
270c32efdd3Sdlg errx(1, "timeout %s is %s", optarg, errstr);
271c32efdd3Sdlg break;
272c32efdd3Sdlg default:
273c32efdd3Sdlg usage();
274c32efdd3Sdlg /* NOTREACHED */
275c32efdd3Sdlg }
276c32efdd3Sdlg }
277c32efdd3Sdlg
278c32efdd3Sdlg argc -= optind;
279c32efdd3Sdlg argv += optind;
280c32efdd3Sdlg
281c32efdd3Sdlg if (argc != 0)
282c32efdd3Sdlg usage();
283c32efdd3Sdlg
284c32efdd3Sdlg if (geteuid() != 0)
285c32efdd3Sdlg errx(1, "need root privileges");
286c32efdd3Sdlg
2874c23dba0Sdlg if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK,
2884c23dba0Sdlg PF_UNSPEC, pair) == -1)
289c32efdd3Sdlg err(1, "socketpair");
290c32efdd3Sdlg
291c32efdd3Sdlg pw = getpwnam(IDENTD_USER);
292c32efdd3Sdlg if (pw == NULL)
29303436e2cSclaudio errx(1, "no %s user", IDENTD_USER);
294c32efdd3Sdlg
295c32efdd3Sdlg if (!debug && daemon(1, 0) == -1)
296c32efdd3Sdlg err(1, "daemon");
297c32efdd3Sdlg
298c32efdd3Sdlg parent = fork();
299c32efdd3Sdlg switch (parent) {
300c32efdd3Sdlg case -1:
301c32efdd3Sdlg lerr(1, "fork");
302c32efdd3Sdlg
303c32efdd3Sdlg case 0:
304c32efdd3Sdlg /* child */
305c32efdd3Sdlg setproctitle("listener");
306c32efdd3Sdlg close(pair[1]);
307c32efdd3Sdlg sibling = pair[0];
308c32efdd3Sdlg break;
309c32efdd3Sdlg
310c32efdd3Sdlg default:
311c32efdd3Sdlg /* parent */
312c32efdd3Sdlg setproctitle("resolver");
313c32efdd3Sdlg close(pair[0]);
314c32efdd3Sdlg sibling = pair[1];
315c32efdd3Sdlg break;
316c32efdd3Sdlg }
317c32efdd3Sdlg
318c32efdd3Sdlg if (!debug) {
319c32efdd3Sdlg openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
320c32efdd3Sdlg tzset();
321c32efdd3Sdlg logger = &syslogger;
322c32efdd3Sdlg }
323c32efdd3Sdlg
324c32efdd3Sdlg event_init();
325c32efdd3Sdlg
32654ea7419Sdlg if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
32754ea7419Sdlg lerr(1, "signal(SIGPIPE)");
32854ea7419Sdlg
329c32efdd3Sdlg if (parent) {
330095634e3Sjca if (pledge("stdio getpw rpath id", NULL) == -1)
33164e16a71Sdoug err(1, "pledge");
33264e16a71Sdoug
333c32efdd3Sdlg SIMPLEQ_INIT(&sc.parent.replies);
334c32efdd3Sdlg
335c32efdd3Sdlg event_set(&proc_rd, sibling, EV_READ | EV_PERSIST,
336c32efdd3Sdlg parent_rd, NULL);
337c32efdd3Sdlg event_set(&proc_wr, sibling, EV_WRITE,
338c32efdd3Sdlg parent_wr, NULL);
339c32efdd3Sdlg } else {
340c32efdd3Sdlg SIMPLEQ_INIT(&sc.child.pushing);
341c32efdd3Sdlg SIMPLEQ_INIT(&sc.child.popping);
342c32efdd3Sdlg
343986c812aSdlg identd_listen(addr, "auth", family);
344c32efdd3Sdlg
345c32efdd3Sdlg if (chroot(pw->pw_dir) == -1)
346c32efdd3Sdlg lerr(1, "chroot(%s)", pw->pw_dir);
347c32efdd3Sdlg
348c32efdd3Sdlg if (chdir("/") == -1)
349c32efdd3Sdlg lerr(1, "chdir(%s)", pw->pw_dir);
350c32efdd3Sdlg
351c32efdd3Sdlg event_set(&proc_rd, sibling, EV_READ | EV_PERSIST,
352c32efdd3Sdlg child_rd, NULL);
353c32efdd3Sdlg event_set(&proc_wr, sibling, EV_WRITE,
354c32efdd3Sdlg child_wr, NULL);
355c32efdd3Sdlg }
356c32efdd3Sdlg
357c32efdd3Sdlg if (setgroups(1, &pw->pw_gid) ||
358c32efdd3Sdlg setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
359c32efdd3Sdlg setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
360c32efdd3Sdlg lerr(1, "unable to revoke privs");
361c32efdd3Sdlg
36264e16a71Sdoug if (parent) {
36364e16a71Sdoug if (noident) {
36464e16a71Sdoug if (pledge("stdio getpw rpath", NULL) == -1)
36564e16a71Sdoug err(1, "pledge");
36664e16a71Sdoug } else {
36764e16a71Sdoug if (pledge("stdio getpw", NULL) == -1)
36864e16a71Sdoug err(1, "pledge");
36964e16a71Sdoug }
37064e16a71Sdoug }
37164e16a71Sdoug
372c32efdd3Sdlg event_add(&proc_rd, NULL);
373c32efdd3Sdlg event_dispatch();
374c32efdd3Sdlg return (0);
375c32efdd3Sdlg }
376c32efdd3Sdlg
377c32efdd3Sdlg void
parent_rd(int fd,short events,void * arg)378c32efdd3Sdlg parent_rd(int fd, short events, void *arg)
379c32efdd3Sdlg {
380c32efdd3Sdlg struct ident_resolver *r;
381c32efdd3Sdlg struct passwd *pw;
382c32efdd3Sdlg ssize_t n;
383c32efdd3Sdlg uid_t uid;
384c32efdd3Sdlg
385c32efdd3Sdlg n = read(fd, &uid, sizeof(uid));
386c32efdd3Sdlg switch (n) {
387c32efdd3Sdlg case -1:
388c32efdd3Sdlg switch (errno) {
389c32efdd3Sdlg case EAGAIN:
390c32efdd3Sdlg case EINTR:
391c32efdd3Sdlg return;
392c32efdd3Sdlg default:
393c32efdd3Sdlg lerr(1, "parent read");
394c32efdd3Sdlg }
395c32efdd3Sdlg break;
396c32efdd3Sdlg case 0:
397c32efdd3Sdlg lerrx(1, "child has gone");
398c32efdd3Sdlg case sizeof(uid):
399c32efdd3Sdlg break;
400c32efdd3Sdlg default:
401c32efdd3Sdlg lerrx(1, "unexpected %zd data from child", n);
402c32efdd3Sdlg }
403c32efdd3Sdlg
404c32efdd3Sdlg r = calloc(1, sizeof(*r));
405c32efdd3Sdlg if (r == NULL)
406c32efdd3Sdlg lerr(1, "resolver alloc");
407c32efdd3Sdlg
408c32efdd3Sdlg pw = getpwuid(uid);
4094cc355a6Sokan if (pw == NULL && !hideall) {
410c32efdd3Sdlg r->error = E_NOUSER;
4114fe4baadSdlg goto done;
4124fe4baadSdlg }
4134fe4baadSdlg
4144cc355a6Sokan if (noident && !hideall) {
4154fe4baadSdlg parent_noident(r, pw);
4164fe4baadSdlg if (r->error != E_NONE)
4174fe4baadSdlg goto done;
4184fe4baadSdlg }
4194fe4baadSdlg
42053389e0dSdlg n = (*parent_uprintf)(r, pw);
4214fe4baadSdlg if (n == -1) {
422c32efdd3Sdlg r->error = E_UNKNOWN;
4234fe4baadSdlg goto done;
4244fe4baadSdlg }
4254fe4baadSdlg
426c78ca77fSdlg r->buflen = n + 1;
4274fe4baadSdlg
4284fe4baadSdlg done:
4294fe4baadSdlg SIMPLEQ_INSERT_TAIL(&sc.parent.replies, r, entry);
4304fe4baadSdlg event_add(&proc_wr, NULL);
4314fe4baadSdlg }
4324fe4baadSdlg
43353389e0dSdlg int
parent_username(struct ident_resolver * r,struct passwd * pw)43453389e0dSdlg parent_username(struct ident_resolver *r, struct passwd *pw)
43553389e0dSdlg {
43653389e0dSdlg return (asprintf(&r->buf, "%s", pw->pw_name));
43753389e0dSdlg }
43853389e0dSdlg
43953389e0dSdlg int
parent_uid(struct ident_resolver * r,struct passwd * pw)44053389e0dSdlg parent_uid(struct ident_resolver *r, struct passwd *pw)
44153389e0dSdlg {
44253389e0dSdlg return (asprintf(&r->buf, "%u", (u_int)pw->pw_uid));
44353389e0dSdlg }
44453389e0dSdlg
4453f52e118Sdlg int
parent_token(struct ident_resolver * r,struct passwd * pw)4463f52e118Sdlg parent_token(struct ident_resolver *r, struct passwd *pw)
4473f52e118Sdlg {
4483f52e118Sdlg const char *token;
4493f52e118Sdlg int rv;
4503f52e118Sdlg
4513f52e118Sdlg token = gentoken();
4523f52e118Sdlg rv = asprintf(&r->buf, "%s", token);
4533f52e118Sdlg if (rv != -1) {
4544cc355a6Sokan if (pw)
4553f52e118Sdlg lnotice("token %s == uid %u (%s)", token,
4563f52e118Sdlg (u_int)pw->pw_uid, pw->pw_name);
4574cc355a6Sokan else
4584cc355a6Sokan lnotice("token %s == NO USER", token);
4593f52e118Sdlg }
4603f52e118Sdlg
4613f52e118Sdlg return (rv);
4623f52e118Sdlg }
4633f52e118Sdlg
4644fe4baadSdlg void
parent_noident(struct ident_resolver * r,struct passwd * pw)4654fe4baadSdlg parent_noident(struct ident_resolver *r, struct passwd *pw)
4664fe4baadSdlg {
467b9fc9a72Sderaadt char path[PATH_MAX];
4684298a39aSdlg struct stat st;
4694fe4baadSdlg int rv;
4704fe4baadSdlg
4714fe4baadSdlg rv = snprintf(path, sizeof(path), "%s/%s", pw->pw_dir, DOTNOIDENT);
472*515e489cSderaadt if (rv < 0 || rv >= sizeof(path)) {
4734fe4baadSdlg r->error = E_UNKNOWN;
4744fe4baadSdlg return;
4754fe4baadSdlg }
4764fe4baadSdlg
4774298a39aSdlg if (stat(path, &st) == -1)
4784fe4baadSdlg return;
4794fe4baadSdlg
4804fe4baadSdlg r->error = E_HIDDEN;
481c32efdd3Sdlg }
482c32efdd3Sdlg
483c32efdd3Sdlg void
parent_wr(int fd,short events,void * arg)484c32efdd3Sdlg parent_wr(int fd, short events, void *arg)
485c32efdd3Sdlg {
486c32efdd3Sdlg struct ident_resolver *r = SIMPLEQ_FIRST(&sc.parent.replies);
487c32efdd3Sdlg struct iovec iov[2];
488c32efdd3Sdlg int iovcnt = 0;
489c32efdd3Sdlg ssize_t n;
490c32efdd3Sdlg
491c32efdd3Sdlg iov[iovcnt].iov_base = &r->error;
492c32efdd3Sdlg iov[iovcnt].iov_len = sizeof(r->error);
493c32efdd3Sdlg iovcnt++;
494c32efdd3Sdlg
495c32efdd3Sdlg if (r->buflen > 0) {
496c32efdd3Sdlg iov[iovcnt].iov_base = r->buf;
497c32efdd3Sdlg iov[iovcnt].iov_len = r->buflen;
498c32efdd3Sdlg iovcnt++;
499c32efdd3Sdlg }
500c32efdd3Sdlg
501c32efdd3Sdlg n = writev(fd, iov, iovcnt);
502c32efdd3Sdlg if (n == -1) {
5032807f553Sdlg switch (errno) {
5042807f553Sdlg case EINTR:
5052807f553Sdlg case EAGAIN:
506c32efdd3Sdlg event_add(&proc_wr, NULL);
507c32efdd3Sdlg return;
5082807f553Sdlg default:
509c32efdd3Sdlg lerr(1, "parent write");
510c32efdd3Sdlg }
5112807f553Sdlg }
512c32efdd3Sdlg
513c32efdd3Sdlg if (n != sizeof(r->error) + r->buflen)
514c32efdd3Sdlg lerrx(1, "unexpected parent write length %zd", n);
515c32efdd3Sdlg
516c32efdd3Sdlg SIMPLEQ_REMOVE_HEAD(&sc.parent.replies, entry);
517c32efdd3Sdlg
518c32efdd3Sdlg if (r->buflen > 0)
519c32efdd3Sdlg free(r->buf);
520c32efdd3Sdlg
521c32efdd3Sdlg free(r);
522e36d0f04Sdlg
523e36d0f04Sdlg if (!SIMPLEQ_EMPTY(&sc.parent.replies))
524e36d0f04Sdlg event_add(&proc_wr, NULL);
525c32efdd3Sdlg }
526c32efdd3Sdlg
527c32efdd3Sdlg void
child_rd(int fd,short events,void * arg)528c32efdd3Sdlg child_rd(int fd, short events, void *arg)
529c32efdd3Sdlg {
530c32efdd3Sdlg struct ident_client *c;
531c32efdd3Sdlg struct {
532c32efdd3Sdlg u_int error;
533c32efdd3Sdlg char buf[512];
534c32efdd3Sdlg } reply;
535c32efdd3Sdlg ssize_t n;
536c32efdd3Sdlg
537c32efdd3Sdlg n = read(fd, &reply, sizeof(reply));
538c32efdd3Sdlg switch (n) {
539c32efdd3Sdlg case -1:
540c32efdd3Sdlg switch (errno) {
541c32efdd3Sdlg case EAGAIN:
542c32efdd3Sdlg case EINTR:
543c32efdd3Sdlg return;
544c32efdd3Sdlg default:
545c32efdd3Sdlg lerr(1, "child read");
546c32efdd3Sdlg }
547c32efdd3Sdlg break;
548c32efdd3Sdlg case 0:
549c32efdd3Sdlg lerrx(1, "parent has gone");
550c32efdd3Sdlg default:
551c32efdd3Sdlg break;
552c32efdd3Sdlg }
553c32efdd3Sdlg
554c32efdd3Sdlg c = SIMPLEQ_FIRST(&sc.child.popping);
555c32efdd3Sdlg if (c == NULL)
556c32efdd3Sdlg lerrx(1, "unsolicited data from parent");
557c32efdd3Sdlg
558c32efdd3Sdlg SIMPLEQ_REMOVE_HEAD(&sc.child.popping, entry);
559c32efdd3Sdlg
560c32efdd3Sdlg if (n < sizeof(reply.error))
561c32efdd3Sdlg lerrx(1, "short data from parent");
562c32efdd3Sdlg
563c32efdd3Sdlg /* check if something went wrong while the parent was working */
5649a4217c3Sdlg if (c->state == S_DEAD) {
565c32efdd3Sdlg free(c);
566c32efdd3Sdlg return;
567c32efdd3Sdlg }
5689a4217c3Sdlg c->state = S_DEAD;
569c32efdd3Sdlg
570c32efdd3Sdlg switch (reply.error) {
571c32efdd3Sdlg case E_NONE:
572c32efdd3Sdlg n = asprintf(&c->buf, "%u , %u : USERID : UNIX : %s\r\n",
573c32efdd3Sdlg c->server.port, c->client.port, reply.buf);
574c32efdd3Sdlg break;
575c32efdd3Sdlg case E_NOUSER:
5766b9316d1Ssthen n = asprintf(&c->buf, "%u , %u : ERROR : %s\r\n",
5776b9316d1Ssthen c->server.port, c->client.port,
5786b9316d1Ssthen unknown_err ? "UNKNOWN-ERROR" : "NO-USER");
579c32efdd3Sdlg break;
580c32efdd3Sdlg case E_UNKNOWN:
581c32efdd3Sdlg n = asprintf(&c->buf, "%u , %u : ERROR : UNKNOWN-ERROR\r\n",
582c32efdd3Sdlg c->server.port, c->client.port);
583c32efdd3Sdlg break;
584c32efdd3Sdlg case E_HIDDEN:
585c32efdd3Sdlg n = asprintf(&c->buf, "%u , %u : ERROR : HIDDEN-USER\r\n",
586c32efdd3Sdlg c->server.port, c->client.port);
587c32efdd3Sdlg break;
588c32efdd3Sdlg default:
589c32efdd3Sdlg lerrx(1, "unexpected error from parent %u", reply.error);
590c32efdd3Sdlg }
591c32efdd3Sdlg if (n == -1)
592c32efdd3Sdlg goto fail;
593c32efdd3Sdlg
594c32efdd3Sdlg c->buflen = n;
595c32efdd3Sdlg
596c32efdd3Sdlg fd = EVENT_FD(&c->ev);
597c32efdd3Sdlg event_del(&c->ev);
598c32efdd3Sdlg event_set(&c->ev, fd, EV_READ | EV_WRITE | EV_PERSIST,
599c32efdd3Sdlg identd_response, c);
6009a4217c3Sdlg event_add(&c->ev, NULL);
601c32efdd3Sdlg return;
602c32efdd3Sdlg
603c32efdd3Sdlg fail:
604181dd5c9Sdlg identd_close(c);
605c32efdd3Sdlg }
606c32efdd3Sdlg
607c32efdd3Sdlg void
child_wr(int fd,short events,void * arg)608c32efdd3Sdlg child_wr(int fd, short events, void *arg)
609c32efdd3Sdlg {
610c32efdd3Sdlg struct ident_client *c = SIMPLEQ_FIRST(&sc.child.pushing);
611181dd5c9Sdlg const char *errstr = NULL;
612c32efdd3Sdlg ssize_t n;
613c32efdd3Sdlg
614c32efdd3Sdlg n = write(fd, &c->uid, sizeof(c->uid));
615c32efdd3Sdlg switch (n) {
616c32efdd3Sdlg case -1:
617181dd5c9Sdlg switch (errno) {
6182807f553Sdlg case EINTR:
619181dd5c9Sdlg case EAGAIN:
620c32efdd3Sdlg event_add(&proc_wr, NULL);
621c32efdd3Sdlg return;
622181dd5c9Sdlg case ENOBUFS: /* parent has a backlog of requests */
623181dd5c9Sdlg errstr = "UNKNOWN-ERROR";
624181dd5c9Sdlg break;
625181dd5c9Sdlg default:
626c32efdd3Sdlg lerr(1, "child write");
627181dd5c9Sdlg }
628181dd5c9Sdlg break;
629c32efdd3Sdlg case sizeof(c->uid):
630c32efdd3Sdlg break;
631c32efdd3Sdlg default:
632c32efdd3Sdlg lerrx(1, "unexpected child write length %zd", n);
633c32efdd3Sdlg }
634c32efdd3Sdlg
635c32efdd3Sdlg SIMPLEQ_REMOVE_HEAD(&sc.child.pushing, entry);
636181dd5c9Sdlg if (errstr == NULL)
637c32efdd3Sdlg SIMPLEQ_INSERT_TAIL(&sc.child.popping, c, entry);
638181dd5c9Sdlg else if (identd_error(c, errstr) == -1)
639181dd5c9Sdlg identd_close(c);
640c32efdd3Sdlg
641c32efdd3Sdlg if (!SIMPLEQ_EMPTY(&sc.child.pushing))
642c32efdd3Sdlg event_add(&proc_wr, NULL);
643c32efdd3Sdlg }
644c32efdd3Sdlg
645c32efdd3Sdlg void
identd_listen(const char * addr,const char * port,int family)646c32efdd3Sdlg identd_listen(const char *addr, const char *port, int family)
647c32efdd3Sdlg {
648ff28ff65Sdlg struct identd_listener *l = NULL;
649c32efdd3Sdlg
650c32efdd3Sdlg struct addrinfo hints, *res, *res0;
651397cfbf5Sderaadt int error, s;
652c32efdd3Sdlg const char *cause = NULL;
6534c23dba0Sdlg int on = 1;
654c32efdd3Sdlg
655c32efdd3Sdlg memset(&hints, 0, sizeof(hints));
656c32efdd3Sdlg hints.ai_family = family;
657c32efdd3Sdlg hints.ai_socktype = SOCK_STREAM;
658c32efdd3Sdlg hints.ai_flags = AI_PASSIVE;
659c32efdd3Sdlg
660c32efdd3Sdlg error = getaddrinfo(addr, port, &hints, &res0);
661c32efdd3Sdlg if (error)
662c32efdd3Sdlg lerrx(1, "%s/%s: %s", addr, port, gai_strerror(error));
663c32efdd3Sdlg
664c32efdd3Sdlg for (res = res0; res != NULL; res = res->ai_next) {
6654c23dba0Sdlg s = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK,
6664c23dba0Sdlg res->ai_protocol);
667c32efdd3Sdlg if (s == -1) {
668c32efdd3Sdlg cause = "socket";
669c32efdd3Sdlg continue;
670c32efdd3Sdlg }
671c32efdd3Sdlg
672c32efdd3Sdlg if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
673c32efdd3Sdlg &on, sizeof(on)) == -1)
674c32efdd3Sdlg err(1, "listener setsockopt(SO_REUSEADDR)");
675c32efdd3Sdlg
676c32efdd3Sdlg if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
677397cfbf5Sderaadt int serrno = errno;
678397cfbf5Sderaadt
679c32efdd3Sdlg cause = "bind";
680c32efdd3Sdlg close(s);
681c32efdd3Sdlg errno = serrno;
682c32efdd3Sdlg continue;
683c32efdd3Sdlg }
684c32efdd3Sdlg
685c32efdd3Sdlg if (listen(s, 5) == -1)
686c32efdd3Sdlg err(1, "listen");
687c32efdd3Sdlg
688ff28ff65Sdlg l = calloc(1, sizeof(*l));
689ff28ff65Sdlg if (l == NULL)
690c32efdd3Sdlg err(1, "listener ev alloc");
691c32efdd3Sdlg
692ff28ff65Sdlg event_set(&l->ev, s, EV_READ | EV_PERSIST, identd_accept, l);
693ff28ff65Sdlg event_add(&l->ev, NULL);
694ff28ff65Sdlg evtimer_set(&l->pause, identd_paused, l);
695c32efdd3Sdlg }
696ff28ff65Sdlg if (l == NULL)
697c32efdd3Sdlg err(1, "%s", cause);
698c32efdd3Sdlg
699c32efdd3Sdlg freeaddrinfo(res0);
700c32efdd3Sdlg }
701c32efdd3Sdlg
702c32efdd3Sdlg void
identd_paused(int fd,short events,void * arg)703ff28ff65Sdlg identd_paused(int fd, short events, void *arg)
704ff28ff65Sdlg {
705ff28ff65Sdlg struct identd_listener *l = arg;
706ff28ff65Sdlg event_add(&l->ev, NULL);
707ff28ff65Sdlg }
708ff28ff65Sdlg
709ff28ff65Sdlg void
identd_accept(int fd,short events,void * arg)710c32efdd3Sdlg identd_accept(int fd, short events, void *arg)
711c32efdd3Sdlg {
712ff28ff65Sdlg struct identd_listener *l = arg;
713c32efdd3Sdlg struct sockaddr_storage ss;
714ff28ff65Sdlg struct timeval pause = { 1, 0 };
715c32efdd3Sdlg struct ident_client *c = NULL;
716c32efdd3Sdlg socklen_t len;
717c32efdd3Sdlg int s;
718c32efdd3Sdlg
719c32efdd3Sdlg len = sizeof(ss);
7204c23dba0Sdlg s = accept4(fd, sa(&ss), &len, SOCK_NONBLOCK);
721c32efdd3Sdlg if (s == -1) {
722c32efdd3Sdlg switch (errno) {
723c32efdd3Sdlg case EINTR:
724c32efdd3Sdlg case EWOULDBLOCK:
725c32efdd3Sdlg case ECONNABORTED:
726c32efdd3Sdlg return;
727ff28ff65Sdlg case EMFILE:
728ff28ff65Sdlg case ENFILE:
729ff28ff65Sdlg event_del(&l->ev);
730ff28ff65Sdlg evtimer_add(&l->pause, &pause);
731ff28ff65Sdlg return;
732c32efdd3Sdlg default:
733c32efdd3Sdlg lerr(1, "accept");
734c32efdd3Sdlg }
735c32efdd3Sdlg }
736c32efdd3Sdlg
737c32efdd3Sdlg c = calloc(1, sizeof(*c));
738c32efdd3Sdlg if (c == NULL) {
739c32efdd3Sdlg lwarn("client alloc");
740c32efdd3Sdlg close(fd);
741c32efdd3Sdlg return;
742c32efdd3Sdlg }
743c32efdd3Sdlg
744c32efdd3Sdlg memcpy(&c->client.ss, &ss, len);
745c32efdd3Sdlg c->client.len = len;
746c32efdd3Sdlg ldebug("client: %s", gethost(&ss));
747c32efdd3Sdlg
748c32efdd3Sdlg /* lookup the local ip it connected to */
749c32efdd3Sdlg c->server.len = sizeof(c->server.ss);
750c32efdd3Sdlg if (getsockname(s, sa(&c->server.ss), &c->server.len) == -1)
751c32efdd3Sdlg lerr(1, "getsockname");
752c32efdd3Sdlg
753c32efdd3Sdlg event_set(&c->ev, s, EV_READ | EV_PERSIST, identd_request, c);
7549a4217c3Sdlg event_add(&c->ev, NULL);
7559a4217c3Sdlg
756270badb5Sdlg evtimer_set(&c->tmo, identd_timeout, c);
757270badb5Sdlg evtimer_add(&c->tmo, &timeout);
7589a4217c3Sdlg }
7599a4217c3Sdlg
7609a4217c3Sdlg void
identd_timeout(int fd,short events,void * arg)7619a4217c3Sdlg identd_timeout(int fd, short events, void *arg)
7629a4217c3Sdlg {
7639a4217c3Sdlg struct ident_client *c = arg;
7649a4217c3Sdlg
7659a4217c3Sdlg event_del(&c->ev);
7669a4217c3Sdlg close(fd);
7679a4217c3Sdlg free(c->buf);
7689a4217c3Sdlg
7699a4217c3Sdlg if (c->state == S_QUEUED) /* it is queued for resolving */
7709a4217c3Sdlg c->state = S_DEAD;
7719a4217c3Sdlg else
7729a4217c3Sdlg free(c);
773c32efdd3Sdlg }
774c32efdd3Sdlg
775c32efdd3Sdlg void
identd_request(int fd,short events,void * arg)776c32efdd3Sdlg identd_request(int fd, short events, void *arg)
777c32efdd3Sdlg {
778c32efdd3Sdlg struct ident_client *c = arg;
7794f91e8dcSdlg unsigned char buf[64];
780c32efdd3Sdlg ssize_t n, i;
7816b9316d1Ssthen char *errstr = unknown_err ? "UNKNOWN-ERROR" : "INVALID-PORT";
782c32efdd3Sdlg
783c32efdd3Sdlg n = read(fd, buf, sizeof(buf));
784c32efdd3Sdlg switch (n) {
785c32efdd3Sdlg case -1:
786c32efdd3Sdlg switch (errno) {
787c32efdd3Sdlg case EINTR:
788c32efdd3Sdlg case EAGAIN:
789c32efdd3Sdlg return;
790c32efdd3Sdlg default:
791c32efdd3Sdlg lwarn("%s read", gethost(&c->client.ss));
792c32efdd3Sdlg goto fail;
793c32efdd3Sdlg }
794c32efdd3Sdlg break;
795c32efdd3Sdlg
796c32efdd3Sdlg case 0:
797c32efdd3Sdlg ldebug("%s closed connection", gethost(&c->client.ss));
798c32efdd3Sdlg goto fail;
799c32efdd3Sdlg default:
800c32efdd3Sdlg break;
801c32efdd3Sdlg }
802c32efdd3Sdlg
803acc4509dSdlg c->rxbytes += n;
804acc4509dSdlg if (c->rxbytes >= INPUT_MAX)
805acc4509dSdlg goto fail;
806acc4509dSdlg
807c32efdd3Sdlg for (i = 0; c->state < S_EOL && i < n; i++)
808c32efdd3Sdlg c->state = identd_parse(c, buf[i]);
809c32efdd3Sdlg
810c32efdd3Sdlg if (c->state == S_DEAD)
811c32efdd3Sdlg goto error;
812c32efdd3Sdlg if (c->state != S_EOL)
813c32efdd3Sdlg return;
814c32efdd3Sdlg
815c32efdd3Sdlg if (c->server.port < 1 || c->client.port < 1)
816c32efdd3Sdlg goto error;
817c32efdd3Sdlg
818c32efdd3Sdlg if (fetchuid(c) == -1) {
8196b9316d1Ssthen errstr = unknown_err ? "UNKNOWN-ERROR" : "NO-USER";
820c32efdd3Sdlg goto error;
821c32efdd3Sdlg }
822c32efdd3Sdlg
823c32efdd3Sdlg SIMPLEQ_INSERT_TAIL(&sc.child.pushing, c, entry);
8249a4217c3Sdlg c->state = S_QUEUED;
825c32efdd3Sdlg
8269a4217c3Sdlg event_del(&c->ev);
827c32efdd3Sdlg event_set(&c->ev, fd, EV_READ | EV_PERSIST, identd_resolving, c);
8289a4217c3Sdlg event_add(&c->ev, NULL);
829c32efdd3Sdlg
830c32efdd3Sdlg event_add(&proc_wr, NULL);
831c32efdd3Sdlg return;
832c32efdd3Sdlg
833c32efdd3Sdlg error:
834181dd5c9Sdlg if (identd_error(c, errstr) == -1)
835181dd5c9Sdlg goto fail;
836181dd5c9Sdlg
837181dd5c9Sdlg return;
838181dd5c9Sdlg
839181dd5c9Sdlg fail:
840181dd5c9Sdlg identd_close(c);
841181dd5c9Sdlg }
842181dd5c9Sdlg
843181dd5c9Sdlg int
identd_error(struct ident_client * c,const char * errstr)844181dd5c9Sdlg identd_error(struct ident_client *c, const char *errstr)
845181dd5c9Sdlg {
846181dd5c9Sdlg int fd = EVENT_FD(&c->ev);
847181dd5c9Sdlg ssize_t n;
848181dd5c9Sdlg
849c32efdd3Sdlg n = asprintf(&c->buf, "%u , %u : ERROR : %s\r\n",
850c32efdd3Sdlg c->server.port, c->client.port, errstr);
851c32efdd3Sdlg if (n == -1)
852181dd5c9Sdlg return (-1);
853c32efdd3Sdlg
854c32efdd3Sdlg c->buflen = n;
855c32efdd3Sdlg
856c32efdd3Sdlg event_del(&c->ev);
857c32efdd3Sdlg event_set(&c->ev, fd, EV_READ | EV_WRITE | EV_PERSIST,
858c32efdd3Sdlg identd_response, c);
8599a4217c3Sdlg event_add(&c->ev, NULL);
860c32efdd3Sdlg
861181dd5c9Sdlg return (0);
862181dd5c9Sdlg }
863181dd5c9Sdlg
864181dd5c9Sdlg void
identd_close(struct ident_client * c)865181dd5c9Sdlg identd_close(struct ident_client *c)
866181dd5c9Sdlg {
867181dd5c9Sdlg int fd = EVENT_FD(&c->ev);
868181dd5c9Sdlg
8699a4217c3Sdlg evtimer_del(&c->tmo);
870c32efdd3Sdlg event_del(&c->ev);
871c32efdd3Sdlg close(fd);
872181dd5c9Sdlg free(c->buf);
873c32efdd3Sdlg free(c);
874c32efdd3Sdlg }
875c32efdd3Sdlg
876c32efdd3Sdlg void
identd_resolving(int fd,short events,void * arg)877c32efdd3Sdlg identd_resolving(int fd, short events, void *arg)
878c32efdd3Sdlg {
879c32efdd3Sdlg struct ident_client *c = arg;
880c32efdd3Sdlg char buf[64];
881c32efdd3Sdlg ssize_t n;
882c32efdd3Sdlg
883c32efdd3Sdlg /*
884c32efdd3Sdlg * something happened while we're waiting for the parent to lookup
885c32efdd3Sdlg * the user.
886c32efdd3Sdlg */
887c32efdd3Sdlg
888c32efdd3Sdlg n = read(fd, buf, sizeof(buf));
889c32efdd3Sdlg switch (n) {
890c32efdd3Sdlg case -1:
891c32efdd3Sdlg switch (errno) {
892c32efdd3Sdlg case EINTR:
893c32efdd3Sdlg case EAGAIN:
894c32efdd3Sdlg return;
895c32efdd3Sdlg default:
8962807f553Sdlg lwarn("resolving read");
8972807f553Sdlg break;
898c32efdd3Sdlg }
8992807f553Sdlg break;
900c32efdd3Sdlg case 0:
901c32efdd3Sdlg ldebug("%s closed connection during resolving",
902c32efdd3Sdlg gethost(&c->client.ss));
903c32efdd3Sdlg break;
9049a4217c3Sdlg default:
905acc4509dSdlg c->rxbytes += n;
906acc4509dSdlg if (c->rxbytes >= INPUT_MAX)
907acc4509dSdlg break;
908acc4509dSdlg
9099a4217c3Sdlg /* ignore extra input */
9109a4217c3Sdlg return;
911c32efdd3Sdlg }
912c32efdd3Sdlg
9139a4217c3Sdlg evtimer_del(&c->tmo);
914c32efdd3Sdlg event_del(&c->ev);
915c32efdd3Sdlg close(fd);
9169a4217c3Sdlg c->state = S_DEAD; /* on the resolving queue */
917c32efdd3Sdlg }
918c32efdd3Sdlg
919c32efdd3Sdlg enum ident_client_state
identd_parse(struct ident_client * c,int ch)920c32efdd3Sdlg identd_parse(struct ident_client *c, int ch)
921c32efdd3Sdlg {
922c32efdd3Sdlg enum ident_client_state s = c->state;
923c32efdd3Sdlg
924c32efdd3Sdlg switch (s) {
925c32efdd3Sdlg case S_BEGINNING:
926c32efdd3Sdlg /* ignore leading space */
927c32efdd3Sdlg if (ch == '\t' || ch == ' ')
928c32efdd3Sdlg return (s);
929c32efdd3Sdlg
930c32efdd3Sdlg if (ch == '0' || !isdigit(ch))
931c32efdd3Sdlg return (S_DEAD);
932c32efdd3Sdlg
933c32efdd3Sdlg c->server.port = ch - '0';
934c32efdd3Sdlg return (S_SERVER_PORT);
935c32efdd3Sdlg
936c32efdd3Sdlg case S_SERVER_PORT:
937c32efdd3Sdlg if (ch == '\t' || ch == ' ')
938c32efdd3Sdlg return (S_PRE_COMMA);
939c32efdd3Sdlg if (ch == ',')
940c32efdd3Sdlg return (S_POST_COMMA);
941c32efdd3Sdlg
942c32efdd3Sdlg if (!isdigit(ch))
943c32efdd3Sdlg return (S_DEAD);
944c32efdd3Sdlg
945c32efdd3Sdlg c->server.port *= 10;
946c32efdd3Sdlg c->server.port += ch - '0';
947c32efdd3Sdlg if (c->server.port > 65535)
948c32efdd3Sdlg return (S_DEAD);
949c32efdd3Sdlg
950c32efdd3Sdlg return (s);
951c32efdd3Sdlg
952c32efdd3Sdlg case S_PRE_COMMA:
953c32efdd3Sdlg if (ch == '\t' || ch == ' ')
954c32efdd3Sdlg return (s);
955c32efdd3Sdlg if (ch == ',')
956c32efdd3Sdlg return (S_POST_COMMA);
957c32efdd3Sdlg
958c32efdd3Sdlg return (S_DEAD);
959c32efdd3Sdlg
960c32efdd3Sdlg case S_POST_COMMA:
961c32efdd3Sdlg if (ch == '\t' || ch == ' ')
962c32efdd3Sdlg return (s);
963c32efdd3Sdlg
964c32efdd3Sdlg if (ch == '0' || !isdigit(ch))
965c32efdd3Sdlg return (S_DEAD);
966c32efdd3Sdlg
967c32efdd3Sdlg c->client.port = ch - '0';
968c32efdd3Sdlg return (S_CLIENT_PORT);
969c32efdd3Sdlg
970c32efdd3Sdlg case S_CLIENT_PORT:
971c32efdd3Sdlg if (ch == '\t' || ch == ' ')
972c32efdd3Sdlg return (S_PRE_EOL);
973c32efdd3Sdlg if (ch == '\r' || ch == '\n')
974c32efdd3Sdlg return (S_EOL);
975c32efdd3Sdlg
976c32efdd3Sdlg if (!isdigit(ch))
977c32efdd3Sdlg return (S_DEAD);
978c32efdd3Sdlg
979c32efdd3Sdlg c->client.port *= 10;
980c32efdd3Sdlg c->client.port += ch - '0';
981c32efdd3Sdlg if (c->client.port > 65535)
982c32efdd3Sdlg return (S_DEAD);
983c32efdd3Sdlg
984c32efdd3Sdlg return (s);
985c32efdd3Sdlg
986c32efdd3Sdlg case S_PRE_EOL:
987c32efdd3Sdlg if (ch == '\t' || ch == ' ')
988c32efdd3Sdlg return (s);
989c32efdd3Sdlg if (ch == '\r' || ch == '\n')
990c32efdd3Sdlg return (S_EOL);
991c32efdd3Sdlg
992c32efdd3Sdlg return (S_DEAD);
993c32efdd3Sdlg
994c32efdd3Sdlg case S_EOL:
995c32efdd3Sdlg /* ignore trailing garbage */
996c32efdd3Sdlg return (s);
997c32efdd3Sdlg
998c32efdd3Sdlg default:
999c32efdd3Sdlg return (S_DEAD);
1000c32efdd3Sdlg }
1001c32efdd3Sdlg }
1002c32efdd3Sdlg
1003c32efdd3Sdlg void
identd_response(int fd,short events,void * arg)1004c32efdd3Sdlg identd_response(int fd, short events, void *arg)
1005c32efdd3Sdlg {
1006c32efdd3Sdlg struct ident_client *c = arg;
1007c32efdd3Sdlg char buf[64];
1008c32efdd3Sdlg ssize_t n;
1009c32efdd3Sdlg
1010c32efdd3Sdlg if (events & EV_READ) {
1011c32efdd3Sdlg n = read(fd, buf, sizeof(buf));
1012c32efdd3Sdlg switch (n) {
1013c32efdd3Sdlg case -1:
1014c32efdd3Sdlg switch (errno) {
1015c32efdd3Sdlg case EINTR:
1016c32efdd3Sdlg case EAGAIN:
1017c32efdd3Sdlg /* meh, try a write */
1018c32efdd3Sdlg break;
1019c32efdd3Sdlg default:
10202807f553Sdlg lwarn("response read");
10212807f553Sdlg goto done;
1022c32efdd3Sdlg }
1023c32efdd3Sdlg break;
1024c32efdd3Sdlg case 0:
1025c32efdd3Sdlg ldebug("%s closed connection during response",
1026c32efdd3Sdlg gethost(&c->client.ss));
1027c32efdd3Sdlg goto done;
1028c32efdd3Sdlg default:
1029acc4509dSdlg c->rxbytes += n;
1030acc4509dSdlg if (c->rxbytes >= INPUT_MAX)
1031acc4509dSdlg goto done;
1032acc4509dSdlg
10339a4217c3Sdlg /* ignore extra input */
1034c32efdd3Sdlg break;
1035c32efdd3Sdlg }
1036c32efdd3Sdlg }
1037c32efdd3Sdlg
1038c32efdd3Sdlg if (!(events & EV_WRITE))
1039c32efdd3Sdlg return; /* try again later */
1040c32efdd3Sdlg
1041c32efdd3Sdlg n = write(fd, c->buf + c->bufoff, c->buflen - c->bufoff);
1042c32efdd3Sdlg if (n == -1) {
1043c32efdd3Sdlg switch (errno) {
10442807f553Sdlg case EINTR:
1045c32efdd3Sdlg case EAGAIN:
1046c32efdd3Sdlg return; /* try again later */
104754ea7419Sdlg case EPIPE:
104854ea7419Sdlg goto done;
1049c32efdd3Sdlg default:
105054ea7419Sdlg lwarn("response write");
105154ea7419Sdlg goto done;
1052c32efdd3Sdlg }
1053c32efdd3Sdlg }
1054c32efdd3Sdlg
1055c32efdd3Sdlg c->bufoff += n;
1056c32efdd3Sdlg if (c->bufoff != c->buflen)
1057c32efdd3Sdlg return; /* try again later */
1058c32efdd3Sdlg
1059c32efdd3Sdlg done:
1060181dd5c9Sdlg identd_close(c);
1061c32efdd3Sdlg }
1062c32efdd3Sdlg
1063c32efdd3Sdlg void
syslog_vstrerror(int e,int priority,const char * fmt,va_list ap)1064c32efdd3Sdlg syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1065c32efdd3Sdlg {
1066c32efdd3Sdlg char *s;
1067c32efdd3Sdlg
1068c32efdd3Sdlg if (vasprintf(&s, fmt, ap) == -1) {
1069c32efdd3Sdlg syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
1070c32efdd3Sdlg exit(1);
1071c32efdd3Sdlg }
1072c32efdd3Sdlg syslog(priority, "%s: %s", s, strerror(e));
1073c32efdd3Sdlg free(s);
1074c32efdd3Sdlg }
1075c32efdd3Sdlg
1076c32efdd3Sdlg void
syslog_err(int ecode,const char * fmt,...)1077c32efdd3Sdlg syslog_err(int ecode, const char *fmt, ...)
1078c32efdd3Sdlg {
1079c32efdd3Sdlg va_list ap;
1080c32efdd3Sdlg
1081c32efdd3Sdlg va_start(ap, fmt);
1082a52b97d1Sflorian syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
1083c32efdd3Sdlg va_end(ap);
1084c32efdd3Sdlg exit(ecode);
1085c32efdd3Sdlg }
1086c32efdd3Sdlg
1087c32efdd3Sdlg void
syslog_errx(int ecode,const char * fmt,...)1088c32efdd3Sdlg syslog_errx(int ecode, const char *fmt, ...)
1089c32efdd3Sdlg {
1090c32efdd3Sdlg va_list ap;
1091c32efdd3Sdlg
1092c32efdd3Sdlg va_start(ap, fmt);
1093a52b97d1Sflorian vsyslog(LOG_CRIT, fmt, ap);
1094c32efdd3Sdlg va_end(ap);
1095c32efdd3Sdlg exit(ecode);
1096c32efdd3Sdlg }
1097c32efdd3Sdlg
1098c32efdd3Sdlg void
syslog_warn(const char * fmt,...)1099c32efdd3Sdlg syslog_warn(const char *fmt, ...)
1100c32efdd3Sdlg {
1101c32efdd3Sdlg va_list ap;
1102c32efdd3Sdlg
1103c32efdd3Sdlg va_start(ap, fmt);
1104a52b97d1Sflorian syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1105c32efdd3Sdlg va_end(ap);
1106c32efdd3Sdlg }
1107c32efdd3Sdlg
1108c32efdd3Sdlg void
syslog_warnx(const char * fmt,...)1109c32efdd3Sdlg syslog_warnx(const char *fmt, ...)
1110c32efdd3Sdlg {
1111c32efdd3Sdlg va_list ap;
1112c32efdd3Sdlg
1113c32efdd3Sdlg va_start(ap, fmt);
1114a52b97d1Sflorian vsyslog(LOG_ERR, fmt, ap);
1115c32efdd3Sdlg va_end(ap);
1116c32efdd3Sdlg }
1117c32efdd3Sdlg
1118c32efdd3Sdlg void
syslog_notice(const char * fmt,...)11193f52e118Sdlg syslog_notice(const char *fmt, ...)
1120c32efdd3Sdlg {
1121c32efdd3Sdlg va_list ap;
1122c32efdd3Sdlg
1123c32efdd3Sdlg va_start(ap, fmt);
11243f52e118Sdlg vsyslog(LOG_NOTICE, fmt, ap);
1125c32efdd3Sdlg va_end(ap);
1126c32efdd3Sdlg }
1127c32efdd3Sdlg
1128c32efdd3Sdlg void
syslog_debug(const char * fmt,...)1129c32efdd3Sdlg syslog_debug(const char *fmt, ...)
1130c32efdd3Sdlg {
1131c32efdd3Sdlg va_list ap;
1132c32efdd3Sdlg
1133c32efdd3Sdlg if (!debug)
1134c32efdd3Sdlg return;
1135c32efdd3Sdlg
1136c32efdd3Sdlg va_start(ap, fmt);
1137c32efdd3Sdlg vsyslog(LOG_DEBUG, fmt, ap);
1138c32efdd3Sdlg va_end(ap);
1139c32efdd3Sdlg }
1140c32efdd3Sdlg
1141c32efdd3Sdlg const char *
gethost(struct sockaddr_storage * ss)1142c32efdd3Sdlg gethost(struct sockaddr_storage *ss)
1143c32efdd3Sdlg {
1144c32efdd3Sdlg struct sockaddr *sa = (struct sockaddr *)ss;
1145c32efdd3Sdlg static char buf[NI_MAXHOST];
1146c32efdd3Sdlg
1147c32efdd3Sdlg if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf),
1148c32efdd3Sdlg NULL, 0, NI_NUMERICHOST) != 0)
1149c32efdd3Sdlg return ("(unknown)");
1150c32efdd3Sdlg
1151c32efdd3Sdlg return (buf);
1152c32efdd3Sdlg }
1153c32efdd3Sdlg
1154c32efdd3Sdlg const char *
gentoken(void)11553f52e118Sdlg gentoken(void)
11563f52e118Sdlg {
11573f52e118Sdlg static char buf[21];
11583f52e118Sdlg u_int32_t r;
11593f52e118Sdlg int i;
11603f52e118Sdlg
11613f52e118Sdlg buf[0] = 'a' + arc4random_uniform(26);
11623f52e118Sdlg for (i = 1; i < sizeof(buf) - 1; i++) {
11633f52e118Sdlg r = arc4random_uniform(36);
11643f52e118Sdlg buf[i] = (r < 26 ? 'a' : '0' - 26) + r;
11653f52e118Sdlg }
11663f52e118Sdlg buf[i] = '\0';
11673f52e118Sdlg
11683f52e118Sdlg return (buf);
11693f52e118Sdlg }
11703f52e118Sdlg
1171c32efdd3Sdlg int
fetchuid(struct ident_client * c)1172c32efdd3Sdlg fetchuid(struct ident_client *c)
1173c32efdd3Sdlg {
1174c32efdd3Sdlg struct tcp_ident_mapping tir;
1175c32efdd3Sdlg int mib[] = { CTL_NET, PF_INET, IPPROTO_TCP, TCPCTL_IDENT };
1176c32efdd3Sdlg struct sockaddr_in *s4;
1177c32efdd3Sdlg struct sockaddr_in6 *s6;
1178c32efdd3Sdlg int err = 0;
1179c32efdd3Sdlg size_t len;
1180c32efdd3Sdlg
1181c32efdd3Sdlg memset(&tir, 0, sizeof(tir));
1182b8347973Sdlg memcpy(&tir.faddr, &c->client.ss, sizeof(tir.faddr));
1183b8347973Sdlg memcpy(&tir.laddr, &c->server.ss, sizeof(tir.laddr));
1184c32efdd3Sdlg
1185c32efdd3Sdlg switch (c->server.ss.ss_family) {
1186c32efdd3Sdlg case AF_INET:
1187c32efdd3Sdlg s4 = (struct sockaddr_in *)&tir.faddr;
1188c32efdd3Sdlg s4->sin_port = htons(c->client.port);
1189c32efdd3Sdlg
1190c32efdd3Sdlg s4 = (struct sockaddr_in *)&tir.laddr;
1191c32efdd3Sdlg s4->sin_port = htons(c->server.port);
1192c32efdd3Sdlg break;
1193c32efdd3Sdlg case AF_INET6:
1194c32efdd3Sdlg s6 = (struct sockaddr_in6 *)&tir.faddr;
1195c32efdd3Sdlg s6->sin6_port = htons(c->client.port);
1196c32efdd3Sdlg
1197c32efdd3Sdlg s6 = (struct sockaddr_in6 *)&tir.laddr;
1198c32efdd3Sdlg s6->sin6_port = htons(c->server.port);
1199c32efdd3Sdlg break;
1200c32efdd3Sdlg default:
1201c32efdd3Sdlg lerrx(1, "unexpected family %d", c->server.ss.ss_family);
1202c32efdd3Sdlg }
1203c32efdd3Sdlg
1204c32efdd3Sdlg len = sizeof(tir);
1205c32efdd3Sdlg err = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &tir, &len, NULL, 0);
1206c32efdd3Sdlg if (err == -1)
1207c32efdd3Sdlg lerr(1, "sysctl");
1208c32efdd3Sdlg
1209c32efdd3Sdlg if (tir.ruid == -1)
1210c32efdd3Sdlg return (-1);
1211c32efdd3Sdlg
1212c32efdd3Sdlg c->uid = tir.ruid;
1213c32efdd3Sdlg return (0);
1214c32efdd3Sdlg }
1215