summaryrefslogtreecommitdiffstats
path: root/ipa-server
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2007-10-12 13:24:41 -0400
committerSimo Sorce <ssorce@redhat.com>2007-10-12 13:24:41 -0400
commit08855a4d770bb29f8f8737182e157faed29fc965 (patch)
tree148ac735c35e3df64353b60a2ae32d18227b0acc /ipa-server
parent91ab2d3893e1fa3843b38c1b05a6dccbff8a09b4 (diff)
downloadfreeipa-08855a4d770bb29f8f8737182e157faed29fc965.tar.gz
freeipa-08855a4d770bb29f8f8737182e157faed29fc965.tar.xz
freeipa-08855a4d770bb29f8f8737182e157faed29fc965.zip
Better handling of IPv4/IPv6 sockets in ipa-kpasswd
Tested with UDP and works
Diffstat (limited to 'ipa-server')
-rw-r--r--ipa-server/ipa-kpasswd/ipa_kpasswd.c214
1 files changed, 82 insertions, 132 deletions
diff --git a/ipa-server/ipa-kpasswd/ipa_kpasswd.c b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
index 5adb90b72..f5540b74c 100644
--- a/ipa-server/ipa-kpasswd/ipa_kpasswd.c
+++ b/ipa-server/ipa-kpasswd/ipa_kpasswd.c
@@ -8,12 +8,14 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
+#include <sys/poll.h>
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <netdb.h>
#include <syslog.h>
#include <netinet/in.h>
#include <arpa/inet.h>
@@ -25,8 +27,6 @@
#define DEFAULT_KEYTAB "FILE:/var/kerberos/krb5kdc/kpasswd.keytab"
#define TMP_TEMPLATE "/tmp/kpasswd.XXXXXX"
#define KPASSWD_PORT 464
-#define KPASSWD_TCP 1
-#define KPASSWD_UDP 2
struct blacklist {
struct blacklist *next;
@@ -785,7 +785,7 @@ done:
pid_t handle_conn(int fd, int type)
{
- int mfd;
+ int mfd, tcp;
pid_t pid;
char address[INET6_ADDRSTRLEN+1];
uint8_t request[1500];
@@ -797,10 +797,11 @@ pid_t handle_conn(int fd, int type)
ssize_t sendret;
fromlen = sizeof(from);
+ tcp = 0;
/* receive request */
- if (type == KPASSWD_TCP) {
-
+ if (type == SOCK_STREAM) {
+ tcp = 1;
mfd = accept(fd, (struct sockaddr *)&from, &fromlen);
if (mfd == -1) {
syslog(LOG_ERR, "Accept failed with error (%d) %s",
@@ -811,42 +812,15 @@ pid_t handle_conn(int fd, int type)
mfd = fd;
}
- reqlen = recvfrom(mfd, request, sizeof(request), 0,
- (struct sockaddr *)&from, &fromlen);
- if (reqlen <= 0) {
- syslog(LOG_ERR, "Error receiving request (%d) %s",
- errno, strerror(errno));
- if (type == KPASSWD_TCP) close(mfd);
- return -1;
- }
-
- switch(((struct sockaddr *)&from)->sa_family) {
- case AF_INET:
- if (!inet_ntop(((struct sockaddr_in *)&from)->sin_family,
- &(((struct sockaddr_in *)&from)->sin_addr),
- address, sizeof(address))) {
- address[0] = '\0';
- }
- break;
- case AF_INET6:
- if (!inet_ntop(((struct sockaddr_in6 *)&from)->sin6_family,
- &(((struct sockaddr_in6 *)&from)->sin6_addr),
- address, sizeof(address))) {
- address[0] = '\0';
- }
- break;
- default:
- syslog(LOG_ERR, "Invalid IP address Family");
- if (type == KPASSWD_TCP) close(mfd);
- return -1;
- }
-
+ (void) getnameinfo((struct sockaddr *)&from, fromlen,
+ address, INET6_ADDRSTRLEN+1,
+ NULL, 0, NI_NUMERICHOST);
if (debug > 0) {
syslog(LOG_ERR, "Connection from %s", address);
}
- /* Check blacklist for requests frm the same IP until operations
+ /* Check blacklist for requests from the same IP until operations
* are finished on the active client.
* the password change may be slow and pam_krb5 sends up to 3 UDP
* requests waiting 1 sec. each time.
@@ -856,21 +830,30 @@ pid_t handle_conn(int fd, int type)
if (debug > 0) {
syslog(LOG_ERR, "[%s] blacklisted", address);
}
- if (type == KPASSWD_TCP) close(mfd);
+ if (tcp) close(mfd);
return 0;
}
+ reqlen = recvfrom(mfd, request, sizeof(request), 0,
+ (struct sockaddr *)&from, &fromlen);
+ if (reqlen <= 0) {
+ syslog(LOG_ERR, "Error receiving request (%d) %s",
+ errno, strerror(errno));
+ if (tcp) close(mfd);
+ return -1;
+ }
+
#if 1
/* handle kerberos and ldap operations in childrens */
pid = fork();
if (pid == -1) {
syslog(LOG_ERR, "Fork failed with error (%d) %s",
errno, strerror(errno));
- if (type == KPASSWD_TCP) close(mfd);
+ if (tcp) close(mfd);
return 0;
}
if (pid != 0) { /* parent */
- if (type == KPASSWD_TCP) close(mfd);
+ if (tcp) close(mfd);
add_blacklist(pid, address);
return pid;
}
@@ -881,14 +864,14 @@ pid_t handle_conn(int fd, int type)
/* TCP packets prepend the lenght as a 32bit network order field,
* this information seem to be just redundant, so let's simply
* skip it */
- if (type == KPASSWD_TCP) {
+ if (tcp) {
handle_krb_packets(request+4, reqlen-4, &from, &reply, &replen);
} else {
handle_krb_packets(request, reqlen, &from, &reply, &replen);
}
if (replen) { /* we have something to reply */
- if (type == KPASSWD_TCP) {
+ if (tcp) {
sendret = sendto(mfd, reply, replen, 0, NULL, 0);
} else {
sendret = sendto(mfd, reply, replen, 0, (struct sockaddr *)&from, fromlen);
@@ -906,9 +889,11 @@ pid_t handle_conn(int fd, int type)
int main(int argc, char *argv[])
{
pid_t pid;
- struct sockaddr_in6 addr;
- int tcp_s, udp_s;
- int tru = 1;
+ struct addrinfo *ai, *tai;
+ struct addrinfo hints;
+ struct pollfd pfds[4];
+ int pfdtype[4];
+ int nfds;
int ret;
char *key;
@@ -935,6 +920,7 @@ int main(int argc, char *argv[])
/* new session */
setsid();
/* close std* descriptors */
+
close(0);
close(1);
close(2);
@@ -958,98 +944,65 @@ int main(int argc, char *argv[])
syslog(LOG_ERR, "Out of memory!");
}
- tcp_s = socket(AF_INET6, SOCK_STREAM, 0);
- if (tcp_s == -1) {
- syslog(LOG_ERR, "Unable to create TCP socket");
- exit(1);
- }
+ /* set hints */
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
- udp_s = socket(AF_INET6, SOCK_DGRAM, 0);
- if (udp_s == -1) {
- syslog(LOG_ERR, "Unable to create UDP socket");
- close(tcp_s);
+ ret = getaddrinfo (NULL, "kpasswd", &hints, &ai);
+ if (ret) {
+ syslog(LOG_ERR, "getaddrinfo failed: %s", gai_strerror(ret));
exit(1);
}
- /* make sockets immediately reusable */
- ret = setsockopt(tcp_s, SOL_SOCKET, SO_REUSEADDR,
- (void *)&tru, sizeof(tru));
- if (ret == -1) {
- syslog(LOG_ERR,
- "Unable to set SO_REUSEADDR for the TCP socket (%d) %s",
- errno, strerror(errno));
- close(tcp_s);
- close(udp_s);
- exit(2);
- }
-
- ret = setsockopt(udp_s, SOL_SOCKET, SO_REUSEADDR,
- (void *)&tru, sizeof(tru));
- if (ret == -1) {
- syslog(LOG_ERR,
- "Unable to set SO_REUSEADDR for the UDP socket (%d) %s",
- errno, strerror(errno));
- close(tcp_s);
- close(udp_s);
- exit(2);
- }
-
- /* bind sockets */
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_addr = in6addr_any;
- addr.sin6_port = htons(KPASSWD_PORT);
-
- ret = bind(tcp_s, (struct sockaddr *)&addr, sizeof(addr));
- if (ret == -1) {
- syslog(LOG_ERR,
- "Unable to bind the TCP kpasswd port (%d) %s",
- errno, strerror(errno));
- close(tcp_s);
- close(udp_s);
- exit(3);
- }
+ tai = ai;
+ nfds = 0;
+ /* we can have a maximum of 4 sockets (IPv4/IPv6(TCP/UDP)) */
+ for (tai = ai; tai != NULL && nfds < 4; tai = tai->ai_next) {
+ int tru = 1;
- memset(&addr, 0, sizeof(addr));
- addr.sin6_family = AF_INET6;
- addr.sin6_addr = in6addr_any;
- addr.sin6_port = htons(KPASSWD_PORT);
+ pfds[nfds].fd = socket( tai->ai_family,
+ tai->ai_socktype,
+ tai->ai_protocol);
+ if (pfds[nfds].fd == -1) {
+ syslog(LOG_ERR, "Unable to create socket (%d)", nfds);
+ exit(1);
+ }
+ pfds[nfds].events = POLLIN;
+ ret = setsockopt(pfds[nfds].fd, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&tru, sizeof(tru));
- ret = bind(udp_s, (struct sockaddr *)&addr, sizeof(addr));
- if (ret == -1) {
- syslog(LOG_ERR,
- "Unable to bind the UDP kpasswd port (%d) %s",
- errno, strerror(errno));
- close(tcp_s);
- close(udp_s);
- exit(3);
- }
- ret = listen(tcp_s, 5);
- if (ret == -1) {
- syslog(LOG_ERR,
- "Unable to listen oin the TCP socket (%d) %s",
- errno, strerror(errno));
- close(tcp_s);
- close(udp_s);
- exit(4);
+ ret = bind(pfds[nfds].fd, tai->ai_addr, tai->ai_addrlen);
+ if (ret) {
+ if (errno != EADDRINUSE) {
+ syslog(LOG_ERR, "Unable to bind to socket");
+ exit(1);
+ }
+ /* if EADDRINUSE it means we are on a machine
+ * with a dual ipv4/ipv6 stack that does not
+ * allow to bind on both at the same time as the
+ * ipv6 bind already allows connections on ipv4
+ * Just ignore */
+ close(pfds[nfds].fd);
+ } else {
+ if (tai->ai_socktype == SOCK_STREAM) {
+ ret = listen(pfds[nfds].fd, SOMAXCONN);
+ if (ret) {
+ syslog(LOG_ERR, "Unable to listen to socket");
+ exit(1);
+ }
+ }
+ pfdtype[nfds] = tai->ai_socktype;
+ nfds++;
+ }
}
- /* now that sockets are set up, enter the select loop */
+ /* now that sockets are set up, enter the poll loop */
while (1) {
- struct timeval tv;
- int cstatus, cid;
- fd_set rfd;
+ int cstatus, cid, i;
- tv.tv_sec = 3;
- tv.tv_usec = 0;
-
- FD_ZERO(&rfd);
- FD_SET(udp_s, &rfd);
- FD_SET(tcp_s, &rfd);
-
- ret = select(udp_s+1, &rfd, NULL, NULL, &tv);
+ ret = poll(pfds, nfds, 3000);
switch(ret) {
case 0:
@@ -1057,19 +1010,16 @@ int main(int argc, char *argv[])
case -1:
if (errno != EINTR) {
syslog(LOG_ERR,
- "Unexpected error in select (%d) %s",
+ "Unexpected error in poll (%d) %s",
errno, strerror(errno));
exit(5);
}
break;
default:
- if (FD_ISSET(tcp_s, &rfd)) {
- handle_conn(tcp_s, KPASSWD_TCP);
- break;
- }
- if (FD_ISSET(udp_s, &rfd)) {
- handle_conn(udp_s, KPASSWD_UDP);
- break;
+ for (i = 0; i < nfds; i++) {
+ if (pfds[i].revents & POLLIN) {
+ handle_conn(pfds[i].fd, pfdtype[i]);
+ }
}
}