> -----Original Message----- > From: Ramesh Betham [mailto:[email protected]] > Sent: den 25 juni 2014 13:42 > To: Hans Feldt > Cc: [email protected] > Subject: Re: [devel] [PATCH 1 of 1] base: add utilities for sending, > receiving over a UNIX socket [#554] > > Ack. No major comments, except to fulfill the comments made with in the > patch. > > Say., > + int timeout = 10000; // TODO allow configuration? And [Hans] not sure why right now? We don't have the use case. Can be done later.
> + char grpmembuf[16384]; // can use sysconf(_SC_GETPW_R_SIZE_MAX) [Hans] the problem with sysconf is that it is not in LSB so we would get some complaints... Thanks, Hans > > Also can you please elaborate on the implementation scope of ticket #938 > for 4.5 release. > > Regards, > Ramesh. > > On 6/19/2014 3:58 PM, Hans Feldt wrote: > > osaf/libs/core/common/Makefile.am | 3 +- > > osaf/libs/core/common/include/Makefile.am | 3 +- > > osaf/libs/core/common/include/osaf_secutil.h | 83 +++++++ > > osaf/libs/core/common/osaf_secutil.c | 302 > > +++++++++++++++++++++++++++ > > 4 files changed, 389 insertions(+), 2 deletions(-) > > > > > > This patch add some infrastructure that can be used by other services > > to securely get credentials for a client. > > > > When initialized on the server side a tiny server thread is created > > that listen to a named connection oriented UNIX socket. For each incoming > > connection request it calls a user specified callback and handover > > file descriptor and peer credentials. > > > > A typical use case is for a library to create the MDS socket and then > > use the client side function to send the MDS address as a data messages. > > The client credentials can be stored on the server side and verified > > when needed. > > > > Note each received connection less message needs to be checked with the > > original received MDS address so no spoofing (handle hijacking) is > > happening. > > > > diff --git a/osaf/libs/core/common/Makefile.am > > b/osaf/libs/core/common/Makefile.am > > --- a/osaf/libs/core/common/Makefile.am > > +++ b/osaf/libs/core/common/Makefile.am > > @@ -39,4 +39,5 @@ libopensaf_common_la_SOURCES = \ > > saf_edu.c \ > > daemon.c \ > > osaf_unicode.c \ > > - saf_error.c > > + saf_error.c \ > > + osaf_secutil.c > > diff --git a/osaf/libs/core/common/include/Makefile.am > > b/osaf/libs/core/common/include/Makefile.am > > --- a/osaf/libs/core/common/include/Makefile.am > > +++ b/osaf/libs/core/common/include/Makefile.am > > @@ -34,4 +34,5 @@ noinst_HEADERS = \ > > osaf_unicode.h \ > > osaf_poll.h \ > > osaf_time.h \ > > - saf_error.h > > + saf_error.h \ > > + osaf_secutil.h > > diff --git a/osaf/libs/core/common/include/osaf_secutil.h > > b/osaf/libs/core/common/include/osaf_secutil.h > > new file mode 100644 > > --- /dev/null > > +++ b/osaf/libs/core/common/include/osaf_secutil.h > > @@ -0,0 +1,83 @@ > > +/* -*- OpenSAF -*- > > + * > > + * (C) Copyright 2014 The OpenSAF Foundation > > + * > > + * This program is distributed in the hope that it will be useful, but > > + * WITHOUT ANY WARRANTY; without even the implied warranty of > > MERCHANTABILITY > > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > > + * under the GNU Lesser General Public License Version 2.1, February 1999. > > + * The complete license can be accessed from the following location: > > + * http://opensource.org/licenses/lgpl-license.php > > + * See the Copying file included with the OpenSAF distribution for full > > + * licensing terms. > > + * > > + * Author(s): Ericsson AB > > + * > > + */ > > + > > +#ifndef OPENSAF_CORE_OSAF_SECUTIL_H_ > > +#define OPENSAF_CORE_OSAF_SECUTIL_H_ > > + > > +#define _GNU_SOURCE > > +#include <sys/socket.h> > > +#include <sys/un.h> > > + > > +#include <sys/types.h> > > +#include <ncsgl_defs.h> > > + > > +#ifdef __cplusplus > > +extern "C" { > > +#endif > > + > > +/** > > + * Connects with server via UNIX stream socket and send and receive message > > + * The function is typically used on the client side to register an MDS > > address > > + * with a server. > > + * > > + * @param path file system path to server UNIX stream socket > > + * @param req_buf ptr to buffer with data to be sent > > + * @param req_size size of data to send > > + * @param resp_buf ptr to buffer where to put received data > > + * @param resp_size size of received data > > + * @param timeout timeout to wait (same semantics as for poll timeout) > > + * > > + * @return on success length of received message, on failure negated errno, > > + * on timeout 0. > > + */ > > +int osaf_auth_server_connect(const char *path, > > + const void *req_buf, size_t req_size, void *resp_buf, size_t > > resp_size, > > + int timeout); > > + > > +/** > > + * Type for callback installed on server side > > + * > > + * @param fd socket file descriptor from where data is available > > + * @param client_cred credentials for peer > > + */ > > +typedef void (*client_auth_data_callback_t)(int fd, > > + const struct ucred > > *client_cred); > > + > > +/** > > + * Creates a new authentication server > > + * > > + * @param _pathname name to use for server socket > > + * @param callback callback to call when a client has connect and data is > > + * available on socket > > + */ > > +int osaf_auth_server_create(const char *_pathname, > > + client_auth_data_callback_t callback); > > + > > +/** > > + * Checks if user represented by uid is member of group > > + * > > + * @param uid > > + * @param groupname > > + * @return true if member > > + */ > > +bool osaf_user_is_member_of_group(uid_t uid, const char *groupname); > > + > > +#ifdef __cplusplus > > +} > > +#endif > > + > > +#endif /* OPENSAF_CORE_OSAF_SECUTIL_H_ */ > > diff --git a/osaf/libs/core/common/osaf_secutil.c > > b/osaf/libs/core/common/osaf_secutil.c > > new file mode 100644 > > --- /dev/null > > +++ b/osaf/libs/core/common/osaf_secutil.c > > @@ -0,0 +1,302 @@ > > +/* -*- OpenSAF -*- > > + * > > + * (C) Copyright 2014 The OpenSAF Foundation > > + * > > + * This program is distributed in the hope that it will be useful, but > > + * WITHOUT ANY WARRANTY; without even the implied warranty of > > MERCHANTABILITY > > + * or FITNESS FOR A PARTICULAR PURPOSE. This file and program are licensed > > + * under the GNU Lesser General Public License Version 2.1, February 1999. > > + * The complete license can be accessed from the following location: > > + * http://opensource.org/licenses/lgpl-license.php > > + * See the Copying file included with the OpenSAF distribution for full > > + * licensing terms. > > + * > > + * Author(s): Ericsson AB > > + * > > + */ > > + > > +/* > > + * This file contains infrastructure for sending, receiving over a UNIX > > socket > > + * This can be used by services to securely get credentials for a client. > > + * > > + * When initialized on the server side a tiny server thread is created > > + * that listen to a named connection oriented UNIX socket. For each > > incoming > > + * connection request it calls a user specified callback with file > > descriptor > > + * and peer credentials. > > + * > > + * A typical use case is for a library to create the MDS socket and then > > + * use the client side function to send the MDS address as a data message. > > + * The client credentials are stored on the server side and verified > > + * when needed. > > + */ > > + > > +#define _GNU_SOURCE > > +#include <stdlib.h> > > +#include <errno.h> > > +#include <unistd.h> > > +#include <sys/types.h> > > +#include <sys/socket.h> > > +#include <sys/un.h> > > +#include <sys/stat.h> > > +#include <pwd.h> > > +#include <grp.h> > > +#include <pthread.h> > > +#include <osaf_poll.h> > > + > > +#include "logtrace.h" > > +#include "include/osaf_secutil.h" > > + > > +// singleton (one per process) callback > > +static client_auth_data_callback_t client_auth_data_callback; > > + > > +/** > > + * accepts a new client and get its credentials, call the handler > > + * @param servsock > > + */ > > +static void handle_new_connection(int servsock) > > +{ > > + int client_fd; > > + struct sockaddr_un remote; > > + socklen_t addrlen = sizeof(remote); > > + struct ucred client_cred; > > + socklen_t ucred_length = sizeof(struct ucred); > > + > > + TRACE_ENTER(); > > + > > + // a client wants to connect, accept > > + if ((client_fd = accept(servsock, (struct sockaddr *)&remote, > > &addrlen)) == -1) { > > + LOG_ER("accept failed - %s", strerror(errno)); > > + goto done; > > + } > > + > > + // get client credentials > > + if (getsockopt(client_fd, SOL_SOCKET, SO_PEERCRED, &client_cred, > > &ucred_length) == -1) { > > + LOG_WA("could not get credentials from socket - %s", > > strerror(errno)); > > + goto done; > > + } > > + > > + // wait a while for data to get available on socket > > + struct pollfd fds; > > + fds.fd = client_fd; > > + fds.events = POLLIN; > > + int timeout = 10000; // TODO allow configuration? > > + int res = osaf_poll(&fds, 1, timeout); > > + > > + if (res == 0) { > > + TRACE_3("poll timeout %d", timeout); > > + // timeout > > + goto done; > > + } > > + > > + // callback with file descriptor and credentials > > + if (fds.revents & POLLIN) { > > + client_auth_data_callback(client_fd, &client_cred); > > + } else > > + osafassert(0); // TODO > > + > > +done: > > + // the socket is short lived, close it > > + if (client_fd > 0) > > + close(client_fd); > > + > > + TRACE_LEAVE(); > > +} > > + > > +/** > > + * Single time used helper function to the socket server > > + */ > > +static int server_sock_create(const char *pathname) > > +{ > > + int server_sockfd; > > + socklen_t addrlen; > > + struct sockaddr_un unaddr; > > + > > + if ((server_sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { > > + LOG_ER("%s: socket failed - %s", __FUNCTION__, strerror(errno)); > > + return -1; > > + } > > + > > + unlink(pathname); > > + > > + unaddr.sun_family = AF_UNIX; > > + strcpy(unaddr.sun_path, pathname); > > + addrlen = strlen(unaddr.sun_path) + sizeof(unaddr.sun_family); > > + if (bind(server_sockfd, (struct sockaddr *)&unaddr, addrlen) == -1) { > > + LOG_ER("%s: bind failed - %s", __FUNCTION__, strerror(errno)); > > + return -1; > > + } > > + > > + /* Connecting to the socket object requires read/write permission. */ > > + if (chmod(pathname, 0777) == -1) { > > + LOG_ER("%s: chmod failed - %s", __FUNCTION__, strerror(errno)); > > + return -1; > > + } > > + > > + if (listen(server_sockfd, 5) == -1) { > > + LOG_ER("%s: listen failed - %s", __FUNCTION__, strerror(errno)); > > + return -1; > > + } > > + > > + return server_sockfd; > > +} > > + > > +/** > > + * main for authentication server > > + */ > > +static void *auth_server_main(void *_pathname) > > +{ > > + const char *pathname = _pathname; > > + int fd = server_sock_create(pathname); > > + struct pollfd fds[1]; > > + > > + TRACE_ENTER(); > > + > > + fds[0].fd = fd; > > + fds[0].events = POLLIN; > > + > > + while (1) { > > + (void) osaf_poll(fds, 1, -1); > > + > > + if (fds[0].revents & POLLIN) { > > + handle_new_connection(fd); > > + } > > + } > > + > > + osafassert(0); > > + return 0; > > +} > > + > > +/*************** public interface follows*************************** */ > > + > > +int osaf_auth_server_create(const char *_pathname, > > + client_auth_data_callback_t callback) > > +{ > > + pthread_t thread; > > + pthread_attr_t attr; > > + char *pathname = strdup(_pathname); > > + > > + TRACE_ENTER(); > > + > > + // callback is singleton > > + osafassert(client_auth_data_callback == NULL); > > + > > + // save provided callback for later use when clients connect > > + client_auth_data_callback = callback; > > + > > + osafassert(pthread_attr_init(&attr) == 0); > > + osafassert(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) > > == 0); > > + > > + if (pthread_create(&thread, &attr, auth_server_main, pathname) != 0) { > > + LOG_ER("pthread_create FAILED: %s", strerror(errno)); > > + return -1; > > + } > > + > > + osafassert(pthread_attr_destroy(&attr) == 0); > > + > > + TRACE_LEAVE(); > > + return 0; > > +} > > + > > +/* used by server, logging is OK */ > > +bool osaf_user_is_member_of_group(uid_t uid, const char *groupname) > > +{ > > + int res; > > + char **member; > > + struct group grp; > > + struct group *result; > > + char grpmembuf[16384]; // can use sysconf(_SC_GETPW_R_SIZE_MAX) > > + > > + // get group file entry with list of member user names > > + res = getgrnam_r(groupname, &grp, grpmembuf, sizeof(grpmembuf), > > &result); > > + if (res > 0 || result == NULL) { > > + LOG_ER("%s: get group file entry failed for '%s' - %s", > > + __FUNCTION__, groupname, strerror(res)); > > + return false; > > + } > > + > > + // get user name > > + errno = 0; > > + struct passwd *client_pwd = getpwuid(uid); > > + if (client_pwd == NULL) { > > + LOG_WA("%s: get password file entry failed for uid=%d - %s", > > + __FUNCTION__, uid, strerror(errno)); > > + return false; > > + } > > + > > + /* loop list of usernames that are members of the group trying find a > > + * match with the specified user name */ > > + for (member = grp.gr_mem; *member != NULL; member++) { > > + if (strcmp(client_pwd->pw_name, *member) == 0) > > + break; > > + } > > + > > + if (*member != NULL) > > + return true; > > + else > > + return false; > > +} > > + > > +/* used in libraries, do not log. Only trace */ > > +int osaf_auth_server_connect(const char *path, const void *req_buf, > > + size_t req_size, void *resp_buf, size_t > > resp_size, > > + int timeout) > > +{ > > + int sock_fd, len; > > + struct sockaddr_un remote; > > + > > + TRACE_ENTER(); > > + > > + if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { > > + TRACE_3("socket failed - %s", strerror(errno)); > > + return -errno; > > + } > > + > > + remote.sun_family = AF_UNIX; > > + strcpy(remote.sun_path, path); > > + len = strlen(remote.sun_path) + sizeof(remote.sun_family); > > + if (connect(sock_fd, (struct sockaddr *)&remote, len) == -1) { > > + TRACE_3("connect to '%s' failed - %s", remote.sun_path, > > strerror(errno)); > > + len = -errno; > > + goto done; > > + } > > + > > + if (send(sock_fd, req_buf, req_size, 0) == -1) { > > + TRACE_3("send failed - %s", strerror(errno)); > > + len = -errno; > > + goto done; > > + } > > + > > + struct pollfd fds; > > + fds.fd = sock_fd; > > + fds.events = POLLIN; > > + > > + int res = osaf_poll(&fds, 1, timeout); > > + > > + if (res == 0) { > > + TRACE_3("poll timeout %d", timeout); > > + len = 0; > > + goto done; > > + } else if (res == 1) { > > + if (fds.revents & POLLIN) { > > + if ((len = recv(sock_fd, resp_buf, resp_size, 0)) == > > -1) { > > + TRACE_3("recv failed - %s", strerror(errno)); > > + len = -errno; > > + goto done; > > + } > > + } else { > > + TRACE_3("revents:%x", fds.revents); > > + len = -1; > > + goto done; > > + } > > + } else { > > + // osaf_poll has failed (which it shouldn't) > > + osafassert(0); > > + } > > + > > +done: > > + (void)close(sock_fd); // ignore error, server side normally closes it > > + > > + TRACE_LEAVE(); > > + return len; > > +} > > + > > > ------------------------------------------------------------------------------ > Open source business process management suite built on Java and Eclipse > Turn processes into business applications with Bonita BPM Community Edition > Quickly connect people, data, and systems into organized workflows > Winner of BOSSIE, CODIE, OW2 and Gartner awards > http://p.sf.net/sfu/Bonitasoft > _______________________________________________ > Opensaf-devel mailing list > [email protected] > https://lists.sourceforge.net/lists/listinfo/opensaf-devel ------------------------------------------------------------------------------ _______________________________________________ Opensaf-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/opensaf-devel
