diff --git a/kpasswd/kpasswdd.c b/kpasswd/kpasswdd.c index 8166c5a94..4e4e2b530 100644 --- a/kpasswd/kpasswdd.c +++ b/kpasswd/kpasswdd.c @@ -706,45 +706,98 @@ doit(krb5_keytab keytab, int port) fd_set real_fdset; struct sockaddr_storage __ss; struct sockaddr *sa = (struct sockaddr *)&__ss; + int sd_activated = 0; - if (explicit_addresses.len) { - addrs = explicit_addresses; - } else { - ret = krb5_get_all_server_addrs(context, &addrs); - if (ret) - krb5_err(context, 1, ret, "krb5_get_all_server_addrs"); - } - n = addrs.len; +#ifdef HAVE_SYSTEMD + { + char **names = NULL; + int sd_n, j; - sockets = malloc(n * sizeof(*sockets)); - if (sockets == NULL) - krb5_errx(context, 1, "out of memory"); - maxfd = -1; - FD_ZERO(&real_fdset); - for (i = 0; i < n; ++i) { - krb5_socklen_t sa_size = sizeof(__ss); + sd_n = sd_listen_fds_with_names(0, &names); + if (sd_n < 0) + krb5_err(context, 1, -sd_n, "sd_listen_fds_with_names"); + if (sd_n > 0) { + sd_activated = 1; + sockets = malloc(sd_n * sizeof(*sockets)); + if (sockets == NULL) + krb5_errx(context, 1, "out of memory"); + memset(&addrs, 0, sizeof(addrs)); + addrs.val = malloc(sd_n * sizeof(*addrs.val)); + if (addrs.val == NULL) + krb5_errx(context, 1, "out of memory"); + n = 0; + maxfd = -1; + FD_ZERO(&real_fdset); + for (j = 0; j < sd_n; j++) { + int fd = SD_LISTEN_FDS_START + j; + krb5_socklen_t sa_size = sizeof(__ss); - krb5_addr2sockaddr(context, &addrs.val[i], sa, &sa_size, port); - - sockets[i] = socket(__ss.ss_family, SOCK_DGRAM, 0); - if (sockets[i] < 0) - krb5_err(context, 1, errno, "socket"); - if (bind(sockets[i], sa, sa_size) < 0) { - char str[128]; - size_t len; - int save_errno = errno; - - ret = krb5_print_address(&addrs.val[i], str, sizeof(str), &len); - if (ret) - strlcpy(str, "unknown address", sizeof(str)); - krb5_warn(context, save_errno, "bind(%s)", str); - continue; + if (names == NULL || names[j] == NULL || + strncmp(names[j], "kpasswdd", 8) != 0) + continue; + if (getsockname(fd, sa, &sa_size) < 0) { + krb5_warn(context, errno, + "getsockname on socket-activated fd %d", fd); + continue; + } + if (krb5_sockaddr2address(context, sa, &addrs.val[n]) != 0) + continue; + sockets[n] = fd; + maxfd = max(maxfd, fd); + if (maxfd >= FD_SETSIZE) + krb5_errx(context, 1, "fd too large"); + FD_SET(fd, &real_fdset); + n++; + } + addrs.len = n; } - maxfd = max(maxfd, sockets[i]); - if (maxfd >= FD_SETSIZE) - krb5_errx(context, 1, "fd too large"); - FD_SET(sockets[i], &real_fdset); + for (j = 0; names != NULL && names[j] != NULL; j++) + free(names[j]); + free(names); } +#endif /* HAVE_SYSTEMD */ + + if (!sd_activated) { + if (explicit_addresses.len) { + addrs = explicit_addresses; + } else { + ret = krb5_get_all_server_addrs(context, &addrs); + if (ret) + krb5_err(context, 1, ret, "krb5_get_all_server_addrs"); + } + n = addrs.len; + + sockets = malloc(n * sizeof(*sockets)); + if (sockets == NULL) + krb5_errx(context, 1, "out of memory"); + maxfd = -1; + FD_ZERO(&real_fdset); + for (i = 0; i < n; ++i) { + krb5_socklen_t sa_size = sizeof(__ss); + + krb5_addr2sockaddr(context, &addrs.val[i], sa, &sa_size, port); + + sockets[i] = socket(__ss.ss_family, SOCK_DGRAM, 0); + if (sockets[i] < 0) + krb5_err(context, 1, errno, "socket"); + if (bind(sockets[i], sa, sa_size) < 0) { + char str[128]; + size_t len; + int save_errno = errno; + + ret = krb5_print_address(&addrs.val[i], str, sizeof(str), &len); + if (ret) + strlcpy(str, "unknown address", sizeof(str)); + krb5_warn(context, save_errno, "bind(%s)", str); + continue; + } + maxfd = max(maxfd, sockets[i]); + if (maxfd >= FD_SETSIZE) + krb5_errx(context, 1, "fd too large"); + FD_SET(sockets[i], &real_fdset); + } + } + if (maxfd == -1) krb5_errx(context, 1, "No sockets!");