1 1.38 msaitoh /* $NetBSD: identd.c,v 1.38 2021/12/05 05:03:05 msaitoh Exp $ */ 2 1.8 mrg 3 1.1 cgd /* 4 1.20 christos * identd.c - TCP/IP Ident protocol server. 5 1.20 christos * 6 1.20 christos * This software is in the public domain. 7 1.26 peter * Written by Peter Postma <peter (at) NetBSD.org> 8 1.20 christos */ 9 1.20 christos 10 1.29 peter #include <sys/cdefs.h> 11 1.38 msaitoh __RCSID("$NetBSD: identd.c,v 1.38 2021/12/05 05:03:05 msaitoh Exp $"); 12 1.29 peter 13 1.29 peter #include <sys/param.h> 14 1.20 christos #include <sys/socket.h> 15 1.20 christos #include <sys/stat.h> 16 1.20 christos #include <sys/sysctl.h> 17 1.20 christos 18 1.20 christos #include <netinet/in.h> 19 1.20 christos #include <netinet/ip_var.h> 20 1.20 christos #include <netinet/tcp.h> 21 1.20 christos #include <netinet/tcp_timer.h> 22 1.20 christos #include <netinet/tcp_var.h> 23 1.20 christos 24 1.20 christos #include <arpa/inet.h> 25 1.9 msaitoh 26 1.9 msaitoh #include <ctype.h> 27 1.20 christos #include <err.h> 28 1.9 msaitoh #include <errno.h> 29 1.20 christos #include <fcntl.h> 30 1.20 christos #include <grp.h> 31 1.9 msaitoh #include <netdb.h> 32 1.20 christos #include <poll.h> 33 1.20 christos #include <pwd.h> 34 1.9 msaitoh #include <signal.h> 35 1.25 peter #include <stdarg.h> 36 1.20 christos #include <stdio.h> 37 1.20 christos #include <stdlib.h> 38 1.20 christos #include <string.h> 39 1.20 christos #include <syslog.h> 40 1.20 christos #include <unistd.h> 41 1.20 christos 42 1.26 peter #include "identd.h" 43 1.26 peter 44 1.29 peter #define OPSYS_NAME "UNIX" 45 1.29 peter #define IDENT_SERVICE "auth" 46 1.29 peter #define TIMEOUT 30 /* seconds */ 47 1.20 christos 48 1.20 christos static int idhandle(int, const char *, const char *, const char *, 49 1.26 peter const char *, struct sockaddr *, int); 50 1.20 christos static void idparse(int, int, int, const char *, const char *, const char *); 51 1.20 christos static void iderror(int, int, int, const char *); 52 1.26 peter static const char *gethost(struct sockaddr *); 53 1.20 christos static int *socketsetup(const char *, const char *, int); 54 1.26 peter static int ident_getuid(struct sockaddr_storage *, socklen_t, 55 1.26 peter struct sockaddr *, uid_t *); 56 1.20 christos static int sysctl_getuid(struct sockaddr_storage *, socklen_t, uid_t *); 57 1.26 peter static int sysctl_proxy_getuid(struct sockaddr_storage *, 58 1.26 peter struct sockaddr *, uid_t *); 59 1.26 peter static int forward(int, struct sockaddr *, int, int, int); 60 1.20 christos static int check_noident(const char *); 61 1.20 christos static int check_userident(const char *, char *, size_t); 62 1.20 christos static void random_string(char *, size_t); 63 1.25 peter static int change_format(const char *, struct passwd *, char *, size_t); 64 1.33 joerg __dead static void timeout_handler(int); 65 1.33 joerg __dead static void fatal(const char *); 66 1.34 joerg __dead static void die(const char *, ...) __printflike(1, 2); 67 1.20 christos 68 1.35 christos static int bflag, dflag, eflag, fflag, iflag, Iflag; 69 1.20 christos static int lflag, Lflag, nflag, Nflag, rflag; 70 1.20 christos 71 1.26 peter /* NAT lookup function pointer. */ 72 1.35 christos typedef int (*nat_lookup_t)(const struct sockaddr_storage *, 73 1.35 christos struct sockaddr_storage *, in_port_t *); 74 1.35 christos 75 1.35 christos static nat_lookup_t nat_lookup; 76 1.26 peter 77 1.26 peter /* Packet filters. */ 78 1.26 peter static const struct { 79 1.26 peter const char *name; 80 1.35 christos nat_lookup_t fn; 81 1.26 peter } filters[] = { 82 1.26 peter #ifdef WITH_PF 83 1.26 peter { "pf", pf_natlookup }, 84 1.26 peter #endif 85 1.26 peter #ifdef WITH_IPF 86 1.26 peter { "ipfilter", ipf_natlookup }, 87 1.26 peter #endif 88 1.35 christos #ifdef WITH_NPF 89 1.35 christos { "npf", npf_natlookup }, 90 1.35 christos #endif 91 1.26 peter { NULL, NULL } 92 1.26 peter }; 93 1.26 peter 94 1.20 christos int 95 1.20 christos main(int argc, char *argv[]) 96 1.20 christos { 97 1.26 peter int IPv4or6, ch, error, i, *socks, timeout; 98 1.26 peter const char *filter, *osname, *portno, *proxy; 99 1.25 peter char *address, *charset, *fmt, *p; 100 1.20 christos char user[LOGIN_NAME_MAX]; 101 1.26 peter struct addrinfo *ai, hints; 102 1.26 peter struct sockaddr *proxy_addr; 103 1.20 christos struct group *grp; 104 1.20 christos struct passwd *pw; 105 1.20 christos gid_t gid; 106 1.20 christos uid_t uid; 107 1.20 christos 108 1.28 lukem socks = NULL; 109 1.20 christos IPv4or6 = AF_UNSPEC; 110 1.20 christos osname = OPSYS_NAME; 111 1.20 christos portno = IDENT_SERVICE; 112 1.20 christos timeout = TIMEOUT; 113 1.26 peter nat_lookup = NULL; 114 1.26 peter proxy_addr = NULL; 115 1.26 peter filter = proxy = NULL; 116 1.25 peter address = charset = fmt = NULL; 117 1.25 peter uid = gid = 0; 118 1.35 christos bflag = dflag = eflag = fflag = iflag = Iflag = 0; 119 1.20 christos lflag = Lflag = nflag = Nflag = rflag = 0; 120 1.20 christos 121 1.25 peter /* Started from a tty? then run as daemon. */ 122 1.29 peter if (isatty(STDIN_FILENO)) 123 1.20 christos bflag = 1; 124 1.20 christos 125 1.25 peter /* Parse command line arguments. */ 126 1.26 peter while ((ch = getopt(argc, argv, 127 1.35 christos "46a:bcdeF:f:g:IiL:lm:Nno:P:p:rt:u:")) != -1) { 128 1.20 christos switch (ch) { 129 1.20 christos case '4': 130 1.20 christos IPv4or6 = AF_INET; 131 1.20 christos break; 132 1.20 christos case '6': 133 1.20 christos IPv4or6 = AF_INET6; 134 1.20 christos break; 135 1.20 christos case 'a': 136 1.20 christos address = optarg; 137 1.20 christos break; 138 1.20 christos case 'b': 139 1.20 christos bflag = 1; 140 1.20 christos break; 141 1.20 christos case 'c': 142 1.20 christos charset = optarg; 143 1.20 christos break; 144 1.35 christos case 'd': 145 1.35 christos dflag++; 146 1.35 christos break; 147 1.20 christos case 'e': 148 1.20 christos eflag = 1; 149 1.20 christos break; 150 1.20 christos case 'F': 151 1.20 christos fmt = optarg; 152 1.20 christos break; 153 1.20 christos case 'f': 154 1.20 christos fflag = 1; 155 1.20 christos (void)strlcpy(user, optarg, sizeof(user)); 156 1.20 christos break; 157 1.20 christos case 'g': 158 1.20 christos gid = (gid_t)strtol(optarg, &p, 0); 159 1.20 christos if (*p != '\0') { 160 1.20 christos if ((grp = getgrnam(optarg)) != NULL) 161 1.20 christos gid = grp->gr_gid; 162 1.20 christos else 163 1.26 peter die("No such group `%s'", optarg); 164 1.20 christos } 165 1.20 christos break; 166 1.20 christos case 'I': 167 1.20 christos Iflag = 1; 168 1.20 christos /* FALLTHROUGH */ 169 1.20 christos case 'i': 170 1.20 christos iflag = 1; 171 1.20 christos break; 172 1.20 christos case 'L': 173 1.20 christos Lflag = 1; 174 1.20 christos (void)strlcpy(user, optarg, sizeof(user)); 175 1.20 christos break; 176 1.20 christos case 'l': 177 1.26 peter if (!lflag) 178 1.26 peter openlog("identd", LOG_PID, LOG_DAEMON); 179 1.20 christos lflag = 1; 180 1.20 christos break; 181 1.26 peter case 'm': 182 1.26 peter filter = optarg; 183 1.26 peter break; 184 1.20 christos case 'N': 185 1.20 christos Nflag = 1; 186 1.20 christos break; 187 1.20 christos case 'n': 188 1.20 christos nflag = 1; 189 1.20 christos break; 190 1.20 christos case 'o': 191 1.20 christos osname = optarg; 192 1.20 christos break; 193 1.26 peter case 'P': 194 1.26 peter proxy = optarg; 195 1.26 peter break; 196 1.20 christos case 'p': 197 1.20 christos portno = optarg; 198 1.20 christos break; 199 1.20 christos case 'r': 200 1.20 christos rflag = 1; 201 1.20 christos break; 202 1.20 christos case 't': 203 1.20 christos timeout = (int)strtol(optarg, &p, 0); 204 1.26 peter if (*p != '\0' || timeout < 1) 205 1.26 peter die("Invalid timeout value `%s'", optarg); 206 1.20 christos break; 207 1.20 christos case 'u': 208 1.20 christos uid = (uid_t)strtol(optarg, &p, 0); 209 1.20 christos if (*p != '\0') { 210 1.20 christos if ((pw = getpwnam(optarg)) != NULL) { 211 1.20 christos uid = pw->pw_uid; 212 1.20 christos gid = pw->pw_gid; 213 1.20 christos } else 214 1.26 peter die("No such user `%s'", optarg); 215 1.20 christos } 216 1.20 christos break; 217 1.20 christos default: 218 1.25 peter exit(EXIT_FAILURE); 219 1.20 christos } 220 1.26 peter } 221 1.20 christos 222 1.26 peter /* Verify proxy address, if enabled. */ 223 1.26 peter if (proxy != NULL) { 224 1.26 peter (void)memset(&hints, 0, sizeof(hints)); 225 1.26 peter hints.ai_family = IPv4or6; 226 1.26 peter hints.ai_socktype = SOCK_STREAM; 227 1.26 peter error = getaddrinfo(proxy, NULL, &hints, &ai); 228 1.26 peter if (error != 0) 229 1.26 peter die("Bad proxy `%s': %s", proxy, gai_strerror(error)); 230 1.26 peter if (ai->ai_next != NULL) 231 1.26 peter die("Bad proxy `%s': resolves to multiple addresses", 232 1.26 peter proxy); 233 1.26 peter proxy_addr = ai->ai_addr; 234 1.26 peter } 235 1.26 peter 236 1.26 peter /* Verify filter, if enabled. */ 237 1.26 peter if (filter != NULL) { 238 1.26 peter for (i = 0; filters[i].name != NULL; i++) { 239 1.26 peter if (strcasecmp(filter, filters[i].name) == 0) { 240 1.26 peter nat_lookup = filters[i].fn; 241 1.26 peter break; 242 1.26 peter } 243 1.26 peter } 244 1.26 peter if (nat_lookup == NULL) 245 1.26 peter die("Packet filter `%s' is not supported", filter); 246 1.26 peter } 247 1.20 christos 248 1.25 peter /* Setup sockets when running in the background. */ 249 1.25 peter if (bflag) 250 1.20 christos socks = socketsetup(address, portno, IPv4or6); 251 1.20 christos 252 1.25 peter /* Switch to another uid/gid? */ 253 1.26 peter if (gid && setgid(gid) == -1) 254 1.26 peter die("Failed to set GID to `%d': %s", gid, strerror(errno)); 255 1.26 peter if (uid && setuid(uid) == -1) 256 1.26 peter die("Failed to set UID to `%d': %s", uid, strerror(errno)); 257 1.20 christos 258 1.25 peter /* 259 1.25 peter * When running as daemon: daemonize, setup pollfds and go into 260 1.25 peter * the mainloop. Otherwise, just read the input from stdin and 261 1.25 peter * let inetd handle the sockets. 262 1.25 peter */ 263 1.20 christos if (bflag) { 264 1.26 peter int fd, nfds, rv; 265 1.20 christos struct pollfd *rfds; 266 1.20 christos 267 1.35 christos if (!dflag && daemon(0, 0) < 0) 268 1.26 peter die("daemon: %s", strerror(errno)); 269 1.20 christos 270 1.20 christos rfds = malloc(*socks * sizeof(struct pollfd)); 271 1.20 christos if (rfds == NULL) 272 1.20 christos fatal("malloc"); 273 1.20 christos nfds = *socks; 274 1.20 christos for (i = 0; i < nfds; i++) { 275 1.20 christos rfds[i].fd = socks[i+1]; 276 1.20 christos rfds[i].events = POLLIN; 277 1.20 christos rfds[i].revents = 0; 278 1.20 christos } 279 1.25 peter /* Mainloop for daemon. */ 280 1.20 christos for (;;) { 281 1.20 christos rv = poll(rfds, nfds, INFTIM); 282 1.25 peter if (rv < 0) { 283 1.25 peter if (errno == EINTR) 284 1.25 peter continue; 285 1.20 christos fatal("poll"); 286 1.25 peter } 287 1.20 christos for (i = 0; i < nfds; i++) { 288 1.20 christos if (rfds[i].revents & POLLIN) { 289 1.20 christos fd = accept(rfds[i].fd, NULL, NULL); 290 1.20 christos if (fd < 0) { 291 1.25 peter maybe_syslog(LOG_ERR, 292 1.25 peter "accept: %m"); 293 1.20 christos continue; 294 1.20 christos } 295 1.20 christos switch (fork()) { 296 1.20 christos case -1: /* error */ 297 1.25 peter maybe_syslog(LOG_ERR, 298 1.25 peter "fork: %m"); 299 1.20 christos (void)sleep(1); 300 1.20 christos break; 301 1.20 christos case 0: /* child */ 302 1.20 christos (void)idhandle(fd, charset, 303 1.26 peter fmt, osname, user, 304 1.26 peter proxy_addr, timeout); 305 1.25 peter _exit(EXIT_SUCCESS); 306 1.20 christos default: /* parent */ 307 1.27 peter (void)signal(SIGCHLD, SIG_IGN); 308 1.20 christos (void)close(fd); 309 1.20 christos } 310 1.20 christos } 311 1.20 christos } 312 1.20 christos } 313 1.20 christos } else 314 1.20 christos (void)idhandle(STDIN_FILENO, charset, fmt, osname, user, 315 1.26 peter proxy_addr, timeout); 316 1.20 christos 317 1.20 christos return 0; 318 1.20 christos } 319 1.20 christos 320 1.29 peter /* 321 1.29 peter * Handle a request on the ident port. Returns 0 on success or 1 on 322 1.29 peter * failure. The return values are currently ignored. 323 1.29 peter */ 324 1.20 christos static int 325 1.20 christos idhandle(int fd, const char *charset, const char *fmt, const char *osname, 326 1.26 peter const char *user, struct sockaddr *proxy, int timeout) 327 1.20 christos { 328 1.20 christos struct sockaddr_storage ss[2]; 329 1.22 christos char userbuf[LOGIN_NAME_MAX]; /* actual user name (or numeric uid) */ 330 1.22 christos char idbuf[LOGIN_NAME_MAX]; /* name to be used in response */ 331 1.20 christos char buf[BUFSIZ], *p; 332 1.20 christos struct passwd *pw; 333 1.29 peter int lport, fport; 334 1.20 christos socklen_t len; 335 1.20 christos uid_t uid; 336 1.29 peter ssize_t n; 337 1.32 lukem size_t qlen; 338 1.20 christos 339 1.20 christos lport = fport = 0; 340 1.20 christos 341 1.20 christos (void)strlcpy(idbuf, user, sizeof(idbuf)); 342 1.20 christos (void)signal(SIGALRM, timeout_handler); 343 1.20 christos (void)alarm(timeout); 344 1.20 christos 345 1.25 peter /* Get foreign internet address. */ 346 1.20 christos len = sizeof(ss[0]); 347 1.20 christos if (getpeername(fd, (struct sockaddr *)&ss[0], &len) < 0) 348 1.20 christos fatal("getpeername"); 349 1.20 christos 350 1.26 peter maybe_syslog(LOG_INFO, "Connection from %s", 351 1.26 peter gethost((struct sockaddr *)&ss[0])); 352 1.20 christos 353 1.25 peter /* Get local internet address. */ 354 1.20 christos len = sizeof(ss[1]); 355 1.20 christos if (getsockname(fd, (struct sockaddr *)&ss[1], &len) < 0) 356 1.20 christos fatal("getsockname"); 357 1.20 christos 358 1.25 peter /* Be sure to have the same address families. */ 359 1.20 christos if (ss[0].ss_family != ss[1].ss_family) { 360 1.25 peter maybe_syslog(LOG_ERR, "Different foreign/local address family"); 361 1.20 christos return 1; 362 1.20 christos } 363 1.20 christos 364 1.25 peter /* Receive data from the client. */ 365 1.30 christos qlen = 0; 366 1.30 christos for (;;) { 367 1.30 christos if ((n = recv(fd, &buf[qlen], sizeof(buf) - qlen, 0)) < 0) { 368 1.30 christos fatal("recv"); 369 1.30 christos } else if (n == 0) { 370 1.30 christos maybe_syslog(LOG_NOTICE, "recv: EOF"); 371 1.30 christos iderror(fd, 0, 0, "UNKNOWN-ERROR"); 372 1.30 christos return 1; 373 1.30 christos } 374 1.30 christos /* 375 1.30 christos * 1413 is not clear on what to do if data follows the first 376 1.30 christos * CRLF before we respond. We do not consider the query 377 1.30 christos * complete until we get a CRLF _at the end of the buffer_. 378 1.30 christos */ 379 1.30 christos qlen += n; 380 1.31 christos if (qlen >= sizeof(buf)) { 381 1.31 christos maybe_syslog(LOG_NOTICE, "recv: message too long"); 382 1.31 christos exit(0); 383 1.31 christos } 384 1.30 christos if ((qlen >= 2) && (buf[qlen - 2] == '\r') && 385 1.30 christos (buf[qlen - 1] == '\n')) 386 1.30 christos break; 387 1.20 christos } 388 1.30 christos buf[qlen - 2] = '\0'; 389 1.20 christos 390 1.25 peter /* Get local and remote ports from the received data. */ 391 1.20 christos p = buf; 392 1.24 dsl while (*p != '\0' && isspace((unsigned char)*p)) 393 1.20 christos p++; 394 1.20 christos if ((p = strtok(p, " \t,")) != NULL) { 395 1.20 christos lport = atoi(p); 396 1.20 christos if ((p = strtok(NULL, " \t,")) != NULL) 397 1.20 christos fport = atoi(p); 398 1.20 christos } 399 1.20 christos 400 1.20 christos /* Are the ports valid? */ 401 1.20 christos if (lport < 1 || lport > 65535 || fport < 1 || fport > 65535) { 402 1.25 peter maybe_syslog(LOG_NOTICE, "Invalid port(s): %d, %d from %s", 403 1.26 peter lport, fport, gethost((struct sockaddr *)&ss[0])); 404 1.20 christos iderror(fd, 0, 0, eflag ? "UNKNOWN-ERROR" : "INVALID-PORT"); 405 1.20 christos return 1; 406 1.20 christos } 407 1.20 christos 408 1.25 peter /* If there is a 'lie' user enabled, then handle it now and stop. */ 409 1.20 christos if (Lflag) { 410 1.25 peter maybe_syslog(LOG_NOTICE, "Lying with name %s to %s", 411 1.26 peter idbuf, gethost((struct sockaddr *)&ss[0])); 412 1.20 christos idparse(fd, lport, fport, charset, osname, idbuf); 413 1.20 christos return 0; 414 1.20 christos } 415 1.20 christos 416 1.25 peter /* Protocol dependent stuff. */ 417 1.20 christos switch (ss[0].ss_family) { 418 1.20 christos case AF_INET: 419 1.26 peter satosin(&ss[0])->sin_port = htons(fport); 420 1.26 peter satosin(&ss[1])->sin_port = htons(lport); 421 1.20 christos break; 422 1.20 christos case AF_INET6: 423 1.26 peter satosin6(&ss[0])->sin6_port = htons(fport); 424 1.26 peter satosin6(&ss[1])->sin6_port = htons(lport); 425 1.20 christos break; 426 1.20 christos default: 427 1.25 peter maybe_syslog(LOG_ERR, "Unsupported protocol (no. %d)", 428 1.25 peter ss[0].ss_family); 429 1.20 christos return 1; 430 1.20 christos } 431 1.20 christos 432 1.25 peter /* Try to get the UID of the connection owner using sysctl. */ 433 1.26 peter if (ident_getuid(ss, sizeof(ss), proxy, &uid) == -1) { 434 1.26 peter /* Lookup failed, try to forward if enabled. */ 435 1.26 peter if (nat_lookup != NULL) { 436 1.35 christos struct sockaddr_storage nat_addr; 437 1.35 christos in_port_t nat_lport; 438 1.26 peter 439 1.26 peter (void)memset(&nat_addr, 0, sizeof(nat_addr)); 440 1.26 peter if ((*nat_lookup)(ss, &nat_addr, &nat_lport) && 441 1.35 christos forward(fd, (struct sockaddr *)&nat_addr, 442 1.35 christos nat_lport, fport, lport)) { 443 1.26 peter maybe_syslog(LOG_INFO, 444 1.37 andvar "Successfully forwarded the request to %s", 445 1.35 christos gethost((struct sockaddr *)&nat_addr)); 446 1.26 peter return 0; 447 1.26 peter } 448 1.26 peter } 449 1.26 peter /* Fall back to a default name? */ 450 1.20 christos if (fflag) { 451 1.25 peter maybe_syslog(LOG_NOTICE, "Using fallback name %s to %s", 452 1.26 peter idbuf, gethost((struct sockaddr *)&ss[0])); 453 1.20 christos idparse(fd, lport, fport, charset, osname, idbuf); 454 1.20 christos return 0; 455 1.20 christos } 456 1.26 peter maybe_syslog(LOG_ERR, "Lookup failed, returning error to %s", 457 1.26 peter gethost((struct sockaddr *)&ss[0])); 458 1.20 christos iderror(fd, lport, fport, eflag ? "UNKNOWN-ERROR" : "NO-USER"); 459 1.20 christos return 1; 460 1.20 christos } 461 1.20 christos 462 1.25 peter /* Fill in userbuf with user name if possible, else numeric UID. */ 463 1.20 christos if ((pw = getpwuid(uid)) == NULL) { 464 1.25 peter maybe_syslog(LOG_ERR, "Couldn't map uid (%u) to name", uid); 465 1.22 christos (void)snprintf(userbuf, sizeof(userbuf), "%u", uid); 466 1.22 christos } else { 467 1.25 peter maybe_syslog(LOG_INFO, "Successful lookup: %d, %d: %s for %s", 468 1.26 peter lport, fport, pw->pw_name, 469 1.26 peter gethost((struct sockaddr *)&ss[0])); 470 1.22 christos (void)strlcpy(userbuf, pw->pw_name, sizeof(userbuf)); 471 1.20 christos } 472 1.20 christos 473 1.20 christos /* No ident enabled? */ 474 1.22 christos if (Nflag && pw && check_noident(pw->pw_dir)) { 475 1.25 peter maybe_syslog(LOG_NOTICE, "Returning HIDDEN-USER for user %s" 476 1.26 peter " to %s", pw->pw_name, gethost((struct sockaddr *)&ss[0])); 477 1.20 christos iderror(fd, lport, fport, "HIDDEN-USER"); 478 1.20 christos return 1; 479 1.20 christos } 480 1.20 christos 481 1.25 peter /* User ident enabled? */ 482 1.22 christos if (iflag && pw && check_userident(pw->pw_dir, idbuf, sizeof(idbuf))) { 483 1.20 christos if (!Iflag) { 484 1.22 christos if ((strspn(idbuf, "0123456789") && 485 1.25 peter getpwuid(atoi(idbuf)) != NULL) || 486 1.25 peter (getpwnam(idbuf) != NULL)) { 487 1.25 peter maybe_syslog(LOG_NOTICE, 488 1.25 peter "Ignoring user-specified '%s' for user %s", 489 1.25 peter idbuf, userbuf); 490 1.20 christos (void)strlcpy(idbuf, userbuf, sizeof(idbuf)); 491 1.22 christos } 492 1.20 christos } 493 1.26 peter maybe_syslog(LOG_NOTICE, 494 1.26 peter "Returning user-specified '%s' for user %s to %s", 495 1.26 peter idbuf, userbuf, gethost((struct sockaddr *)&ss[0])); 496 1.20 christos idparse(fd, lport, fport, charset, osname, idbuf); 497 1.20 christos return 0; 498 1.20 christos } 499 1.20 christos 500 1.25 peter /* Send a random message? */ 501 1.20 christos if (rflag) { 502 1.20 christos /* Random number or string? */ 503 1.20 christos if (nflag) 504 1.20 christos (void)snprintf(idbuf, sizeof(idbuf), "%u", 505 1.20 christos (unsigned int)(arc4random() % 65535)); 506 1.20 christos else 507 1.20 christos random_string(idbuf, sizeof(idbuf)); 508 1.20 christos 509 1.26 peter maybe_syslog(LOG_NOTICE, 510 1.26 peter "Returning random '%s' for user %s to %s", 511 1.26 peter idbuf, userbuf, gethost((struct sockaddr *)&ss[0])); 512 1.20 christos idparse(fd, lport, fport, charset, osname, idbuf); 513 1.20 christos return 0; 514 1.20 christos } 515 1.20 christos 516 1.38 msaitoh /* Return numeric user ID? */ 517 1.20 christos if (nflag) 518 1.20 christos (void)snprintf(idbuf, sizeof(idbuf), "%u", uid); 519 1.20 christos else 520 1.22 christos (void)strlcpy(idbuf, userbuf, sizeof(idbuf)); 521 1.20 christos 522 1.25 peter /* 523 1.25 peter * Change the output format? Note that 512 is the maximum 524 1.25 peter * size of the result according to RFC 1413. 525 1.25 peter */ 526 1.29 peter if (fmt && change_format(fmt, pw, buf, 512 + 1)) 527 1.20 christos idparse(fd, lport, fport, charset, osname, buf); 528 1.25 peter else 529 1.20 christos idparse(fd, lport, fport, charset, osname, idbuf); 530 1.20 christos 531 1.20 christos return 0; 532 1.20 christos } 533 1.20 christos 534 1.25 peter /* Send/parse the ident result. */ 535 1.20 christos static void 536 1.20 christos idparse(int fd, int lport, int fport, const char *charset, const char *osname, 537 1.20 christos const char *user) 538 1.20 christos { 539 1.20 christos char *p; 540 1.9 msaitoh 541 1.23 kim if (asprintf(&p, "%d,%d:USERID:%s%s%s:%s\r\n", lport, fport, 542 1.23 kim osname, charset ? "," : "", charset ? charset : "", user) < 0) 543 1.20 christos fatal("asprintf"); 544 1.20 christos if (send(fd, p, strlen(p), 0) < 0) { 545 1.20 christos free(p); 546 1.20 christos fatal("send"); 547 1.20 christos } 548 1.20 christos free(p); 549 1.20 christos } 550 1.1 cgd 551 1.25 peter /* Return a specified ident error. */ 552 1.20 christos static void 553 1.20 christos iderror(int fd, int lport, int fport, const char *error) 554 1.20 christos { 555 1.20 christos char *p; 556 1.1 cgd 557 1.23 kim if (asprintf(&p, "%d,%d:ERROR:%s\r\n", lport, fport, error) < 0) 558 1.20 christos fatal("asprintf"); 559 1.20 christos if (send(fd, p, strlen(p), 0) < 0) { 560 1.20 christos free(p); 561 1.20 christos fatal("send"); 562 1.20 christos } 563 1.20 christos free(p); 564 1.20 christos } 565 1.1 cgd 566 1.25 peter /* Return the IP address of the connecting host. */ 567 1.20 christos static const char * 568 1.26 peter gethost(struct sockaddr *sa) 569 1.20 christos { 570 1.20 christos static char host[NI_MAXHOST]; 571 1.8 mrg 572 1.26 peter if (getnameinfo(sa, sa->sa_len, host, sizeof(host), 573 1.26 peter NULL, 0, NI_NUMERICHOST) == 0) 574 1.20 christos return host; 575 1.9 msaitoh 576 1.20 christos return "UNKNOWN"; 577 1.9 msaitoh } 578 1.1 cgd 579 1.25 peter /* Setup sockets, for daemon mode. */ 580 1.20 christos static int * 581 1.20 christos socketsetup(const char *address, const char *port, int af) 582 1.20 christos { 583 1.20 christos struct addrinfo hints, *res, *res0; 584 1.29 peter int error, maxs, *s, *socks; 585 1.20 christos const char *cause = NULL; 586 1.29 peter socklen_t y = 1; 587 1.20 christos 588 1.20 christos (void)memset(&hints, 0, sizeof(hints)); 589 1.20 christos hints.ai_flags = AI_PASSIVE; 590 1.20 christos hints.ai_family = af; 591 1.20 christos hints.ai_socktype = SOCK_STREAM; 592 1.20 christos error = getaddrinfo(address, port, &hints, &res0); 593 1.20 christos if (error) { 594 1.26 peter die("getaddrinfo: %s", gai_strerror(error)); 595 1.25 peter /* NOTREACHED */ 596 1.20 christos } 597 1.20 christos 598 1.25 peter /* Count max number of sockets we may open. */ 599 1.20 christos for (maxs = 0, res = res0; res != NULL; res = res->ai_next) 600 1.20 christos maxs++; 601 1.20 christos 602 1.20 christos socks = malloc((maxs + 1) * sizeof(int)); 603 1.20 christos if (socks == NULL) { 604 1.26 peter die("malloc: %s", strerror(errno)); 605 1.20 christos /* NOTREACHED */ 606 1.20 christos } 607 1.20 christos 608 1.20 christos *socks = 0; 609 1.20 christos s = socks + 1; 610 1.20 christos for (res = res0; res != NULL; res = res->ai_next) { 611 1.20 christos *s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 612 1.20 christos if (*s < 0) { 613 1.20 christos cause = "socket"; 614 1.20 christos continue; 615 1.20 christos } 616 1.20 christos (void)setsockopt(*s, SOL_SOCKET, SO_REUSEADDR, &y, sizeof(y)); 617 1.20 christos if (bind(*s, res->ai_addr, res->ai_addrlen) < 0) { 618 1.20 christos cause = "bind"; 619 1.20 christos (void)close(*s); 620 1.20 christos continue; 621 1.20 christos } 622 1.20 christos if (listen(*s, 5) < 0) { 623 1.20 christos cause = "listen"; 624 1.20 christos (void)close(*s); 625 1.20 christos continue; 626 1.20 christos } 627 1.20 christos *socks = *socks + 1; 628 1.20 christos s++; 629 1.20 christos } 630 1.20 christos 631 1.20 christos if (*socks == 0) { 632 1.20 christos free(socks); 633 1.26 peter die("%s: %s", cause, strerror(errno)); 634 1.20 christos /* NOTREACHED */ 635 1.20 christos } 636 1.20 christos if (res0) 637 1.20 christos freeaddrinfo(res0); 638 1.9 msaitoh 639 1.20 christos return socks; 640 1.1 cgd } 641 1.1 cgd 642 1.26 peter /* UID lookup wrapper. */ 643 1.26 peter static int 644 1.26 peter ident_getuid(struct sockaddr_storage *ss, socklen_t len, 645 1.26 peter struct sockaddr *proxy, uid_t *uid) 646 1.26 peter { 647 1.26 peter int rc; 648 1.26 peter 649 1.26 peter rc = sysctl_getuid(ss, len, uid); 650 1.26 peter if (rc == -1 && proxy != NULL) 651 1.26 peter rc = sysctl_proxy_getuid(ss, proxy, uid); 652 1.26 peter 653 1.26 peter return rc; 654 1.26 peter } 655 1.26 peter 656 1.25 peter /* Try to get the UID of the connection owner using sysctl. */ 657 1.20 christos static int 658 1.20 christos sysctl_getuid(struct sockaddr_storage *ss, socklen_t len, uid_t *uid) 659 1.1 cgd { 660 1.20 christos int mib[4]; 661 1.20 christos uid_t myuid; 662 1.20 christos size_t uidlen; 663 1.20 christos 664 1.20 christos uidlen = sizeof(myuid); 665 1.20 christos 666 1.20 christos mib[0] = CTL_NET; 667 1.20 christos mib[1] = ss->ss_family; 668 1.20 christos mib[2] = IPPROTO_TCP; 669 1.20 christos mib[3] = TCPCTL_IDENT; 670 1.20 christos 671 1.20 christos if (sysctl(mib, sizeof(mib)/ sizeof(int), &myuid, &uidlen, ss, len) < 0) 672 1.20 christos return -1; 673 1.20 christos *uid = myuid; 674 1.20 christos 675 1.20 christos return 0; 676 1.1 cgd } 677 1.9 msaitoh 678 1.26 peter /* Try to get the UID of the connection owner using sysctl (proxy version). */ 679 1.26 peter static int 680 1.26 peter sysctl_proxy_getuid(struct sockaddr_storage *ss, struct sockaddr *proxy, 681 1.26 peter uid_t *uid) 682 1.26 peter { 683 1.26 peter struct sockaddr_storage new[2]; 684 1.32 lukem int rc, name[CTL_MAXNAME]; 685 1.32 lukem size_t i; 686 1.26 peter struct kinfo_pcb *kp; 687 1.26 peter size_t sz, len; 688 1.26 peter const char *list; 689 1.26 peter 690 1.26 peter rc = -1; 691 1.26 peter sz = CTL_MAXNAME; 692 1.26 peter list = NULL; 693 1.26 peter 694 1.26 peter /* Retrieve a list of sockets. */ 695 1.26 peter switch (ss[0].ss_family) { 696 1.26 peter case AF_INET: 697 1.26 peter /* We only accept queries from the proxy. */ 698 1.26 peter if (in_hosteq(satosin(&ss[0])->sin_addr, 699 1.26 peter satosin(proxy)->sin_addr)) 700 1.26 peter list = "net.inet.tcp.pcblist"; 701 1.26 peter break; 702 1.26 peter case AF_INET6: 703 1.26 peter /* We only accept queries from the proxy. */ 704 1.26 peter if (IN6_ARE_ADDR_EQUAL(&satosin6(&ss[0])->sin6_addr, 705 1.26 peter &satosin6(proxy)->sin6_addr)) 706 1.26 peter list = "net.inet6.tcp.pcblist"; 707 1.26 peter break; 708 1.26 peter default: 709 1.26 peter maybe_syslog(LOG_ERR, "Unsupported protocol for proxy (no. %d)", 710 1.26 peter ss[0].ss_family); 711 1.26 peter } 712 1.26 peter if (list != NULL) 713 1.26 peter rc = sysctlnametomib(list, &name[0], &sz); 714 1.26 peter if (rc == -1) 715 1.26 peter return -1; 716 1.26 peter len = sz; 717 1.26 peter 718 1.26 peter name[len++] = PCB_ALL; 719 1.26 peter name[len++] = 0; 720 1.26 peter name[len++] = sizeof(struct kinfo_pcb); 721 1.26 peter name[len++] = INT_MAX; 722 1.26 peter 723 1.26 peter kp = NULL; 724 1.26 peter sz = 0; 725 1.26 peter do { 726 1.26 peter rc = sysctl(&name[0], len, kp, &sz, NULL, 0); 727 1.26 peter if (rc == -1 && errno != ENOMEM) 728 1.26 peter return -1; 729 1.26 peter if (kp == NULL) { 730 1.26 peter kp = malloc(sz); 731 1.26 peter rc = -1; 732 1.26 peter } 733 1.26 peter if (kp == NULL) 734 1.26 peter return -1; 735 1.26 peter } while (rc == -1); 736 1.26 peter 737 1.26 peter rc = -1; 738 1.26 peter /* 739 1.26 peter * Walk through the list of sockets and try to find a match. 740 1.26 peter * We don't know who has sent the query (we only know that the 741 1.26 peter * proxy has forwarded to us) so just try to match the ports and 742 1.26 peter * the local address. 743 1.26 peter */ 744 1.26 peter for (i = 0; i < sz / sizeof(struct kinfo_pcb); i++) { 745 1.26 peter switch (ss[0].ss_family) { 746 1.26 peter case AF_INET: 747 1.26 peter /* Foreign and local ports must match. */ 748 1.26 peter if (satosin(&ss[0])->sin_port != 749 1.26 peter satosin(&kp[i].ki_src)->sin_port) 750 1.26 peter continue; 751 1.26 peter if (satosin(&ss[1])->sin_port != 752 1.26 peter satosin(&kp[i].ki_dst)->sin_port) 753 1.26 peter continue; 754 1.26 peter /* Foreign address may not match proxy address. */ 755 1.26 peter if (in_hosteq(satosin(proxy)->sin_addr, 756 1.26 peter satosin(&kp[i].ki_dst)->sin_addr)) 757 1.26 peter continue; 758 1.26 peter /* Local addresses must match. */ 759 1.26 peter if (!in_hosteq(satosin(&ss[1])->sin_addr, 760 1.26 peter satosin(&kp[i].ki_src)->sin_addr)) 761 1.26 peter continue; 762 1.26 peter break; 763 1.26 peter case AF_INET6: 764 1.26 peter /* Foreign and local ports must match. */ 765 1.26 peter if (satosin6(&ss[0])->sin6_port != 766 1.26 peter satosin6(&kp[i].ki_src)->sin6_port) 767 1.26 peter continue; 768 1.26 peter if (satosin6(&ss[1])->sin6_port != 769 1.26 peter satosin6(&kp[i].ki_dst)->sin6_port) 770 1.26 peter continue; 771 1.26 peter /* Foreign address may not match proxy address. */ 772 1.26 peter if (IN6_ARE_ADDR_EQUAL(&satosin6(proxy)->sin6_addr, 773 1.26 peter &satosin6(&kp[i].ki_dst)->sin6_addr)) 774 1.26 peter continue; 775 1.26 peter /* Local addresses must match. */ 776 1.26 peter if (!IN6_ARE_ADDR_EQUAL(&satosin6(&ss[1])->sin6_addr, 777 1.26 peter &satosin6(&kp[i].ki_src)->sin6_addr)) 778 1.26 peter continue; 779 1.26 peter break; 780 1.26 peter } 781 1.26 peter 782 1.26 peter /* 783 1.26 peter * We have found the foreign address, copy it to a new 784 1.26 peter * struct and retrieve the UID of the connection owner. 785 1.26 peter */ 786 1.26 peter (void)memcpy(&new[0], &kp[i].ki_dst, kp[i].ki_dst.sa_len); 787 1.26 peter (void)memcpy(&new[1], &kp[i].ki_src, kp[i].ki_src.sa_len); 788 1.26 peter 789 1.26 peter rc = sysctl_getuid(new, sizeof(new), uid); 790 1.26 peter 791 1.26 peter /* Done. */ 792 1.26 peter break; 793 1.26 peter } 794 1.26 peter 795 1.26 peter free(kp); 796 1.26 peter return rc; 797 1.26 peter } 798 1.26 peter 799 1.37 andvar /* Forward ident queries. Returns 1 when successful, or zero if not. */ 800 1.26 peter static int 801 1.26 peter forward(int fd, struct sockaddr *nat_addr, int nat_lport, int fport, int lport) 802 1.26 peter { 803 1.26 peter char buf[BUFSIZ], reply[BUFSIZ], *p; 804 1.29 peter ssize_t n; 805 1.29 peter int sock; 806 1.26 peter 807 1.26 peter /* Connect to the NAT host. */ 808 1.26 peter sock = socket(nat_addr->sa_family, SOCK_STREAM, 0); 809 1.26 peter if (sock < 0) { 810 1.26 peter maybe_syslog(LOG_ERR, "socket: %m"); 811 1.26 peter return 0; 812 1.26 peter } 813 1.26 peter if (connect(sock, nat_addr, nat_addr->sa_len) < 0) { 814 1.26 peter maybe_syslog(LOG_ERR, "Can't connect to %s: %m", 815 1.26 peter gethost(nat_addr)); 816 1.26 peter (void)close(sock); 817 1.26 peter return 0; 818 1.26 peter } 819 1.26 peter 820 1.26 peter /* 821 1.26 peter * Send the ident query to the NAT host, but use as local port 822 1.26 peter * the port of the NAT host. 823 1.26 peter */ 824 1.35 christos (void)snprintf(buf, sizeof(buf), "%d , %d\r\n", fport, nat_lport); 825 1.26 peter if (send(sock, buf, strlen(buf), 0) < 0) { 826 1.26 peter maybe_syslog(LOG_ERR, "send: %m"); 827 1.26 peter (void)close(sock); 828 1.26 peter return 0; 829 1.26 peter } 830 1.26 peter 831 1.26 peter /* Read the reply from the NAT host. */ 832 1.26 peter if ((n = recv(sock, reply, sizeof(reply) - 1, 0)) < 0) { 833 1.26 peter maybe_syslog(LOG_ERR, "recv: %m"); 834 1.26 peter (void)close(sock); 835 1.26 peter return 0; 836 1.26 peter } else if (n == 0) { 837 1.26 peter maybe_syslog(LOG_NOTICE, "recv: EOF"); 838 1.26 peter (void)close(sock); 839 1.26 peter return 0; 840 1.26 peter } 841 1.26 peter reply[n] = '\0'; 842 1.35 christos if (dflag) 843 1.35 christos maybe_syslog(LOG_ERR, "Replied %s", reply); 844 1.26 peter (void)close(sock); 845 1.26 peter 846 1.26 peter /* Extract everything after the port specs from the ident reply. */ 847 1.26 peter for (p = reply; *p != '\0' && *p != ':'; p++) 848 1.26 peter continue; 849 1.26 peter if (*p == '\0' || *++p == '\0') { 850 1.26 peter maybe_syslog(LOG_ERR, "Malformed ident reply from %s", 851 1.26 peter gethost(nat_addr)); 852 1.26 peter return 0; 853 1.26 peter } 854 1.26 peter /* Build reply for the requesting host, use the original local port. */ 855 1.26 peter (void)snprintf(buf, sizeof(buf), "%d,%d:%s", lport, fport, p); 856 1.26 peter 857 1.26 peter /* Send the reply from the NAT host back to the requesting host. */ 858 1.26 peter if (send(fd, buf, strlen(buf), 0) < 0) { 859 1.26 peter maybe_syslog(LOG_ERR, "send: %m"); 860 1.26 peter return 0; 861 1.26 peter } 862 1.26 peter 863 1.26 peter return 1; 864 1.26 peter } 865 1.26 peter 866 1.25 peter /* Check if a .noident file exists in the user home directory. */ 867 1.20 christos static int 868 1.20 christos check_noident(const char *homedir) 869 1.20 christos { 870 1.20 christos struct stat sb; 871 1.20 christos char *path; 872 1.20 christos int ret; 873 1.20 christos 874 1.20 christos if (homedir == NULL) 875 1.20 christos return 0; 876 1.20 christos if (asprintf(&path, "%s/.noident", homedir) < 0) 877 1.20 christos return 0; 878 1.20 christos ret = stat(path, &sb); 879 1.20 christos 880 1.20 christos free(path); 881 1.20 christos return (ret == 0); 882 1.20 christos } 883 1.1 cgd 884 1.1 cgd /* 885 1.20 christos * Check if a .ident file exists in the user home directory and 886 1.20 christos * return the contents of that file. 887 1.20 christos */ 888 1.20 christos static int 889 1.20 christos check_userident(const char *homedir, char *username, size_t len) 890 1.20 christos { 891 1.20 christos struct stat sb; 892 1.20 christos char *path, *p; 893 1.29 peter ssize_t n; 894 1.29 peter int fd; 895 1.20 christos 896 1.20 christos if (len == 0 || homedir == NULL) 897 1.20 christos return 0; 898 1.20 christos if (asprintf(&path, "%s/.ident", homedir) < 0) 899 1.20 christos return 0; 900 1.20 christos if ((fd = open(path, O_RDONLY|O_NONBLOCK|O_NOFOLLOW, 0)) < 0) { 901 1.20 christos free(path); 902 1.20 christos return 0; 903 1.20 christos } 904 1.20 christos if (fstat(fd, &sb) < 0 || !S_ISREG(sb.st_mode)) { 905 1.20 christos (void)close(fd); 906 1.20 christos free(path); 907 1.20 christos return 0; 908 1.20 christos } 909 1.20 christos if ((n = read(fd, username, len - 1)) < 1) { 910 1.20 christos (void)close(fd); 911 1.20 christos free(path); 912 1.20 christos return 0; 913 1.20 christos } 914 1.20 christos username[n] = '\0'; 915 1.20 christos 916 1.25 peter if ((p = strpbrk(username, "\r\n")) != NULL) 917 1.20 christos *p = '\0'; 918 1.20 christos 919 1.20 christos (void)close(fd); 920 1.20 christos free(path); 921 1.20 christos return 1; 922 1.1 cgd } 923 1.1 cgd 924 1.25 peter /* Generate a random string. */ 925 1.20 christos static void 926 1.20 christos random_string(char *str, size_t len) 927 1.20 christos { 928 1.20 christos static const char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; 929 1.20 christos char *p; 930 1.20 christos 931 1.20 christos if (len == 0) 932 1.20 christos return; 933 1.20 christos for (p = str; len > 1; len--) 934 1.20 christos *p++ = chars[arc4random() % (sizeof(chars) - 1)]; 935 1.20 christos *p = '\0'; 936 1.20 christos } 937 1.1 cgd 938 1.25 peter /* Change the output format. */ 939 1.25 peter static int 940 1.20 christos change_format(const char *format, struct passwd *pw, char *dest, size_t len) 941 1.20 christos { 942 1.20 christos struct group *gr; 943 1.20 christos const char *cp; 944 1.20 christos char **gmp; 945 1.29 peter size_t bp; 946 1.20 christos 947 1.25 peter if (len == 0 || ((gr = getgrgid(pw->pw_gid)) == NULL)) 948 1.25 peter return 0; 949 1.20 christos 950 1.29 peter for (bp = 0, cp = format; *cp != '\0' && bp < len - 1; cp++) { 951 1.20 christos if (*cp != '%') { 952 1.20 christos dest[bp++] = *cp; 953 1.20 christos continue; 954 1.9 msaitoh } 955 1.20 christos if (*++cp == '\0') 956 1.20 christos break; 957 1.20 christos switch (*cp) { 958 1.20 christos case 'u': 959 1.29 peter (void)snprintf(&dest[bp], len - bp, "%s", pw->pw_name); 960 1.20 christos break; 961 1.20 christos case 'U': 962 1.20 christos (void)snprintf(&dest[bp], len - bp, "%d", pw->pw_uid); 963 1.20 christos break; 964 1.20 christos case 'g': 965 1.29 peter (void)snprintf(&dest[bp], len - bp, "%s", gr->gr_name); 966 1.20 christos break; 967 1.20 christos case 'G': 968 1.20 christos (void)snprintf(&dest[bp], len - bp, "%d", gr->gr_gid); 969 1.20 christos break; 970 1.20 christos case 'l': 971 1.29 peter (void)snprintf(&dest[bp], len - bp, "%s", gr->gr_name); 972 1.20 christos bp += strlen(&dest[bp]); 973 1.29 peter if (bp >= len) 974 1.20 christos break; 975 1.20 christos setgrent(); 976 1.20 christos while ((gr = getgrent()) != NULL) { 977 1.20 christos if (gr->gr_gid == pw->pw_gid) 978 1.20 christos continue; 979 1.20 christos for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) { 980 1.20 christos if (strcmp(*gmp, pw->pw_name) == 0) { 981 1.20 christos (void)snprintf(&dest[bp], 982 1.29 peter len - bp, ",%s", 983 1.29 peter gr->gr_name); 984 1.20 christos bp += strlen(&dest[bp]); 985 1.20 christos break; 986 1.20 christos } 987 1.20 christos } 988 1.29 peter if (bp >= len) 989 1.20 christos break; 990 1.20 christos } 991 1.20 christos endgrent(); 992 1.20 christos break; 993 1.20 christos case 'L': 994 1.20 christos (void)snprintf(&dest[bp], len - bp, "%u", gr->gr_gid); 995 1.20 christos bp += strlen(&dest[bp]); 996 1.29 peter if (bp >= len) 997 1.20 christos break; 998 1.20 christos setgrent(); 999 1.20 christos while ((gr = getgrent()) != NULL) { 1000 1.20 christos if (gr->gr_gid == pw->pw_gid) 1001 1.20 christos continue; 1002 1.20 christos for (gmp = gr->gr_mem; *gmp && **gmp; gmp++) { 1003 1.20 christos if (strcmp(*gmp, pw->pw_name) == 0) { 1004 1.20 christos (void)snprintf(&dest[bp], 1005 1.20 christos len - bp, ",%u", 1006 1.20 christos gr->gr_gid); 1007 1.20 christos bp += strlen(&dest[bp]); 1008 1.20 christos break; 1009 1.20 christos } 1010 1.20 christos } 1011 1.29 peter if (bp >= len) 1012 1.20 christos break; 1013 1.20 christos } 1014 1.20 christos endgrent(); 1015 1.20 christos break; 1016 1.20 christos default: 1017 1.20 christos dest[bp] = *cp; 1018 1.20 christos dest[bp+1] = '\0'; 1019 1.20 christos break; 1020 1.9 msaitoh } 1021 1.20 christos bp += strlen(&dest[bp]); 1022 1.20 christos } 1023 1.20 christos dest[bp] = '\0'; 1024 1.25 peter 1025 1.25 peter return 1; 1026 1.20 christos } 1027 1.20 christos 1028 1.25 peter /* Just exit when we caught SIGALRM. */ 1029 1.20 christos static void 1030 1.29 peter timeout_handler(int __unused s) 1031 1.20 christos { 1032 1.29 peter maybe_syslog(LOG_INFO, "Timeout for request, closing connection..."); 1033 1.25 peter exit(EXIT_FAILURE); 1034 1.20 christos } 1035 1.20 christos 1036 1.25 peter /* Report error message string through syslog and quit. */ 1037 1.20 christos static void 1038 1.20 christos fatal(const char *func) 1039 1.20 christos { 1040 1.25 peter maybe_syslog(LOG_ERR, "%s: %m", func); 1041 1.25 peter exit(EXIT_FAILURE); 1042 1.25 peter } 1043 1.25 peter 1044 1.26 peter /* 1045 1.26 peter * Report an error through syslog and/or stderr and quit. Only used when 1046 1.26 peter * running identd in the background and when it isn't a daemon yet. 1047 1.26 peter */ 1048 1.26 peter static void 1049 1.26 peter die(const char *message, ...) 1050 1.26 peter { 1051 1.26 peter va_list ap; 1052 1.26 peter 1053 1.36 christos if (bflag) { 1054 1.36 christos va_start(ap, message); 1055 1.26 peter vwarnx(message, ap); 1056 1.36 christos va_end(ap); 1057 1.36 christos } 1058 1.36 christos 1059 1.36 christos if (lflag) { 1060 1.36 christos va_start(ap, message); 1061 1.26 peter vsyslog(LOG_ERR, message, ap); 1062 1.36 christos va_end(ap); 1063 1.36 christos } 1064 1.26 peter 1065 1.26 peter exit(EXIT_FAILURE); 1066 1.26 peter } 1067 1.26 peter 1068 1.25 peter /* Log using syslog, but only if enabled with the -l flag. */ 1069 1.26 peter void 1070 1.25 peter maybe_syslog(int priority, const char *message, ...) 1071 1.25 peter { 1072 1.25 peter va_list ap; 1073 1.25 peter 1074 1.25 peter if (lflag) { 1075 1.25 peter va_start(ap, message); 1076 1.25 peter vsyslog(priority, message, ap); 1077 1.25 peter va_end(ap); 1078 1.25 peter } 1079 1.1 cgd } 1080