* The backend socket has now support of credentials of peer clients
* Added: CLICON_NACM_CREDENTIALS and CLICON_NACM_RECOVERY_USER
This commit is contained in:
parent
77b491c568
commit
279614d64f
33 changed files with 951 additions and 145 deletions
|
|
@ -145,7 +145,6 @@ backend_client_rm(clicon_handle h,
|
|||
}
|
||||
ce_prev = &c->ce_next;
|
||||
}
|
||||
|
||||
return backend_client_delete(h, ce); /* actually purge it */
|
||||
}
|
||||
|
||||
|
|
@ -1240,6 +1239,68 @@ from_client_ping(clicon_handle h,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Verify nacm user with peer uid credentials
|
||||
* @param[in] mode Peer credential mode: none, exact or except
|
||||
* @param[in] peername Peer username if any
|
||||
* @param[in] username username received in XML (eg for NACM)
|
||||
* @param[out] cbret Set with netconf error message if ret == 0
|
||||
* @retval -1 Error
|
||||
* @retval 0 Not verified (cbret set)
|
||||
* @retval 1 Verified
|
||||
* Credentials OK if both NACM user and peer useri s defined AND one of the
|
||||
* following is true:
|
||||
* - peer user is same as NACM user
|
||||
* - peer user is root (can be any NACM user)
|
||||
* - peer user is www (can be any NACM user)
|
||||
*/
|
||||
static int
|
||||
verify_nacm_user(enum nacm_credentials_t mode,
|
||||
char *peername,
|
||||
char *nacmname,
|
||||
cbuf *cbret)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cbmsg = NULL;
|
||||
|
||||
if (mode == NC_NONE)
|
||||
return 1;
|
||||
if (peername == NULL){
|
||||
if (netconf_access_denied(cbret, "application", "No peer user credentials available") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (nacmname == NULL){
|
||||
if (netconf_access_denied(cbret, "application", "No NACM available") < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
if (mode == NC_EXCEPT){
|
||||
if (strcmp(peername, "root") == 0)
|
||||
goto ok;
|
||||
if (strcmp(peername, WWWUSER) == 0)
|
||||
goto ok;
|
||||
}
|
||||
if (strcmp(peername, nacmname) != 0){
|
||||
if ((cbmsg = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cbmsg, "User %s credential not matching NACM user %s", peername, nacmname);
|
||||
if (netconf_access_denied(cbret, "application", cbuf_get(cbmsg)) < 0)
|
||||
goto done;
|
||||
goto fail;
|
||||
}
|
||||
ok:
|
||||
retval = 1;
|
||||
done:
|
||||
if (cbmsg)
|
||||
cbuf_free(cbmsg);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! An internal clicon message has arrived from a client. Receive and dispatch.
|
||||
* @param[in] h Clicon handle
|
||||
* @param[in] s Socket where message arrived. read from this.
|
||||
|
|
@ -1322,6 +1383,12 @@ from_client_msg(clicon_handle h,
|
|||
if ((ret = nacm_access_pre(h, username, NACM_RPC, &xnacm)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){ /* Do NACM validation */
|
||||
enum nacm_credentials_t mode;
|
||||
mode = clicon_nacm_credentials(h);
|
||||
if ((ret = verify_nacm_user(mode, ce->ce_username, username, cbret)) < 0)
|
||||
goto done;
|
||||
if (ret == 0) /* credentials fail */
|
||||
goto reply;
|
||||
/* NACM rpc operation exec validation */
|
||||
if ((ret = nacm_rpc(rpc, module, username, xnacm, cbret)) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -43,15 +43,15 @@
|
|||
* Keep state about every connected client.
|
||||
*/
|
||||
struct client_entry{
|
||||
struct client_entry *ce_next; /* The clients linked list */
|
||||
struct sockaddr ce_addr; /* The clients (UNIX domain) address */
|
||||
int ce_s; /* stream socket to client */
|
||||
int ce_nr; /* Client number (for dbg/tracing) */
|
||||
int ce_stat_in; /* Nr of received msgs from client */
|
||||
int ce_stat_out;/* Nr of sent msgs to client */
|
||||
int ce_pid; /* Process id */
|
||||
int ce_uid; /* User id of calling process */
|
||||
clicon_handle ce_handle; /* clicon config handle (all clients have same?) */
|
||||
struct client_entry *ce_next; /* The clients linked list */
|
||||
struct sockaddr ce_addr; /* The clients (UNIX domain) address */
|
||||
int ce_s; /* stream socket to client */
|
||||
int ce_nr; /* Client number (for dbg/tracing) */
|
||||
int ce_stat_in; /* Nr of received msgs from client */
|
||||
int ce_stat_out;/* Nr of sent msgs to client */
|
||||
int ce_pid; /* Peer Process id */
|
||||
char *ce_username;/* Translated from peer user cred */
|
||||
clicon_handle ce_handle; /* clicon config handle (all clients have same?) */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -51,13 +51,12 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/param.h>
|
||||
#ifdef HAVE_SYS_UCRED_H
|
||||
#include <sys/types.h>
|
||||
#include <sys/ucred.h>
|
||||
#endif
|
||||
#define __USE_GNU /* for ucred */
|
||||
#define _GNU_SOURCE /* for ucred */
|
||||
#include <sys/socket.h>
|
||||
#ifdef HAVE_LOCAL_PEERCRED
|
||||
#include <sys/ucred.h>
|
||||
#endif
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
|
|
@ -226,63 +225,65 @@ backend_accept_client(int fd,
|
|||
int retval = -1;
|
||||
clicon_handle h = (clicon_handle)arg;
|
||||
int s;
|
||||
struct sockaddr_un from;
|
||||
struct sockaddr from = {0,};
|
||||
socklen_t len;
|
||||
struct client_entry *ce;
|
||||
#ifdef DONT_WORK /* XXX HAVE_SYS_UCRED_H */
|
||||
struct xucred credentials; /* FreeBSD. */
|
||||
socklen_t clen;
|
||||
#elif defined(SO_PEERCRED)
|
||||
struct ucred credentials; /* Linux. */
|
||||
socklen_t clen;
|
||||
#endif
|
||||
char *config_group;
|
||||
struct group *gr;
|
||||
char *mem;
|
||||
int i;
|
||||
char *name = NULL;
|
||||
#ifdef HAVE_SO_PEERCRED
|
||||
socklen_t clen;
|
||||
struct ucred cr = {0,}; /* Linux. */
|
||||
#elif defined(HAVE_GETPEEREID)
|
||||
uid_t euid;
|
||||
uid_t guid;
|
||||
#endif
|
||||
|
||||
clicon_debug(2, "%s", __FUNCTION__);
|
||||
len = sizeof(from);
|
||||
if ((s = accept(fd, (struct sockaddr*)&from, &len)) < 0){
|
||||
if ((s = accept(fd, &from, &len)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "accept");
|
||||
goto done;
|
||||
}
|
||||
#if defined(SO_PEERCRED)
|
||||
/* fill in the user data structure */
|
||||
clen = sizeof(credentials);
|
||||
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED/* XXX finns ej i freebsd*/, &credentials, &clen)){
|
||||
clicon_err(OE_UNIX, errno, "getsockopt");
|
||||
if ((ce = backend_client_add(h, &from)) == NULL)
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
if ((ce = backend_client_add(h, (struct sockaddr*)&from)) == NULL)
|
||||
goto done;
|
||||
#if defined(SO_PEERCRED)
|
||||
ce->ce_pid = credentials.pid;
|
||||
ce->ce_uid = credentials.uid;
|
||||
#endif
|
||||
ce->ce_handle = h;
|
||||
|
||||
/* check credentials of caller (not properly implemented yet) */
|
||||
if ((config_group = clicon_sock_group(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "clicon_sock_group option not set");
|
||||
goto done;
|
||||
}
|
||||
if ((gr = getgrnam(config_group)) != NULL){
|
||||
i = 0; /* one of mem should correspond to ce->ce_uid */
|
||||
while ((mem = gr->gr_mem[i++]) != NULL)
|
||||
;
|
||||
}
|
||||
|
||||
#if 0
|
||||
{ /* XXX */
|
||||
int ii;
|
||||
struct client_entry *c;
|
||||
for (c = ce_list, ii=0; c; c = c->ce_next, ii++);
|
||||
clicon_debug(1, "Open client socket (nr:%d pid:%d [Total: %d])",
|
||||
ce->ce_nr, ce->ce_pid, ii);
|
||||
}
|
||||
/*
|
||||
* Get credentials of connected peer - only for unix socket
|
||||
*/
|
||||
switch (from.sa_family){
|
||||
case AF_UNIX:
|
||||
#if defined(HAVE_SO_PEERCRED)
|
||||
clen = sizeof(cr);
|
||||
if(getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &clen) < 0){
|
||||
clicon_err(OE_UNIX, errno, "getsockopt");
|
||||
goto done;
|
||||
}
|
||||
ce->ce_pid = cr.pid; /* XXX no use session-id */
|
||||
if (uid2name(cr.uid, &name) < 0)
|
||||
goto done;
|
||||
#elif defined(HAVE_GETPEEREID)
|
||||
if (getpeereid(s, &euid, &guid) < 0)
|
||||
goto done;
|
||||
if (uid2name(euid, &name) < 0)
|
||||
goto done;
|
||||
#else
|
||||
#error "Need getsockopt O_PEERCRED or getpeereid for unix socket peer cred"
|
||||
#endif
|
||||
if (name && (ce->ce_username = strdup(name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case AF_INET: /* XXX: HACK ce->ce_pid */
|
||||
ce->ce_pid = 0;
|
||||
for (i=0; i<len; i++)
|
||||
ce->ce_pid ^= from.sa_data[i];
|
||||
break;
|
||||
case AF_INET6:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ce->ce_s = s;
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ backend_client_add(clicon_handle h,
|
|||
return NULL;
|
||||
}
|
||||
memset(ce, 0, sizeof(*ce));
|
||||
ce->ce_nr = bh->bh_ce_nr++;
|
||||
ce->ce_nr = bh->bh_ce_nr++; /* Session-id ? */
|
||||
memcpy(&ce->ce_addr, addr, sizeof(*addr));
|
||||
ce->ce_next = bh->bh_ce_list;
|
||||
bh->bh_ce_list = ce;
|
||||
|
|
@ -177,6 +177,8 @@ backend_client_delete(clicon_handle h,
|
|||
for (c = *ce_prev; c; c = c->ce_next){
|
||||
if (c == ce){
|
||||
*ce_prev = c->ce_next;
|
||||
if (ce->ce_username)
|
||||
free(ce->ce_username);
|
||||
free(ce);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue