X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ffrontend%2Fsock.c;h=1827886628ae6236e991251e6b1d8ecd9a5ab34c;hb=6ae8a44475eef39fa376a657df581a52b5472697;hp=dd0afa907fbcf5564a05d187db28d9eca3c0ea0b;hpb=fda0b2679c4d50d2077a593fdc2b73b521524521;p=sysdb.git diff --git a/src/frontend/sock.c b/src/frontend/sock.c index dd0afa9..1827886 100644 --- a/src/frontend/sock.c +++ b/src/frontend/sock.c @@ -53,10 +53,20 @@ #include #include #include +#include #include -#include +#ifdef HAVE_UCRED_H +# include +#endif +#ifdef HAVE_SYS_UCRED_H +# include +#endif + +#include +#include +#include #include /* @@ -68,14 +78,15 @@ typedef struct { int type; int sock_fd; + int (*setup)(sdb_conn_t *, void *); } listener_t; typedef struct { int type; const char *prefix; - int (*opener)(listener_t *); - void (*closer)(listener_t *); + int (*open)(listener_t *); + void (*close)(listener_t *); } fe_listener_impl_t; struct sdb_fe_socket { @@ -94,9 +105,48 @@ struct sdb_fe_socket { */ static int -open_unix_sock(listener_t *listener) +setup_unixsock(sdb_conn_t *conn, void __attribute__((unused)) *user_data) +{ + uid_t uid; + + struct passwd pw_entry; + struct passwd *result = NULL; + char buf[1024]; + +#ifdef SO_PEERCRED + struct ucred cred; + socklen_t len = sizeof(cred); + + if (getsockopt(conn->fd, SOL_SOCKET, SO_PEERCRED, &cred, &len) + || (len != sizeof(cred))) { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "frontend: Failed to determine peer for " + "connection conn#%i: %s", conn->fd, + sdb_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + uid = cred.uid; +#else /* SO_PEERCRED */ + sdb_log(SDB_LOG_ERR, "frontend: Failed to determine peer for " + "connection conn#%i: operation not supported", conn->fd); + return -1; +#endif + + memset(&pw_entry, 0, sizeof(pw_entry)); + if (getpwuid_r(uid, &pw_entry, buf, sizeof(buf), &result) || (! result) + || (! (conn->username = strdup(result->pw_name)))) { + char errbuf[1024]; + sdb_log(SDB_LOG_ERR, "frontend: Failed to determine peer for " + "connection conn#%i: %s", conn->fd, + sdb_strerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + return 0; +} /* setup_unixsock */ + +static int +open_unixsock(listener_t *listener) { - const char *addr; char *addr_copy; char *base_dir; struct sockaddr_un sa; @@ -110,16 +160,11 @@ open_unix_sock(listener_t *listener) return -1; } - if (*listener->address == '/') - addr = listener->address; - else - addr = listener->address + strlen("unix:"); - memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_UNIX; - strncpy(sa.sun_path, addr, sizeof(sa.sun_path)); + strncpy(sa.sun_path, listener->address, sizeof(sa.sun_path)); - addr_copy = strdup(addr); + addr_copy = strdup(listener->address); if (! addr_copy) { char errbuf[1024]; sdb_log(SDB_LOG_ERR, "frontend: strdup failed: %s", @@ -138,10 +183,10 @@ open_unix_sock(listener_t *listener) } free(addr_copy); - if (unlink(addr) && (errno != ENOENT)) { + if (unlink(listener->address) && (errno != ENOENT)) { char errbuf[1024]; sdb_log(SDB_LOG_WARNING, "frontend: Failed to remove stale UNIX " - "socket %s: %s", listener->address + strlen("unix:"), + "socket %s: %s", listener->address, sdb_strerror(errno, errbuf, sizeof(errbuf))); } @@ -152,29 +197,90 @@ open_unix_sock(listener_t *listener) listener->address, sdb_strerror(errno, buf, sizeof(buf))); return -1; } + + listener->setup = setup_unixsock; return 0; -} /* open_unix_sock */ +} /* open_unixsock */ static void -close_unix_sock(listener_t *listener) +close_unixsock(listener_t *listener) { - const char *addr; assert(listener); if (! listener->address) return; - if (*listener->address == '/') - addr = listener->address; - else - addr = listener->address + strlen("unix:"); - if (listener->sock_fd >= 0) close(listener->sock_fd); listener->sock_fd = -1; - unlink(addr); -} /* close_unix_sock */ + unlink(listener->address); +} /* close_unixsock */ + +static int +open_tcp(listener_t *listener) +{ + struct addrinfo *ai, *ai_list = NULL; + int status; + + assert(listener); + + if ((status = sdb_resolve(SDB_NET_TCP, listener->address, &ai_list))) { + sdb_log(SDB_LOG_ERR, "frontend: Failed to resolve '%s': %s", + listener->address, gai_strerror(status)); + return -1; + } + + for (ai = ai_list; ai != NULL; ai = ai->ai_next) { + char errbuf[1024]; + int reuse = 1; + + listener->sock_fd = socket(ai->ai_family, + ai->ai_socktype, ai->ai_protocol); + if (listener->sock_fd < 0) { + sdb_log(SDB_LOG_ERR, "frontend: Failed to open socket for %s: %s", + listener->address, + sdb_strerror(errno, errbuf, sizeof(errbuf))); + continue; + } + + if (setsockopt(listener->sock_fd, SOL_SOCKET, SO_REUSEADDR, + &reuse, sizeof(reuse)) < 0) { + sdb_log(SDB_LOG_ERR, "frontend: Failed to set socket option: %s", + sdb_strerror(errno, errbuf, sizeof(errbuf))); + close(listener->sock_fd); + listener->sock_fd = -1; + continue; + } + + if (bind(listener->sock_fd, ai->ai_addr, ai->ai_addrlen) < 0) { + char host[1024], port[32]; + getnameinfo(ai->ai_addr, ai->ai_addrlen, host, sizeof(host), + port, sizeof(port), NI_NUMERICHOST | NI_NUMERICSERV); + sdb_log(SDB_LOG_ERR, "frontend: Failed to bind to %s:%s: %s", + host, port, sdb_strerror(errno, errbuf, sizeof(errbuf))); + close(listener->sock_fd); + listener->sock_fd = -1; + continue; + } + break; + } + freeaddrinfo(ai_list); + + if (listener->sock_fd < 0) + return -1; + return 0; +} /* open_tcp */ + +static void +close_tcp(listener_t *listener) +{ + assert(listener); + + if (listener->sock_fd >= 0) + close(listener->sock_fd); + listener->sock_fd = -1; +} /* close_tcp */ /* * private variables @@ -183,10 +289,12 @@ close_unix_sock(listener_t *listener) /* the enum has to be sorted the same as the implementations array * to ensure that the type may be used as index into the array */ enum { - LISTENER_UNIXSOCK = 0, /* this is the default */ + LISTENER_TCP = 0, /* this is the default */ + LISTENER_UNIXSOCK, }; static fe_listener_impl_t listener_impls[] = { - { LISTENER_UNIXSOCK, "unix", open_unix_sock, close_unix_sock }, + { LISTENER_TCP, "tcp", open_tcp, close_tcp }, + { LISTENER_UNIXSOCK, "unix", open_unixsock, close_unixsock }, }; /* @@ -200,7 +308,7 @@ listener_listen(listener_t *listener) /* try to reopen */ if (listener->sock_fd < 0) - if (listener_impls[listener->type].opener(listener)) + if (listener_impls[listener->type].open(listener)) return -1; assert(listener->sock_fd >= 0); @@ -218,8 +326,8 @@ listener_close(listener_t *listener) { assert(listener); - if (listener_impls[listener->type].closer) - listener_impls[listener->type].closer(listener); + if (listener_impls[listener->type].close) + listener_impls[listener->type].close(listener); if (listener->sock_fd >= 0) close(listener->sock_fd); @@ -233,6 +341,8 @@ get_type(const char *address) size_t len; size_t i; + if (*address == '/') + return LISTENER_UNIXSOCK; sep = strchr(address, (int)':'); if (! sep) return listener_impls[0].type; @@ -268,6 +378,7 @@ static listener_t * listener_create(sdb_fe_socket_t *sock, const char *address) { listener_t *listener; + size_t len; int type; type = get_type(address); @@ -289,6 +400,11 @@ listener_create(sdb_fe_socket_t *sock, const char *address) sock->listeners = listener; listener = sock->listeners + sock->listeners_num; + len = strlen(listener_impls[type].prefix); + if ((! strncmp(address, listener_impls[type].prefix, len)) + && (address[len] == ':')) + address += strlen(listener_impls[type].prefix) + 1; + listener->sock_fd = -1; listener->address = strdup(address); if (! listener->address) { @@ -299,8 +415,9 @@ listener_create(sdb_fe_socket_t *sock, const char *address) return NULL; } listener->type = type; + listener->setup = NULL; - if (listener_impls[type].opener(listener)) { + if (listener_impls[type].open(listener)) { /* prints error */ listener_destroy(listener); return NULL; @@ -366,7 +483,7 @@ connection_handler(void *data) continue; } - status = (int)sdb_connection_read(conn); + status = (int)sdb_connection_handle(conn); if (status <= 0) { /* error or EOF -> close connection */ sdb_object_deref(SDB_OBJ(conn)); @@ -392,7 +509,8 @@ connection_accept(sdb_fe_socket_t *sock, listener_t *listener) sdb_object_t *obj; int status; - obj = SDB_OBJ(sdb_connection_accept(listener->sock_fd)); + obj = SDB_OBJ(sdb_connection_accept(listener->sock_fd, + listener->setup, NULL)); if (! obj) return -1; @@ -543,8 +661,8 @@ sdb_fe_sock_listen_and_serve(sdb_fe_socket_t *sock, sdb_fe_loop_t *loop) return -1; } - sdb_log(SDB_LOG_INFO, "frontend: Starting %d connection " - "handler thread%s managing %d listener%s", + sdb_log(SDB_LOG_INFO, "frontend: Starting %zu connection " + "handler thread%s managing %zu listener%s", loop->num_threads, loop->num_threads == 1 ? "" : "s", sock->listeners_num, sock->listeners_num == 1 ? "" : "s");