GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/identd/identd.c Lines: 0 486 0.0 %
Date: 2017-11-07 Branches: 0 277 0.0 %

Line Branch Exec Source
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
}