File: | src/usr.sbin/identd/identd.c |
Warning: | line 279, column 2 Value stored to 'argv' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
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_NONE0 0 |
72 | #define E_NOUSER1 1 |
73 | #define E_UNKNOWN2 2 |
74 | #define E_HIDDEN3 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)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 | |
97 | struct 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 | |
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__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 | |
149 | const 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))); |
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...) 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 | |
193 | static __dead__attribute__((__noreturn__)) void |
194 | usage(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 | |
202 | struct timeval timeout = { TIMEOUT_DEFAULT120, 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)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 | |
221 | int |
222 | main(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 | |
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(*__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 | |
428 | done: |
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 | |
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,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 | |
464 | void |
465 | parent_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 | |
483 | void |
484 | parent_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 | |
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(*__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 | |
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)((&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 | |
645 | void |
646 | identd_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 | |
702 | void |
703 | identd_paused(int fd, short events, void *arg) |
704 | { |
705 | struct identd_listener *l = arg; |
706 | event_add(&l->ev, NULL((void *)0)); |
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((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 | |
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(*__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 | |
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)(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 | |
864 | void |
865 | identd_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 | |
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(*__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 | |
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_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 | |
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_EMERG0, "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)__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 | |
1087 | void |
1088 | syslog_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 | |
1098 | void |
1099 | syslog_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 | |
1108 | void |
1109 | syslog_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 | |
1118 | void |
1119 | syslog_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 | |
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)__builtin_va_start(ap, fmt); |
1137 | vsyslog(LOG_DEBUG7, fmt, ap); |
1138 | va_end(ap)__builtin_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_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 | |
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_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 | } |