diff options
Diffstat (limited to 'proxy')
-rw-r--r-- | proxy/Makefile.am | 1 | ||||
-rw-r--r-- | proxy/src/gp_socket.c | 237 | ||||
-rw-r--r-- | proxy/src/gp_utils.h | 4 | ||||
-rw-r--r-- | proxy/src/gssproxy.c | 6 |
4 files changed, 248 insertions, 0 deletions
diff --git a/proxy/Makefile.am b/proxy/Makefile.am index 8e4ede5..34caffb 100644 --- a/proxy/Makefile.am +++ b/proxy/Makefile.am @@ -84,6 +84,7 @@ dist_noinst_HEADERS = #################### gssproxy_SOURCES = \ src/gp_init.c \ + src/gp_socket.c \ src/gssproxy.c gssproxy_LDADD = \ $(GSS_PROXY_LIBS) diff --git a/proxy/src/gp_socket.c b/proxy/src/gp_socket.c new file mode 100644 index 0000000..a6f17c1 --- /dev/null +++ b/proxy/src/gp_socket.c @@ -0,0 +1,237 @@ +/* + GSS-PROXY + + Copyright (C) 2011 Red Hat, Inc. + Copyright (C) 2011 Simo Sorce <simo.sorce@redhat.com> + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. +*/ + +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/un.h> +#include <syslog.h> +#include <errno.h> +#include "gp_utils.h" + +struct unix_sock_conn { + + struct sockaddr_un sock_addr; + socklen_t sock_addr_len; + +#ifdef HAVE_UCRED + struct ucred creds; +#endif +}; + + + +static int set_status_flags(int fd, int flags) +{ + int cur; + int ret; + + cur = fcntl(fd, F_GETFL, 0); + cur |= flags; + ret = fcntl(fd, F_SETFL, cur); + if (ret == -1) { + return errno; + } + return 0; +} + +static int set_fd_flags(int fd, int flags) +{ + int cur; + int ret; + + cur = fcntl(fd, F_GETFD, 0); + cur |= flags; + ret = fcntl(fd, F_SETFD, cur); + if (ret == -1) { + return errno; + } + return 0; +} + +int init_unix_socket(const char *file_name) +{ + struct sockaddr_un addr = {0}; + mode_t old_mode; + int ret = 0; + int fd = -1; + + /* can't bind if an old socket is around */ + unlink(file_name); + + /* socket should be r/w by anyone */ + old_mode = umask(0111); + + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, file_name, sizeof(addr.sun_path)-1); + addr.sun_path[sizeof(addr.sun_path)-1] = '\0'; + + fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd == -1) { + ret = errno; + goto done; + } + + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret == -1) { + ret = errno; + goto done; + } + + ret = listen(fd, 10); + if (ret == -1) { + ret = errno; + goto done; + } + + ret = set_status_flags(fd, O_NONBLOCK); + if (ret != 0) { + goto done; + } + + ret = set_fd_flags(fd, FD_CLOEXEC); + if (ret != 0) { + goto done; + } + +done: + if (ret) { + syslog(LOG_ERR, "Failed to create Unix Socket! (%d:%s)", + ret, strerror(ret)); + if (fd != -1) { + close(fd); + fd = -1; + } + } + umask(old_mode); + return fd; +} + +/* TODO: use getpeercon for SeLinux context */ + +static int get_peercred(int fd, struct unix_sock_conn *conn) +{ +#ifdef HAVE_UCRED + socklen_t len; + int ret; + + len = sizeof(struct ucred); + ret = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &conn->creds, &len); + if (ret == -1) { + return errno; + } + if (len != sizeof(struct ucred)) { + return EIO; + } +#endif + return 0; +} + +static void free_unix_sock_conn(verto_ctx *vctx, verto_ev *ev) +{ + struct unix_sock_conn *conn; + + conn = verto_get_private(ev); + + free(conn); +} + +void client_sock_conn(verto_ctx *vctx, verto_ev *ev) +{ + int fd; + + fd = verto_get_fd(ev); + + syslog(LOG_ERR, "Ok you got here!"); + + verto_del(ev); + close(fd); +} + +void accept_sock_conn(verto_ctx *vctx, verto_ev *ev) +{ + struct unix_sock_conn *conn = NULL; + verto_ev *nev; + int vflags; + int listen_fd; + int fd = -1; + int ret; + + conn = malloc(sizeof(struct unix_sock_conn)); + if (!conn) { + ret = ENOMEM; + goto done; + } + + listen_fd = verto_get_fd(ev); + fd = accept(listen_fd, + (struct sockaddr *)&conn->sock_addr, + &conn->sock_addr_len); + if (fd == -1) { + ret = errno; + if (ret == EINTR) { + /* let the event loop retry later */ + return; + } + goto done; + } + + ret = set_status_flags(fd, O_NONBLOCK); + if (ret) { + goto done; + } + + ret = set_fd_flags(fd, FD_CLOEXEC); + if (ret) { + goto done; + } + + ret = get_peercred(fd, conn); + if (ret) { + goto done; + } + + vflags = VERTO_EV_FLAG_PERSIST | VERTO_EV_FLAG_IO_READ; + nev = verto_add_io(vctx, vflags, client_sock_conn, fd); + if (!nev) { + ret = ENOMEM; + goto done; + } + verto_set_private(nev, conn, free_unix_sock_conn); + +done: + if (ret) { + syslog(LOG_WARNING, "Error connecting client: (%d:%s)", + ret, strerror(ret)); + if (fd != -1) { + close(fd); + } + free(conn); + } +} + diff --git a/proxy/src/gp_utils.h b/proxy/src/gp_utils.h index 51d62e7..aed9362 100644 --- a/proxy/src/gp_utils.h +++ b/proxy/src/gp_utils.h @@ -36,4 +36,8 @@ void init_server(void); void fini_server(void); verto_ctx *init_event_loop(void); +/* from gp_socket.c */ +int init_unix_socket(const char *file_name); +void accept_sock_conn(verto_ctx *vctx, verto_ev *ev); + #endif /* _SRV_UTILS_H_ */ diff --git a/proxy/src/gssproxy.c b/proxy/src/gssproxy.c index d128d2b..c46edcd 100644 --- a/proxy/src/gssproxy.c +++ b/proxy/src/gssproxy.c @@ -101,6 +101,12 @@ int main(int argc, const char *argv[]) return 1; } + vflags = VERTO_EV_FLAG_PERSIST | VERTO_EV_FLAG_IO_READ; + ev = verto_add_io(vctx, vflags, accept_sock_conn, fd); + if (!ev) { + return 1; + } + verto_run(vctx); fini_server(); |