1 /* $NetBSD: identd.c,v 1.31 2006/09/29 17:02:04 christos Exp $ */
4 * identd.c - TCP/IP Ident protocol server.
6 * This software is in the public domain.
7 * Written by Peter Postma <peter@NetBSD.org>
10 #include <sys/cdefs.h>
11 __RCSID("$NetBSD: identd.c,v 1.31 2006/09/29 17:02:04 christos Exp $");
13 #include <sys/param.h>
14 #include <sys/socket.h>
16 #include <sys/sysctl.h>
18 #include <netinet/in.h>
19 #include <netinet/ip_var.h>
20 #include <netinet/tcp.h>
21 #include <netinet/tcp_timer.h>
22 #include <netinet/tcp_var.h>
24 #include <arpa/inet.h>
44 #define OPSYS_NAME "UNIX"
45 #define IDENT_SERVICE "auth"
46 #define TIMEOUT 30 /* seconds */
48 static int idhandle(int, const char *, const char *, const char *,
49 const char *, struct sockaddr
*, int);
50 static void idparse(int, int, int, const char *, const char *, const char *);
51 static void iderror(int, int, int, const char *);
52 static const char *gethost(struct sockaddr
*);
53 static int *socketsetup(const char *, const char *, int);
54 static int ident_getuid(struct sockaddr_storage
*, socklen_t
,
55 struct sockaddr
*, uid_t
*);
56 static int sysctl_getuid(struct sockaddr_storage
*, socklen_t
, uid_t
*);
57 static int sysctl_proxy_getuid(struct sockaddr_storage
*,
58 struct sockaddr
*, uid_t
*);
59 static int forward(int, struct sockaddr
*, int, int, int);
60 static int check_noident(const char *);
61 static int check_userident(const char *, char *, size_t);
62 static void random_string(char *, size_t);
63 static int change_format(const char *, struct passwd
*, char *, size_t);
64 static void timeout_handler(int);
65 static void fatal(const char *);
66 static void die(const char *, ...);
68 static int bflag
, eflag
, fflag
, iflag
, Iflag
;
69 static int lflag
, Lflag
, nflag
, Nflag
, rflag
;
71 /* NAT lookup function pointer. */
72 static int (*nat_lookup
)(struct sockaddr_storage
*, struct sockaddr
*, int *);
77 int (*fn
)(struct sockaddr_storage
*, struct sockaddr
*, int *);
80 { "pf", pf_natlookup
},
83 { "ipfilter", ipf_natlookup
},
89 main(int argc
, char *argv
[])
91 int IPv4or6
, ch
, error
, i
, *socks
, timeout
;
92 const char *filter
, *osname
, *portno
, *proxy
;
93 char *address
, *charset
, *fmt
, *p
;
94 char user
[LOGIN_NAME_MAX
];
95 struct addrinfo
*ai
, hints
;
96 struct sockaddr
*proxy_addr
;
105 portno
= IDENT_SERVICE
;
109 filter
= proxy
= NULL
;
110 address
= charset
= fmt
= NULL
;
112 bflag
= eflag
= fflag
= iflag
= Iflag
= 0;
113 lflag
= Lflag
= nflag
= Nflag
= rflag
= 0;
115 /* Started from a tty? then run as daemon. */
116 if (isatty(STDIN_FILENO
))
119 /* Parse command line arguments. */
120 while ((ch
= getopt(argc
, argv
,
121 "46a:bceF:f:g:IiL:lm:Nno:P:p:rt:u:")) != -1) {
146 (void)strlcpy(user
, optarg
, sizeof(user
));
149 gid
= (gid_t
)strtol(optarg
, &p
, 0);
151 if ((grp
= getgrnam(optarg
)) != NULL
)
154 die("No such group `%s'", optarg
);
165 (void)strlcpy(user
, optarg
, sizeof(user
));
169 openlog("identd", LOG_PID
, LOG_DAEMON
);
194 timeout
= (int)strtol(optarg
, &p
, 0);
195 if (*p
!= '\0' || timeout
< 1)
196 die("Invalid timeout value `%s'", optarg
);
199 uid
= (uid_t
)strtol(optarg
, &p
, 0);
201 if ((pw
= getpwnam(optarg
)) != NULL
) {
205 die("No such user `%s'", optarg
);
213 /* Verify proxy address, if enabled. */
215 (void)memset(&hints
, 0, sizeof(hints
));
216 hints
.ai_family
= IPv4or6
;
217 hints
.ai_socktype
= SOCK_STREAM
;
218 error
= getaddrinfo(proxy
, NULL
, &hints
, &ai
);
220 die("Bad proxy `%s': %s", proxy
, gai_strerror(error
));
221 if (ai
->ai_next
!= NULL
)
222 die("Bad proxy `%s': resolves to multiple addresses",
224 proxy_addr
= ai
->ai_addr
;
227 /* Verify filter, if enabled. */
228 if (filter
!= NULL
) {
229 for (i
= 0; filters
[i
].name
!= NULL
; i
++) {
230 if (strcasecmp(filter
, filters
[i
].name
) == 0) {
231 nat_lookup
= filters
[i
].fn
;
235 if (nat_lookup
== NULL
)
236 die("Packet filter `%s' is not supported", filter
);
239 /* Setup sockets when running in the background. */
241 socks
= socketsetup(address
, portno
, IPv4or6
);
243 /* Switch to another uid/gid? */
244 if (gid
&& setgid(gid
) == -1)
245 die("Failed to set GID to `%d': %s", gid
, strerror(errno
));
246 if (uid
&& setuid(uid
) == -1)
247 die("Failed to set UID to `%d': %s", uid
, strerror(errno
));
250 * When running as daemon: daemonize, setup pollfds and go into
251 * the mainloop. Otherwise, just read the input from stdin and
252 * let inetd handle the sockets.
258 if (daemon(0, 0) < 0)
259 die("daemon: %s", strerror(errno
));
261 rfds
= malloc(*socks
* sizeof(struct pollfd
));
265 for (i
= 0; i
< nfds
; i
++) {
266 rfds
[i
].fd
= socks
[i
+1];
267 rfds
[i
].events
= POLLIN
;
270 /* Mainloop for daemon. */
272 rv
= poll(rfds
, nfds
, INFTIM
);
278 for (i
= 0; i
< nfds
; i
++) {
279 if (rfds
[i
].revents
& POLLIN
) {
280 fd
= accept(rfds
[i
].fd
, NULL
, NULL
);
282 maybe_syslog(LOG_ERR
,
288 maybe_syslog(LOG_ERR
,
293 (void)idhandle(fd
, charset
,
295 proxy_addr
, timeout
);
297 default: /* parent */
298 (void)signal(SIGCHLD
, SIG_IGN
);
305 (void)idhandle(STDIN_FILENO
, charset
, fmt
, osname
, user
,
306 proxy_addr
, timeout
);
312 * Handle a request on the ident port. Returns 0 on success or 1 on
313 * failure. The return values are currently ignored.
316 idhandle(int fd
, const char *charset
, const char *fmt
, const char *osname
,
317 const char *user
, struct sockaddr
*proxy
, int timeout
)
319 struct sockaddr_storage ss
[2];
320 char userbuf
[LOGIN_NAME_MAX
]; /* actual user name (or numeric uid) */
321 char idbuf
[LOGIN_NAME_MAX
]; /* name to be used in response */
322 char buf
[BUFSIZ
], *p
;
332 (void)strlcpy(idbuf
, user
, sizeof(idbuf
));
333 (void)signal(SIGALRM
, timeout_handler
);
334 (void)alarm(timeout
);
336 /* Get foreign internet address. */
338 if (getpeername(fd
, (struct sockaddr
*)&ss
[0], &len
) < 0)
339 fatal("getpeername");
341 maybe_syslog(LOG_INFO
, "Connection from %s",
342 gethost((struct sockaddr
*)&ss
[0]));
344 /* Get local internet address. */
346 if (getsockname(fd
, (struct sockaddr
*)&ss
[1], &len
) < 0)
347 fatal("getsockname");
349 /* Be sure to have the same address families. */
350 if (ss
[0].ss_family
!= ss
[1].ss_family
) {
351 maybe_syslog(LOG_ERR
, "Different foreign/local address family");
355 /* Receive data from the client. */
358 if ((n
= recv(fd
, &buf
[qlen
], sizeof(buf
) - qlen
, 0)) < 0) {
361 maybe_syslog(LOG_NOTICE
, "recv: EOF");
362 iderror(fd
, 0, 0, "UNKNOWN-ERROR");
366 * 1413 is not clear on what to do if data follows the first
367 * CRLF before we respond. We do not consider the query
368 * complete until we get a CRLF _at the end of the buffer_.
371 if (qlen
>= sizeof(buf
)) {
372 maybe_syslog(LOG_NOTICE
, "recv: message too long");
375 if ((qlen
>= 2) && (buf
[qlen
- 2] == '\r') &&
376 (buf
[qlen
- 1] == '\n'))
379 buf
[qlen
- 2] = '\0';
381 /* Get local and remote ports from the received data. */
383 while (*p
!= '\0' && isspace((unsigned char)*p
))
385 if ((p
= strtok(p
, " \t,")) != NULL
) {
387 if ((p
= strtok(NULL
, " \t,")) != NULL
)
391 /* Are the ports valid? */
392 if (lport
< 1 || lport
> 65535 || fport
< 1 || fport
> 65535) {
393 maybe_syslog(LOG_NOTICE
, "Invalid port(s): %d, %d from %s",
394 lport
, fport
, gethost((struct sockaddr
*)&ss
[0]));
395 iderror(fd
, 0, 0, eflag
? "UNKNOWN-ERROR" : "INVALID-PORT");
399 /* If there is a 'lie' user enabled, then handle it now and stop. */
401 maybe_syslog(LOG_NOTICE
, "Lying with name %s to %s",
402 idbuf
, gethost((struct sockaddr
*)&ss
[0]));
403 idparse(fd
, lport
, fport
, charset
, osname
, idbuf
);
407 /* Protocol dependent stuff. */
408 switch (ss
[0].ss_family
) {
410 satosin(&ss
[0])->sin_port
= htons(fport
);
411 satosin(&ss
[1])->sin_port
= htons(lport
);
414 satosin6(&ss
[0])->sin6_port
= htons(fport
);
415 satosin6(&ss
[1])->sin6_port
= htons(lport
);
418 maybe_syslog(LOG_ERR
, "Unsupported protocol (no. %d)",
423 /* Try to get the UID of the connection owner using sysctl. */
424 if (ident_getuid(ss
, sizeof(ss
), proxy
, &uid
) == -1) {
425 /* Lookup failed, try to forward if enabled. */
426 if (nat_lookup
!= NULL
) {
427 struct sockaddr nat_addr
;
430 (void)memset(&nat_addr
, 0, sizeof(nat_addr
));
432 if ((*nat_lookup
)(ss
, &nat_addr
, &nat_lport
) &&
433 forward(fd
, &nat_addr
, nat_lport
, fport
, lport
)) {
434 maybe_syslog(LOG_INFO
,
435 "Succesfully forwarded the request to %s",
440 /* Fall back to a default name? */
442 maybe_syslog(LOG_NOTICE
, "Using fallback name %s to %s",
443 idbuf
, gethost((struct sockaddr
*)&ss
[0]));
444 idparse(fd
, lport
, fport
, charset
, osname
, idbuf
);
447 maybe_syslog(LOG_ERR
, "Lookup failed, returning error to %s",
448 gethost((struct sockaddr
*)&ss
[0]));
449 iderror(fd
, lport
, fport
, eflag
? "UNKNOWN-ERROR" : "NO-USER");
453 /* Fill in userbuf with user name if possible, else numeric UID. */
454 if ((pw
= getpwuid(uid
)) == NULL
) {
455 maybe_syslog(LOG_ERR
, "Couldn't map uid (%u) to name", uid
);
456 (void)snprintf(userbuf
, sizeof(userbuf
), "%u", uid
);
458 maybe_syslog(LOG_INFO
, "Successful lookup: %d, %d: %s for %s",
459 lport
, fport
, pw
->pw_name
,
460 gethost((struct sockaddr
*)&ss
[0]));
461 (void)strlcpy(userbuf
, pw
->pw_name
, sizeof(userbuf
));
464 /* No ident enabled? */
465 if (Nflag
&& pw
&& check_noident(pw
->pw_dir
)) {
466 maybe_syslog(LOG_NOTICE
, "Returning HIDDEN-USER for user %s"
467 " to %s", pw
->pw_name
, gethost((struct sockaddr
*)&ss
[0]));
468 iderror(fd
, lport
, fport
, "HIDDEN-USER");
472 /* User ident enabled? */
473 if (iflag
&& pw
&& check_userident(pw
->pw_dir
, idbuf
, sizeof(idbuf
))) {
475 if ((strspn(idbuf
, "0123456789") &&
476 getpwuid(atoi(idbuf
)) != NULL
) ||
477 (getpwnam(idbuf
) != NULL
)) {
478 maybe_syslog(LOG_NOTICE
,
479 "Ignoring user-specified '%s' for user %s",
481 (void)strlcpy(idbuf
, userbuf
, sizeof(idbuf
));
484 maybe_syslog(LOG_NOTICE
,
485 "Returning user-specified '%s' for user %s to %s",
486 idbuf
, userbuf
, gethost((struct sockaddr
*)&ss
[0]));
487 idparse(fd
, lport
, fport
, charset
, osname
, idbuf
);
491 /* Send a random message? */
493 /* Random number or string? */
495 (void)snprintf(idbuf
, sizeof(idbuf
), "%u",
496 (unsigned int)(arc4random() % 65535));
498 random_string(idbuf
, sizeof(idbuf
));
500 maybe_syslog(LOG_NOTICE
,
501 "Returning random '%s' for user %s to %s",
502 idbuf
, userbuf
, gethost((struct sockaddr
*)&ss
[0]));
503 idparse(fd
, lport
, fport
, charset
, osname
, idbuf
);
507 /* Return numberic user ID? */
509 (void)snprintf(idbuf
, sizeof(idbuf
), "%u", uid
);
511 (void)strlcpy(idbuf
, userbuf
, sizeof(idbuf
));
514 * Change the output format? Note that 512 is the maximum
515 * size of the result according to RFC 1413.
517 if (fmt
&& change_format(fmt
, pw
, buf
, 512 + 1))
518 idparse(fd
, lport
, fport
, charset
, osname
, buf
);
520 idparse(fd
, lport
, fport
, charset
, osname
, idbuf
);
525 /* Send/parse the ident result. */
527 idparse(int fd
, int lport
, int fport
, const char *charset
, const char *osname
,
532 if (asprintf(&p
, "%d,%d:USERID:%s%s%s:%s\r\n", lport
, fport
,
533 osname
, charset
? "," : "", charset
? charset
: "", user
) < 0)
535 if (send(fd
, p
, strlen(p
), 0) < 0) {
542 /* Return a specified ident error. */
544 iderror(int fd
, int lport
, int fport
, const char *error
)
548 if (asprintf(&p
, "%d,%d:ERROR:%s\r\n", lport
, fport
, error
) < 0)
550 if (send(fd
, p
, strlen(p
), 0) < 0) {
557 /* Return the IP address of the connecting host. */
559 gethost(struct sockaddr
*sa
)
561 static char host
[NI_MAXHOST
];
563 if (getnameinfo(sa
, sa
->sa_len
, host
, sizeof(host
),
564 NULL
, 0, NI_NUMERICHOST
) == 0)
570 /* Setup sockets, for daemon mode. */
572 socketsetup(const char *address
, const char *port
, int af
)
574 struct addrinfo hints
, *res
, *res0
;
575 int error
, maxs
, *s
, *socks
;
576 const char *cause
= NULL
;
579 (void)memset(&hints
, 0, sizeof(hints
));
580 hints
.ai_flags
= AI_PASSIVE
;
581 hints
.ai_family
= af
;
582 hints
.ai_socktype
= SOCK_STREAM
;
583 error
= getaddrinfo(address
, port
, &hints
, &res0
);
585 die("getaddrinfo: %s", gai_strerror(error
));
589 /* Count max number of sockets we may open. */
590 for (maxs
= 0, res
= res0
; res
!= NULL
; res
= res
->ai_next
)
593 socks
= malloc((maxs
+ 1) * sizeof(int));
595 die("malloc: %s", strerror(errno
));
601 for (res
= res0
; res
!= NULL
; res
= res
->ai_next
) {
602 *s
= socket(res
->ai_family
, res
->ai_socktype
, res
->ai_protocol
);
607 (void)setsockopt(*s
, SOL_SOCKET
, SO_REUSEADDR
, &y
, sizeof(y
));
608 if (bind(*s
, res
->ai_addr
, res
->ai_addrlen
) < 0) {
613 if (listen(*s
, 5) < 0) {
624 die("%s: %s", cause
, strerror(errno
));
633 /* UID lookup wrapper. */
635 ident_getuid(struct sockaddr_storage
*ss
, socklen_t len
,
636 struct sockaddr
*proxy
, uid_t
*uid
)
640 rc
= sysctl_getuid(ss
, len
, uid
);
641 if (rc
== -1 && proxy
!= NULL
)
642 rc
= sysctl_proxy_getuid(ss
, proxy
, uid
);
647 /* Try to get the UID of the connection owner using sysctl. */
649 sysctl_getuid(struct sockaddr_storage
*ss
, socklen_t len
, uid_t
*uid
)
655 uidlen
= sizeof(myuid
);
658 mib
[1] = ss
->ss_family
;
659 mib
[2] = IPPROTO_TCP
;
660 mib
[3] = TCPCTL_IDENT
;
662 if (sysctl(mib
, sizeof(mib
)/ sizeof(int), &myuid
, &uidlen
, ss
, len
) < 0)
669 /* Try to get the UID of the connection owner using sysctl (proxy version). */
671 sysctl_proxy_getuid(struct sockaddr_storage
*ss
, struct sockaddr
*proxy
,
674 struct sockaddr_storage
new[2];
675 int rc
, name
[CTL_MAXNAME
];
677 struct kinfo_pcb
*kp
;
685 /* Retrieve a list of sockets. */
686 switch (ss
[0].ss_family
) {
688 /* We only accept queries from the proxy. */
689 if (in_hosteq(satosin(&ss
[0])->sin_addr
,
690 satosin(proxy
)->sin_addr
))
691 list
= "net.inet.tcp.pcblist";
694 /* We only accept queries from the proxy. */
695 if (IN6_ARE_ADDR_EQUAL(&satosin6(&ss
[0])->sin6_addr
,
696 &satosin6(proxy
)->sin6_addr
))
697 list
= "net.inet6.tcp.pcblist";
700 maybe_syslog(LOG_ERR
, "Unsupported protocol for proxy (no. %d)",
704 rc
= sysctlnametomib(list
, &name
[0], &sz
);
709 name
[len
++] = PCB_ALL
;
711 name
[len
++] = sizeof(struct kinfo_pcb
);
712 name
[len
++] = INT_MAX
;
717 rc
= sysctl(&name
[0], len
, kp
, &sz
, NULL
, 0);
718 if (rc
== -1 && errno
!= ENOMEM
)
730 * Walk through the list of sockets and try to find a match.
731 * We don't know who has sent the query (we only know that the
732 * proxy has forwarded to us) so just try to match the ports and
735 for (i
= 0; i
< sz
/ sizeof(struct kinfo_pcb
); i
++) {
736 switch (ss
[0].ss_family
) {
738 /* Foreign and local ports must match. */
739 if (satosin(&ss
[0])->sin_port
!=
740 satosin(&kp
[i
].ki_src
)->sin_port
)
742 if (satosin(&ss
[1])->sin_port
!=
743 satosin(&kp
[i
].ki_dst
)->sin_port
)
745 /* Foreign address may not match proxy address. */
746 if (in_hosteq(satosin(proxy
)->sin_addr
,
747 satosin(&kp
[i
].ki_dst
)->sin_addr
))
749 /* Local addresses must match. */
750 if (!in_hosteq(satosin(&ss
[1])->sin_addr
,
751 satosin(&kp
[i
].ki_src
)->sin_addr
))
755 /* Foreign and local ports must match. */
756 if (satosin6(&ss
[0])->sin6_port
!=
757 satosin6(&kp
[i
].ki_src
)->sin6_port
)
759 if (satosin6(&ss
[1])->sin6_port
!=
760 satosin6(&kp
[i
].ki_dst
)->sin6_port
)
762 /* Foreign address may not match proxy address. */
763 if (IN6_ARE_ADDR_EQUAL(&satosin6(proxy
)->sin6_addr
,
764 &satosin6(&kp
[i
].ki_dst
)->sin6_addr
))
766 /* Local addresses must match. */
767 if (!IN6_ARE_ADDR_EQUAL(&satosin6(&ss
[1])->sin6_addr
,
768 &satosin6(&kp
[i
].ki_src
)->sin6_addr
))
774 * We have found the foreign address, copy it to a new
775 * struct and retrieve the UID of the connection owner.
777 (void)memcpy(&new[0], &kp
[i
].ki_dst
, kp
[i
].ki_dst
.sa_len
);
778 (void)memcpy(&new[1], &kp
[i
].ki_src
, kp
[i
].ki_src
.sa_len
);
780 rc
= sysctl_getuid(new, sizeof(new), uid
);
790 /* Forward ident queries. Returns 1 when succesful, or zero if not. */
792 forward(int fd
, struct sockaddr
*nat_addr
, int nat_lport
, int fport
, int lport
)
794 char buf
[BUFSIZ
], reply
[BUFSIZ
], *p
;
798 /* Connect to the NAT host. */
799 sock
= socket(nat_addr
->sa_family
, SOCK_STREAM
, 0);
801 maybe_syslog(LOG_ERR
, "socket: %m");
804 if (connect(sock
, nat_addr
, nat_addr
->sa_len
) < 0) {
805 maybe_syslog(LOG_ERR
, "Can't connect to %s: %m",
812 * Send the ident query to the NAT host, but use as local port
813 * the port of the NAT host.
815 (void)snprintf(buf
, sizeof(buf
), "%d , %d\r\n", nat_lport
, fport
);
816 if (send(sock
, buf
, strlen(buf
), 0) < 0) {
817 maybe_syslog(LOG_ERR
, "send: %m");
822 /* Read the reply from the NAT host. */
823 if ((n
= recv(sock
, reply
, sizeof(reply
) - 1, 0)) < 0) {
824 maybe_syslog(LOG_ERR
, "recv: %m");
828 maybe_syslog(LOG_NOTICE
, "recv: EOF");
835 /* Extract everything after the port specs from the ident reply. */
836 for (p
= reply
; *p
!= '\0' && *p
!= ':'; p
++)
838 if (*p
== '\0' || *++p
== '\0') {
839 maybe_syslog(LOG_ERR
, "Malformed ident reply from %s",
843 /* Build reply for the requesting host, use the original local port. */
844 (void)snprintf(buf
, sizeof(buf
), "%d,%d:%s", lport
, fport
, p
);
846 /* Send the reply from the NAT host back to the requesting host. */
847 if (send(fd
, buf
, strlen(buf
), 0) < 0) {
848 maybe_syslog(LOG_ERR
, "send: %m");
855 /* Check if a .noident file exists in the user home directory. */
857 check_noident(const char *homedir
)
865 if (asprintf(&path
, "%s/.noident", homedir
) < 0)
867 ret
= stat(path
, &sb
);
874 * Check if a .ident file exists in the user home directory and
875 * return the contents of that file.
878 check_userident(const char *homedir
, char *username
, size_t len
)
885 if (len
== 0 || homedir
== NULL
)
887 if (asprintf(&path
, "%s/.ident", homedir
) < 0)
889 if ((fd
= open(path
, O_RDONLY
|O_NONBLOCK
|O_NOFOLLOW
, 0)) < 0) {
893 if (fstat(fd
, &sb
) < 0 || !S_ISREG(sb
.st_mode
)) {
898 if ((n
= read(fd
, username
, len
- 1)) < 1) {
905 if ((p
= strpbrk(username
, "\r\n")) != NULL
)
913 /* Generate a random string. */
915 random_string(char *str
, size_t len
)
917 static const char chars
[] = "abcdefghijklmnopqrstuvwxyz1234567890";
922 for (p
= str
; len
> 1; len
--)
923 *p
++ = chars
[arc4random() % (sizeof(chars
) - 1)];
927 /* Change the output format. */
929 change_format(const char *format
, struct passwd
*pw
, char *dest
, size_t len
)
936 if (len
== 0 || ((gr
= getgrgid(pw
->pw_gid
)) == NULL
))
939 for (bp
= 0, cp
= format
; *cp
!= '\0' && bp
< len
- 1; cp
++) {
948 (void)snprintf(&dest
[bp
], len
- bp
, "%s", pw
->pw_name
);
951 (void)snprintf(&dest
[bp
], len
- bp
, "%d", pw
->pw_uid
);
954 (void)snprintf(&dest
[bp
], len
- bp
, "%s", gr
->gr_name
);
957 (void)snprintf(&dest
[bp
], len
- bp
, "%d", gr
->gr_gid
);
960 (void)snprintf(&dest
[bp
], len
- bp
, "%s", gr
->gr_name
);
961 bp
+= strlen(&dest
[bp
]);
965 while ((gr
= getgrent()) != NULL
) {
966 if (gr
->gr_gid
== pw
->pw_gid
)
968 for (gmp
= gr
->gr_mem
; *gmp
&& **gmp
; gmp
++) {
969 if (strcmp(*gmp
, pw
->pw_name
) == 0) {
970 (void)snprintf(&dest
[bp
],
973 bp
+= strlen(&dest
[bp
]);
983 (void)snprintf(&dest
[bp
], len
- bp
, "%u", gr
->gr_gid
);
984 bp
+= strlen(&dest
[bp
]);
988 while ((gr
= getgrent()) != NULL
) {
989 if (gr
->gr_gid
== pw
->pw_gid
)
991 for (gmp
= gr
->gr_mem
; *gmp
&& **gmp
; gmp
++) {
992 if (strcmp(*gmp
, pw
->pw_name
) == 0) {
993 (void)snprintf(&dest
[bp
],
996 bp
+= strlen(&dest
[bp
]);
1010 bp
+= strlen(&dest
[bp
]);
1017 /* Just exit when we caught SIGALRM. */
1019 timeout_handler(int __unused s
)
1021 maybe_syslog(LOG_INFO
, "Timeout for request, closing connection...");
1025 /* Report error message string through syslog and quit. */
1027 fatal(const char *func
)
1029 maybe_syslog(LOG_ERR
, "%s: %m", func
);
1034 * Report an error through syslog and/or stderr and quit. Only used when
1035 * running identd in the background and when it isn't a daemon yet.
1038 die(const char *message
, ...)
1042 va_start(ap
, message
);
1044 vwarnx(message
, ap
);
1046 vsyslog(LOG_ERR
, message
, ap
);
1052 /* Log using syslog, but only if enabled with the -l flag. */
1054 maybe_syslog(int priority
, const char *message
, ...)
1059 va_start(ap
, message
);
1060 vsyslog(priority
, message
, ap
);