> -----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

Reply via email to