diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2008-05-24 02:33:06 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2008-05-24 02:33:06 +0000 |
commit | 17597ad2afb50133e284a84457ec06bc53022b22 (patch) | |
tree | bd4f8843e97f14aea5fd4f4471a5ef28fb79204a /libexec/identd | |
parent | b0f752a0ce0c5ad015409dbc9546ec714c1eed10 (diff) |
IPv6 support for standalone mode with assistance from millert@ and deraadt@
Tested by brad@ and sobrado@
ok deraadt@
Diffstat (limited to 'libexec/identd')
-rw-r--r-- | libexec/identd/identd.8 | 18 | ||||
-rw-r--r-- | libexec/identd/identd.c | 170 |
2 files changed, 121 insertions, 67 deletions
diff --git a/libexec/identd/identd.8 b/libexec/identd/identd.8 index 1d061ed65a1..95f70729442 100644 --- a/libexec/identd/identd.8 +++ b/libexec/identd/identd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: identd.8,v 1.26 2007/09/25 14:21:30 jmc Exp $ +.\" $OpenBSD: identd.8,v 1.27 2008/05/24 02:33:05 brad Exp $ .\" .\" Copyright (c) 1997, Jason Downs. All rights reserved. .\" @@ -27,7 +27,7 @@ .\" Copyright (c) 1992 Peter Eriksson, Lysator, Linkoping University. .\" This software has been released into the public domain. .\" -.Dd $Mdocdate: September 25 2007 $ +.Dd $Mdocdate: May 24 2008 $ .Dt IDENTD 8 .Os .Sh NAME @@ -36,7 +36,7 @@ .Sh SYNOPSIS .Nm identd .Bk -words -.Op Fl dehlmNnoUv +.Op Fl 46dehlmNnoUv .Op Fl b | i | w .Op Fl a Ar address .Op Fl c Ar charset @@ -58,6 +58,18 @@ process owning the connection. .Pp The options are as follows: .Bl -tag -width Ds +.It Fl 4 +When +.Fl b +is specified, forces +.Nm +to use IPv4 addresses only. +.It Fl 6 +When +.Fl b +is specified, forces +.Nm +to use IPv6 addresses only. .It Fl a Ar address Specify a local IP address in dotted quad format to bind the listen socket to if running as a stand-alone daemon. diff --git a/libexec/identd/identd.c b/libexec/identd/identd.c index 738e7e11b9f..821dfaf1058 100644 --- a/libexec/identd/identd.c +++ b/libexec/identd/identd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: identd.c,v 1.46 2007/09/26 02:46:29 ray Exp $ */ +/* $OpenBSD: identd.c,v 1.47 2008/05/24 02:33:05 brad Exp $ */ /* * This program is in the public domain and may be used freely by anyone @@ -37,6 +37,8 @@ extern char *__progname; +int af = PF_UNSPEC; + int verbose_flag; int debug_flag; int syslog_flag; @@ -65,7 +67,7 @@ void usage(void) { syslog(LOG_ERR, - "usage: %s [-dehlmNnoUv] [-b | -i | -w] [-a address] [-c charset] " + "usage: %s [-46dehlmNnoUv] [-b | -i | -w] [-a address] [-c charset] " "[-g gid] [-p port] [-t seconds] [-u uid]", __progname); exit(2); } @@ -143,14 +145,14 @@ int main(int argc, char *argv[]) { struct sockaddr_storage sa, sa2; - /* struct sockaddr_in sin;*/ struct sockaddr_in *sin; struct sockaddr_in6 *sin6; struct in_addr laddr, faddr; struct in6_addr laddr6, faddr6; struct passwd *pwd; struct group *grp; - int background_flag = 0, timeout = 0, ch; + struct pollfd *pfds = NULL; + int i, n = 0, background_flag = 0, timeout = 0, ch; char *portno = "auth"; char *bind_address = NULL; uid_t set_uid = 0; @@ -175,8 +177,14 @@ main(int argc, char *argv[]) /* * Parse the command line arguments */ - while ((ch = getopt(argc, argv, "hHbwit:p:a:u:g:c:loenvdmNU")) != -1) { + while ((ch = getopt(argc, argv, "46hHbwit:p:a:u:g:c:loenvdmNU")) != -1) { switch (ch) { + case '4': + af = AF_INET; + break; + case '6': + af = AF_INET6; + break; case 'h': token_flag = 1; break; @@ -271,54 +279,81 @@ main(int argc, char *argv[]) * Do the special handling needed for the "-b" flag */ if (background_flag == 1) { - struct sockaddr_in addr; - struct servent *sp; - int fd; + struct addrinfo hints, *res, *res0; + int true = 1; if (daemon(0, 0) != 0) exit(0); - fd = socket(AF_INET, SOCK_STREAM, 0); - if (fd == -1) - error("main: socket"); + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = af; + hints.ai_flags = AI_PASSIVE; + if (getaddrinfo(bind_address, portno, &hints, &res0) != 0) + error("main: getaddrinfo"); + + i = 0; + for (res = res0; res; res = res->ai_next) + i++; + + pfds = calloc(i, sizeof(pfds[0])); + if (!pfds) { + freeaddrinfo(res0); + error("main: calloc"); + } + + i = 0; + for (res = res0; res; res = res->ai_next) { + if ((pfds[i].fd = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) < 0) + continue; - if (fd != 0) - dup2(fd, 0); - - memset(&addr, 0, sizeof(addr)); - - addr.sin_len = sizeof(struct sockaddr_in); - addr.sin_family = AF_INET; - if (bind_address == NULL) - addr.sin_addr.s_addr = htonl(INADDR_ANY); - else { - if (inet_aton(bind_address, &addr.sin_addr) == 0) { - struct hostent *hp; - - hp = gethostbyname(bind_address); - if (!hp) - error("no such address (%s) for -a switch", - bind_address); - memcpy(&addr.sin_addr, hp->h_addr, - sizeof(addr.sin_addr)); + if (setsockopt(pfds[i].fd, SOL_SOCKET, SO_REUSEADDR, + (void *)&true, sizeof(true))) { + close(pfds[i].fd); + continue; } - } - if (isdigit(portno[0])) - addr.sin_port = htons(atoi(portno)); - else { - sp = getservbyname(portno, "tcp"); - if (sp == NULL) - error("main: getservbyname: %s", portno); - addr.sin_port = sp->s_port; +#ifdef IPV6_V6ONLY + if (res->ai_family == AF_INET6) + (void)setsockopt(pfds[i].fd, IPPROTO_IPV6, + IPV6_V6ONLY, (void *)&true, sizeof(true)); +#endif + + if (bind(pfds[i].fd, res->ai_addr, res->ai_addrlen)) { + close(pfds[i].fd); + continue; + } + + if (listen(pfds[i].fd, 3)) { + close(pfds[i].fd); + continue; + } + + pfds[i].events = POLLIN; + i++; } + freeaddrinfo(res0); - if (bind(0, (struct sockaddr *) &addr, sizeof(addr)) < 0) - error("main: bind"); + if (i == 0) + error("main: socket"); - if (listen(0, 3) < 0) - error("main: listen"); + n = i; } + + /* + * Do the special handling needed for the "-w" flag + */ + if (background_flag == 2) { + pfds = calloc(1, sizeof(pfds[0])); + if (!pfds) + error("main: calloc"); + + pfds[0].fd = 0; + pfds[0].events = POLLIN; + n = 1; + } + if (set_gid) { if (setegid(set_gid) == -1) error("main: setegid"); @@ -331,12 +366,12 @@ main(int argc, char *argv[]) if (setuid(set_uid) == -1) error("main: setuid"); } + /* * Do some special handling if the "-b" or "-w" flags are used */ if (background_flag) { - int nfds, fd; - struct pollfd pfd[1]; + int fd = 0; signal(SIGCHLD, sigchld); @@ -364,25 +399,22 @@ main(int argc, char *argv[]) exit(0); } - pfd[0].fd = 0; - pfd[0].events = POLLIN; - if (timeout) - nfds = poll(pfd, 1, timeout * 1000); + i = poll(pfds, n, timeout * 1000); else - nfds = poll(pfd, 1, INFTIM); - } while (nfds < 0 && errno == EINTR); + i = poll(pfds, n, INFTIM); + } while (i < 0 && errno == EINTR); /* * An error occurred in poll? Just die */ - if (nfds < 0) + if (i < 0) error("main: poll"); /* * Timeout limit reached. Exit nicely */ - if (nfds == 0) + if (i == 0) exit(0); /* @@ -390,18 +422,27 @@ main(int argc, char *argv[]) */ alarm(0); - /* - * Accept the new client - */ - fd = accept(0, NULL, NULL); - if (fd == -1) - error("main: accept. errno = %d", errno); + for (i = 0; i < n; i++) { + if ((pfds[i].revents & POLLIN) == 0) + continue; + + /* + * Accept the new client + */ + fd = accept(pfds[i].fd, NULL, NULL); + if (fd == -1) + error("main: accept. errno = %d", errno); + + /* + * Fork a child, parent continues + */ + child_pid = fork(); + if (child_pid == 0) + break; - /* - * And fork, then close the fd if we are the parent. - */ - child_pid = fork(); - } while (child_pid && (close(fd), 1)); + close(fd); + } + } while (child_pid != 0); /* * We are now in child, the parent has returned to "do" above. @@ -415,6 +456,7 @@ main(int argc, char *argv[]) if (dup2(fd, 2) == -1) error("main: dup2: failed fd 2"); } + /* * Get foreign internet address */ @@ -455,7 +497,7 @@ main(int argc, char *argv[]) */ exit(1); } - /* are we V4 or V6? */ + /* are we v4 or v6? */ if (sa2.ss_family == AF_INET6) { sin6 = (struct sockaddr_in6 *)&sa2; laddr6 = sin6->sin6_addr; |