nfs: Add RPCv2 service

Signed-off-by: Shehjar Tikoo <shehjart@gluster.com>
Signed-off-by: Anand V. Avati <avati@dev.gluster.com>

BUG: 399 (NFS translator with Mount v3 and NFS v3 support)
URL: http://bugs.gluster.com/cgi-bin/bugzilla3/show_bug.cgi?id=399
This commit is contained in:
Shehjar Tikoo 2010-03-31 07:27:02 +00:00 committed by Anand V. Avati
parent eff83c8dae
commit 8b2949db0d
8 changed files with 4436 additions and 2 deletions

View File

@ -1,10 +1,10 @@
lib_LTLIBRARIES = librpcsvc.la
librpcsvc_la_LDFLAGS = -module -avoidversion
librpcsvc_la_SOURCES = msg-nfs3.c xdr-nfs3.c xdr-rpc.c
librpcsvc_la_SOURCES = msg-nfs3.c xdr-nfs3.c xdr-rpc.c auth-unix.c rpcsvc-auth.c rpcsvc.c auth-null.c rpc-socket.c
librpcsvc_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la
noinst_HEADERS = xdr-rpc.h msg-nfs3.h xdr-common.h xdr-nfs3.h
noinst_HEADERS = xdr-rpc.h msg-nfs3.h xdr-common.h xdr-nfs3.h rpc-socket.h rpcsvc.h
AM_CFLAGS = -fPIC -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -Wall -D$(GF_HOST_OS)\
-I$(top_srcdir)/libglusterfs/src -shared -nostartfiles $(GF_CFLAGS)

View File

@ -0,0 +1,71 @@
/*
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "rpcsvc.h"
#include "list.h"
#include "dict.h"
int
auth_null_request_init (rpcsvc_request_t *req, void *priv)
{
if (!req)
return -1;
memset (req->cred.authdata, 0, RPCSVC_MAX_AUTH_BYTES);
req->cred.datalen = 0;
memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES);
req->verf.datalen = 0;
return 0;
}
int auth_null_authenticate (rpcsvc_request_t *req, void *priv)
{
/* Always succeed. */
return RPCSVC_AUTH_ACCEPT;
}
rpcsvc_auth_ops_t auth_null_ops = {
.conn_init = NULL,
.request_init = auth_null_request_init,
.authenticate = auth_null_authenticate
};
rpcsvc_auth_t rpcsvc_auth_null = {
.authname = "AUTH_NULL",
.authnum = AUTH_NULL,
.authops = &auth_null_ops,
.authprivate = NULL
};
rpcsvc_auth_t *
rpcsvc_auth_null_init (rpcsvc_t *svc, dict_t *options)
{
return &rpcsvc_auth_null;
}

View File

@ -0,0 +1,91 @@
/*
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "rpcsvc.h"
#include "list.h"
#include "dict.h"
#include "xdr-rpc.h"
int
auth_unix_request_init (rpcsvc_request_t *req, void *priv)
{
if (!req)
return -1;
memset (req->verf.authdata, 0, RPCSVC_MAX_AUTH_BYTES);
req->verf.datalen = 0;
req->verf.flavour = AUTH_NULL;
return 0;
}
int auth_unix_authenticate (rpcsvc_request_t *req, void *priv)
{
int ret = RPCSVC_AUTH_REJECT;
struct authunix_parms aup;
char machname[MAX_MACHINE_NAME];
if (!req)
return ret;
ret = xdr_to_auth_unix_cred (req->cred.authdata, req->cred.datalen,
&aup, machname, req->auxgids);
if (ret == -1) {
ret = RPCSVC_AUTH_REJECT;
goto err;
}
req->uid = aup.aup_uid;
req->gid = aup.aup_gid;
req->auxgidcount = aup.aup_len;
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth Info: machine name: %s, uid: %d"
", gid: %d", machname, req->uid, req->gid);
ret = RPCSVC_AUTH_ACCEPT;
err:
return ret;
}
rpcsvc_auth_ops_t auth_unix_ops = {
.conn_init = NULL,
.request_init = auth_unix_request_init,
.authenticate = auth_unix_authenticate
};
rpcsvc_auth_t rpcsvc_auth_unix = {
.authname = "AUTH_UNIX",
.authnum = AUTH_UNIX,
.authops = &auth_unix_ops,
.authprivate = NULL
};
rpcsvc_auth_t *
rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options)
{
return &rpcsvc_auth_unix;
}

View File

@ -0,0 +1,358 @@
/*
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "rpc-socket.h"
#include "rpcsvc.h"
#include "dict.h"
#include "logging.h"
#include "byte-order.h"
#include "common-utils.h"
#include "compat-errno.h"
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
static int
rpcsvc_socket_server_get_local_socket (int addrfam, char *listenhost,
uint16_t listenport,
struct sockaddr *addr,
socklen_t *addr_len)
{
struct addrinfo hints, *res = 0;
char service[NI_MAXSERV];
int ret = -1;
memset (service, 0, sizeof (service));
sprintf (service, "%d", listenport);
memset (&hints, 0, sizeof (hints));
addr->sa_family = hints.ai_family = addrfam;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE;
ret = getaddrinfo(listenhost, service, &hints, &res);
if (ret != 0) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR,
"getaddrinfo failed for host %s, service %s (%s)",
listenhost, service, gai_strerror (ret));
ret = -1;
goto err;
}
memcpy (addr, res->ai_addr, res->ai_addrlen);
*addr_len = res->ai_addrlen;
freeaddrinfo (res);
ret = 0;
err:
return ret;
}
int
rpcsvc_socket_listen (int addrfam, char *listenhost, uint16_t listenport)
{
int sock = -1;
struct sockaddr_storage sockaddr;
socklen_t sockaddr_len;
int flags = 0;
int ret = -1;
int opt = 1;
ret = rpcsvc_socket_server_get_local_socket (addrfam, listenhost,
listenport,SA (&sockaddr),
&sockaddr_len);
if (ret == -1)
return ret;
sock = socket (SA (&sockaddr)->sa_family, SOCK_STREAM, 0);
if (sock == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "socket creation failed"
" (%s)", strerror (errno));
goto err;
}
flags = fcntl (sock, F_GETFL);
if (flags == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot get socket flags"
" (%s)", strerror(errno));
goto close_err;
}
ret = fcntl (sock, F_SETFL, flags | O_NONBLOCK);
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set socket "
"non-blocking (%s)", strerror (errno));
goto close_err;
}
ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof (opt));
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "setsockopt() for "
"SO_REUSEADDR failed (%s)", strerror (errno));
goto close_err;
}
ret = bind (sock, (struct sockaddr *)&sockaddr, sockaddr_len);
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "binding socket failed:"
" %s", strerror (errno));
if (errno == EADDRINUSE)
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Port is already"
" in use");
goto close_err;
}
ret = listen (sock, 10);
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "could not listen on"
" socket (%s)", strerror (errno));
goto close_err;
}
return sock;
close_err:
close (sock);
sock = -1;
err:
return sock;
}
int
rpcsvc_socket_accept (int listenfd)
{
int new_sock = -1;
struct sockaddr_storage new_sockaddr = {0, };
socklen_t addrlen = sizeof (new_sockaddr);
int flags = 0;
int ret = -1;
int on = 1;
new_sock = accept (listenfd, SA (&new_sockaddr), &addrlen);
if (new_sock == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR,"accept on socket failed");
goto err;
}
flags = fcntl (new_sock, F_GETFL);
if (flags == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot get socket flags"
" (%s)", strerror(errno));
goto close_err;
}
ret = fcntl (new_sock, F_SETFL, flags | O_NONBLOCK);
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set socket "
"non-blocking (%s)", strerror (errno));
goto close_err;
}
#ifdef TCP_NODELAY
ret = setsockopt(new_sock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "cannot set no-delay "
" socket option");
}
#endif
return new_sock;
close_err:
close (new_sock);
new_sock = -1;
err:
return new_sock;
}
ssize_t
rpcsvc_socket_read (int sockfd, char *readaddr, size_t readsize)
{
ssize_t dataread = 0;
ssize_t readlen = -1;
if (!readaddr)
return -1;
while (readsize > 0) {
readlen = read (sockfd, readaddr, readsize);
if (readlen == -1) {
if (errno != EAGAIN) {
dataread = -1;
break;
} else
break;
} else if (readlen == 0)
break;
dataread += readlen;
readaddr += readlen;
readsize -= readlen;
}
return dataread;
}
ssize_t
rpcsvc_socket_write (int sockfd, char *buffer, size_t size)
{
size_t writelen = -1;
ssize_t written = 0;
if (!buffer)
return -1;
while (size > 0) {
writelen = write (sockfd, buffer, size);
if (writelen == -1) {
if (errno != EAGAIN) {
written = -1;
break;
} else
break;
} else if (writelen == 0)
break;
written += writelen;
size -= writelen;
buffer += writelen;
}
return written;
}
int
rpcsvc_socket_peername (int sockfd, char *hostname, int hostlen)
{
struct sockaddr sa;
socklen_t sl = sizeof (sa);
int ret = EAI_FAIL;
if (!hostname)
return ret;
ret = getpeername (sockfd, &sa, &sl);
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Failed to get peer name:"
" %s", strerror (errno));
ret = EAI_FAIL;
goto err;
}
ret = getnameinfo (&sa, sl, hostname, hostlen, NULL, 0, 0);
if (ret != 0)
goto err;
err:
return ret;
}
int
rpcsvc_socket_peeraddr (int sockfd, char *addrstr, int addrlen,
struct sockaddr *returnsa, socklen_t sasize)
{
struct sockaddr sa;
int ret = EAI_FAIL;
if (returnsa)
ret = getpeername (sockfd, returnsa, &sasize);
else {
sasize = sizeof (sa);
ret = getpeername (sockfd, &sa, &sasize);
}
if (ret == -1) {
gf_log (GF_RPCSVC_SOCK, GF_LOG_ERROR, "Failed to get peer addr:"
" %s", strerror (errno));
ret = EAI_FAIL;
goto err;
}
/* If caller did not specify a string into which the address can be
* stored, dont bother getting it.
*/
if (!addrstr) {
ret = 0;
goto err;
}
if (returnsa)
ret = getnameinfo (returnsa, sasize, addrstr, addrlen, NULL, 0,
NI_NUMERICHOST);
else
ret = getnameinfo (&sa, sasize, addrstr, addrlen, NULL, 0,
NI_NUMERICHOST);
err:
return ret;
}
int
rpcsvc_socket_block_tx (int sockfd)
{
int ret = -1;
int on = 1;
#ifdef TCP_CORK
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &on, sizeof(on));
#endif
#ifdef TCP_NOPUSH
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &on, sizeof(on));
#endif
return ret;
}
int
rpcsvc_socket_unblock_tx (int sockfd)
{
int ret = -1;
int off = 0;
#ifdef TCP_CORK
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_CORK, &off, sizeof(off));
#endif
#ifdef TCP_NOPUSH
ret = setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &off, sizeof(off));
#endif
return ret;
}

View File

@ -0,0 +1,65 @@
/*
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _RPCSVC_SOCKET_H_
#define _RPCSVC_SOCKET_H_
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "rpcsvc.h"
#include "dict.h"
#include "logging.h"
#include "byte-order.h"
#include "common-utils.h"
#include "compat-errno.h"
#include <fcntl.h>
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#define SA(ptr) ((struct sockaddr *)ptr)
#define GF_RPCSVC_SOCK "rpc-socket"
extern int
rpcsvc_socket_listen (int addrfam, char *listenhost, uint16_t listenport);
extern int
rpcsvc_socket_accept (int listenfd);
extern ssize_t
rpcsvc_socket_read (int sockfd, char *readaddr, size_t readsize);
extern ssize_t
rpcsvc_socket_write (int sockfd, char *buffer, size_t size);
extern int
rpcsvc_socket_peername (int sockfd, char *hostname, int hostlen);
extern int
rpcsvc_socket_peeraddr (int sockfd, char *addrstr, int addrlen,
struct sockaddr *returnsa, socklen_t sasize);
extern int
rpcsvc_socket_block_tx (int sockfd);
extern int
rpcsvc_socket_unblock_tx (int sockfd);
#endif

View File

@ -0,0 +1,391 @@
/*
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#include "rpcsvc.h"
#include "logging.h"
#include "dict.h"
extern rpcsvc_auth_t *
rpcsvc_auth_null_init (rpcsvc_t *svc, dict_t *options);
extern rpcsvc_auth_t *
rpcsvc_auth_unix_init (rpcsvc_t *svc, dict_t *options);
int
rpcsvc_auth_add_initer (struct list_head *list, char *idfier,
rpcsvc_auth_initer_t init)
{
struct rpcsvc_auth_list *new = NULL;
if ((!list) || (!init) || (!idfier))
return -1;
new = CALLOC (1, sizeof (*new));
if (!new) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Memory allocation failed");
return -1;
}
new->init = init;
strcpy (new->name, idfier);
INIT_LIST_HEAD (&new->authlist);
list_add_tail (&new->authlist, list);
return 0;
}
int
rpcsvc_auth_add_initers (rpcsvc_t *svc)
{
int ret = -1;
ret = rpcsvc_auth_add_initer (&svc->authschemes, "auth-unix",
(rpcsvc_auth_initer_t)
rpcsvc_auth_unix_init);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_UNIX");
goto err;
}
ret = rpcsvc_auth_add_initer (&svc->authschemes, "auth-null",
(rpcsvc_auth_initer_t)
rpcsvc_auth_null_init);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add AUTH_NULL");
goto err;
}
ret = 0;
err:
return 0;
}
int
rpcsvc_auth_init_auth (rpcsvc_t *svc, dict_t *options,
struct rpcsvc_auth_list *authitem)
{
int ret = -1;
if ((!svc) || (!options) || (!authitem))
return -1;
if (!authitem->init) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "No init function defined");
ret = -1;
goto err;
}
authitem->auth = authitem->init (svc, options);
if (!authitem->auth) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Registration of auth failed:"
" %s", authitem->name);
ret = -1;
goto err;
}
authitem->enable = 1;
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Authentication enabled: %s",
authitem->auth->authname);
ret = 0;
err:
return ret;
}
int
rpcsvc_auth_init_auths (rpcsvc_t *svc, dict_t *options)
{
int ret = -1;
struct rpcsvc_auth_list *auth = NULL;
struct rpcsvc_auth_list *tmp = NULL;
if (!svc)
return -1;
if (list_empty (&svc->authschemes)) {
gf_log (GF_RPCSVC, GF_LOG_WARNING, "No authentication!");
ret = 0;
goto err;
}
/* If auth null and sys are not disabled by the user, we must enable
* it by default. This is a globally default rule, the user is still
* allowed to disable the two for particular subvolumes.
*/
if (!dict_get (options, "rpc-auth.auth-null"))
ret = dict_set_dynstr (options, "rpc-auth.auth-null", "on");
if (!dict_get (options, "rpc-auth.auth-unix"))
ret = dict_set_dynstr (options, "rpc-auth.auth-unix", "on");
list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) {
ret = rpcsvc_auth_init_auth (svc, options, auth);
if (ret == -1)
goto err;
}
ret = 0;
err:
return ret;
}
int
rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options)
{
int ret = -1;
if ((!svc) || (!options))
return -1;
ret = rpcsvc_auth_add_initers (svc);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to add initers");
goto out;
}
ret = rpcsvc_auth_init_auths (svc, options);
if (ret == -1) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Failed to init auth schemes");
goto out;
}
out:
return ret;
}
rpcsvc_auth_t *
__rpcsvc_auth_get_handler (rpcsvc_request_t *req)
{
int ret = -1;
struct rpcsvc_auth_list *auth = NULL;
struct rpcsvc_auth_list *tmp = NULL;
rpcsvc_t *svc = NULL;
if (!req)
return NULL;
svc = rpcsvc_request_service (req);
if (list_empty (&svc->authschemes)) {
gf_log (GF_RPCSVC, GF_LOG_WARNING, "No authentication!");
ret = 0;
goto err;
}
list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) {
if (!auth->enable)
continue;
if (auth->auth->authnum == req->cred.flavour)
goto err;
}
auth = NULL;
err:
if (auth)
return auth->auth;
else
return NULL;
}
rpcsvc_auth_t *
rpcsvc_auth_get_handler (rpcsvc_request_t *req)
{
rpcsvc_auth_t *auth = NULL;
auth = __rpcsvc_auth_get_handler (req);
if (auth)
goto ret;
gf_log (GF_RPCSVC, GF_LOG_TRACE, "No auth handler: %d",
req->cred.flavour);
/* The requested scheme was not available so fall back the to one
* scheme that will always be present.
*/
req->cred.flavour = AUTH_NULL;
req->verf.flavour = AUTH_NULL;
auth = __rpcsvc_auth_get_handler (req);
ret:
return auth;
}
int
rpcsvc_auth_request_init (rpcsvc_request_t *req)
{
int ret = -1;
rpcsvc_auth_t *auth = NULL;
if (!req)
return -1;
auth = rpcsvc_auth_get_handler (req);
if (!auth)
goto err;
ret = 0;
gf_log (GF_RPCSVC, GF_LOG_TRACE, "Auth handler: %s", auth->authname);
if (!auth->authops->request_init)
ret = auth->authops->request_init (req, auth->authprivate);
err:
return ret;
}
int
rpcsvc_authenticate (rpcsvc_request_t *req)
{
int ret = RPCSVC_AUTH_REJECT;
rpcsvc_auth_t *auth = NULL;
int minauth = 0;
if (!req)
return ret;
minauth = rpcsvc_request_prog_minauth (req);
if (minauth > rpcsvc_request_cred_flavour (req)) {
gf_log (GF_RPCSVC, GF_LOG_DEBUG, "Auth too weak");
rpcsvc_request_set_autherr (req, AUTH_TOOWEAK);
goto err;
}
auth = rpcsvc_auth_get_handler (req);
if (!auth) {
gf_log (GF_RPCSVC, GF_LOG_DEBUG, "No auth handler found");
goto err;
}
if (auth->authops->authenticate)
ret = auth->authops->authenticate (req, auth->authprivate);
err:
return ret;
}
int
rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen)
{
int count = 0;
int gen = RPCSVC_AUTH_REJECT;
int spec = RPCSVC_AUTH_REJECT;
int final = RPCSVC_AUTH_REJECT;
char *srchstr = NULL;
char *valstr = NULL;
gf_boolean_t boolval = _gf_false;
int ret = 0;
struct rpcsvc_auth_list *auth = NULL;
struct rpcsvc_auth_list *tmp = NULL;
if ((!svc) || (!autharr) || (!volname))
return -1;
memset (autharr, 0, arrlen * sizeof(int));
if (list_empty (&svc->authschemes)) {
gf_log (GF_RPCSVC, GF_LOG_ERROR, "No authentication!");
goto err;
}
list_for_each_entry_safe (auth, tmp, &svc->authschemes, authlist) {
if (count >= arrlen)
break;
gen = asprintf (&srchstr, "rpc-auth.%s", auth->name);
if (gen == -1) {
count = -1;
goto err;
}
gen = RPCSVC_AUTH_REJECT;
if (dict_get (svc->options, srchstr)) {
ret = dict_get_str (svc->options, srchstr, &valstr);
if (ret == 0) {
ret = gf_string2boolean (valstr, &boolval);
if (ret == 0) {
if (boolval == _gf_true)
gen = RPCSVC_AUTH_ACCEPT;
} else
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile"
"d to read auth val");
} else
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile"
"d to read auth val");
}
FREE (srchstr);
spec = asprintf (&srchstr, "rpc-auth.%s.%s", auth->name,
volname);
if (spec == -1) {
count = -1;
goto err;
}
spec = RPCSVC_AUTH_DONTCARE;
if (dict_get (svc->options, srchstr)) {
ret = dict_get_str (svc->options, srchstr, &valstr);
if (ret == 0) {
ret = gf_string2boolean (valstr, &boolval);
if (ret == 0) {
if (boolval == _gf_true)
spec = RPCSVC_AUTH_ACCEPT;
else
spec = RPCSVC_AUTH_REJECT;
} else
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile"
"d to read auth val");
} else
gf_log (GF_RPCSVC, GF_LOG_ERROR, "Faile"
"d to read auth val");
}
FREE (srchstr);
final = rpcsvc_combine_gen_spec_volume_checks (gen, spec);
if (final == RPCSVC_AUTH_ACCEPT) {
autharr[count] = auth->auth->authnum;
++count;
}
}
err:
return count;
}
gid_t *
rpcsvc_auth_unix_auxgids (rpcsvc_request_t *req, int *arrlen)
{
if ((!req) || (!arrlen))
return NULL;
if (req->cred.flavour != AUTH_UNIX)
return NULL;
*arrlen = req->auxgidcount;
if (*arrlen == 0)
return NULL;
return &req->auxgids[0];
}

2743
xlators/nfs/lib/src/rpcsvc.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,715 @@
/*
Copyright (c) 2010 Gluster, Inc. <http://www.gluster.com>
This file is part of GlusterFS.
GlusterFS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 3 of the License,
or (at your option) any later version.
GlusterFS 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. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see
<http://www.gnu.org/licenses/>.
*/
#ifndef _RPCSVC_H
#define _RPCSVC_H
#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif
#include "event.h"
#include "transport.h"
#include "logging.h"
#include "dict.h"
#include "mem-pool.h"
#include "list.h"
#include "iobuf.h"
#include "xdr-rpc.h"
#include "glusterfs.h"
#include <pthread.h>
#include <sys/uio.h>
#define GF_RPCSVC "rpc-service"
#define RPCSVC_THREAD_STACK_SIZE ((size_t)(1024 * GF_UNIT_KB))
#define RPCSVC_DEFAULT_MEMFACTOR 15
#define RPCSVC_EVENTPOOL_SIZE_MULT 1024
#define RPCSVC_POOLCOUNT_MULT 35
#define RPCSVC_CONN_READ (128 * GF_UNIT_KB)
#define RPCSVC_PAGE_SIZE (128 * GF_UNIT_KB)
/* Defines for RPC record and fragment assembly */
#define RPCSVC_FRAGHDR_SIZE 4 /* 4-byte RPC fragment header size */
/* Given the 4-byte fragment header, returns non-zero if this fragment
* is the last fragment for the RPC record being assemebled.
* RPC Record marking standard defines a 32 bit value as the fragment
* header with the MSB signifying whether the fragment is the last
* fragment for the record being asembled.
*/
#define RPCSVC_LASTFRAG(fraghdr) ((uint32_t)(fraghdr & 0x80000000U))
/* Given the 4-byte fragment header, extracts the bits that contain
* the fragment size.
*/
#define RPCSVC_FRAGSIZE(fraghdr) ((uint32_t)(fraghdr & 0x7fffffffU))
/* RPC Record States */
#define RPCSVC_READ_FRAGHDR 1
#define RPCSVC_READ_FRAG 2
/* The size in bytes, if crossed by a fragment will be handed over to the
* vectored actor so that it can allocate its buffers the way it wants.
* In our RPC layer, we assume that vectored RPC requests/records are never
* spread over multiple RPC fragments since that prevents us from determining
* whether the record should be handled in RPC layer completely or handed to
* the vectored handler.
*/
#define RPCSVC_VECTORED_FRAGSZ 4096
#define RPCSVC_VECTOR_READCRED 1003
#define RPCSVC_VECTOR_READVERFSZ 1004
#define RPCSVC_VECTOR_READVERF 1005
#define RPCSVC_VECTOR_IGNORE 1006
#define RPCSVC_VECTOR_READVEC 1007
#define RPCSVC_VECTOR_READPROCHDR 1008
#define rpcsvc_record_vectored_baremsg(rs) (((rs)->state == RPCSVC_READ_FRAG) && (rs)->vecstate == 0)
#define rpcsvc_record_vectored_cred(rs) ((rs)->vecstate == RPCSVC_VECTOR_READCRED)
#define rpcsvc_record_vectored_verfsz(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVERFSZ)
#define rpcsvc_record_vectored_verfread(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVERF)
#define rpcsvc_record_vectored_ignore(rs) ((rs)->vecstate == RPCSVC_VECTOR_IGNORE)
#define rpcsvc_record_vectored_readvec(rs) ((rs)->vecstate == RPCSVC_VECTOR_READVEC)
#define rpcsvc_record_vectored_readprochdr(rs) ((rs)->vecstate == RPCSVC_VECTOR_READPROCHDR)
#define rpcsvc_record_vectored(rs) ((rs)->fragsize > RPCSVC_VECTORED_FRAGSZ)
/* Includes bytes up to and including the credential length field. The credlen
* will be followed by @credlen bytes of credential data which will have to be
* read separately by the vectored reader. After the credentials comes the
* verifier which will also have to be read separately including the 8 bytes of
* verf flavour and verflen.
*/
#define RPCSVC_BARERPC_MSGSZ 32
#define rpcsvc_record_readfraghdr(rs) ((rs)->state == RPCSVC_READ_FRAGHDR)
#define rpcsvc_record_readfrag(rs) ((rs)->state == RPCSVC_READ_FRAG)
#define rpcsvc_conn_rpcsvc(conn) ((conn)->stage->svc)
#define RPCSVC_LOWVERS 2
#define RPCSVC_HIGHVERS 2
typedef struct rpc_svc_program rpcsvc_program_t;
/* A Stage is the event handler thread together with
* the connections being served by this thread.
* It is called a stage because all the actors, i.e, protocol actors,
* defined by higher level users of the RPC layer, are executed here.
*/
typedef struct rpc_svc_stage_context {
pthread_t tid;
struct event_pool *eventpool; /* Per-stage event-pool */
void *svc; /* Ref to the rpcsvc_t */
} rpcsvc_stage_t;
/* RPC Records and Fragments assembly state.
* This is per-connection state that is used to determine
* how much data has come in, how much more needs to be read
* and where it needs to be read.
*
* All this state is then used to re-assemble network buffers into
* RPC fragments, which are then re-assembled into RPC records.
*
* See RFC 1831: "RPC: Remote Procedure Call Protocol Specification Version 2",
* particularly the section on Record Marking Standard.
*/
typedef struct rpcsvc_record_state {
/* Pending messages storage
* This memory area is currently being used to assemble
* the latest RPC record.
*
* Note that this buffer contains the data other than the
* fragment headers received from the network. This is so that we can
* directly pass this buffer to higher layers without requiring to
* perform memory copies and marshalling of data.
*/
struct iobuf *activeiob;
struct iobuf *vectoriob;
/* The pointer into activeiob memory, into which will go the
* contents from the next read from the network.
*/
char *fragcurrent;
/* Size of the currently incomplete RPC fragment.
* This is filled in when the fragment header comes in.
* Even though only the 31 least significant bits are used from the
* fragment header, we use a 32 bit variable to store the size.
*/
uint32_t fragsize;
/* The fragment header is always read in here so that
* the RPC messages contained in a RPC records can be processed
* separately without copying them out of the activeiob above.
*/
char fragheader[RPCSVC_FRAGHDR_SIZE];
char *hdrcurrent;
/* Bytes remaining to come in for the current fragment. */
uint32_t remainingfrag;
/* It is possible for the frag header to be split over separate
* read calls, so we need to keep track of how much is left.
*/
uint32_t remainingfraghdr;
/* Record size, the total size of the RPC record, i.e. the total
* of all fragment sizes received till now. Does not include the size
* of a partial fragment which is continuing to be assembled right now.
*/
int recordsize;
/* Current state of the record */
int state;
/* Current state of the vectored reading process. */
int vecstate;
/* Set to non-zero when the currently partial or complete fragment is
* the last fragment being received for the current RPC record.
*/
uint32_t islastfrag;
} rpcsvc_record_state_t;
#define RPCSVC_CONNSTATE_CONNECTED 1
#define RPCSVC_CONNSTATE_DISCONNECTED 2
#define rpcsvc_conn_check_active(conn) ((conn)->connstate==RPCSVC_CONNSTATE_CONNECTED)
typedef struct rpcsvc_request rpcsvc_request_t;
/* Contains the state for each connection that is used for transmitting and
* receiving RPC messages.
*
* There is also an eventidx because each connection's fd is added to the event
* pool of the stage to which a connection belongs.
* Anything that can be accessed by a RPC program must be synced through
* connlock.
*/
typedef struct rpc_conn_state {
/* Transport or connection state */
/* Once we start working on RDMA support, this TCP specific state will
* have to be abstracted away.
*/
int sockfd;
int eventidx;
int windowsize;
/* Reference to the stage which is handling this
* connection.
*/
rpcsvc_stage_t *stage;
/* RPC Records and Fragments assembly state.
* All incoming data is staged here before being
* called a full RPC message.
*/
rpcsvc_record_state_t rstate;
/* It is possible that a client disconnects while
* the higher layer RPC service is busy in a call.
* In this case, we cannot just free the conn
* structure, since the higher layer service could
* still have a reference to it.
* The refcount avoids freeing until all references
* have been given up, although the connection is clos()ed at the first
* call to unref.
*/
int connref;
pthread_mutex_t connlock;
int connstate;
/* The program that is listening for requests on this connection. */
rpcsvc_program_t *program;
/* List of buffers awaiting transmission */
/* Accesses to txbufs between multiple threads calling
* rpcsvc_submit is synced through connlock. Prefer spinlock over
* mutex because this is a low overhead op that needs simple
* appending to the tx list.
*/
struct list_head txbufs;
/* Mem pool for the txbufs above. */
struct mem_pool *txpool;
/* Memory pool for rpcsvc_request_t */
struct mem_pool *rxpool;
/* The request which hasnt yet been handed to the RPC program because
* this request is being treated as a vector request and so needs some
* more data to be got from the network.
*/
rpcsvc_request_t *vectoredreq;
} rpcsvc_conn_t;
#define RPCSVC_MAX_AUTH_BYTES 400
typedef struct rpcsvc_auth_data {
int flavour;
int datalen;
char authdata[RPCSVC_MAX_AUTH_BYTES];
} rpcsvc_auth_data_t;
#define rpcsvc_auth_flavour(au) ((au).flavour)
/* The container for the RPC call handed up to an actor.
* Dynamically allocated. Lives till the call reply is completely
* transmitted.
* */
struct rpcsvc_request {
/* Connection over which this request came. */
rpcsvc_conn_t *conn;
/* The identifier for the call from client.
* Needed to pair the reply with the call.
*/
uint32_t xid;
int prognum;
int progver;
int procnum;
/* Uid and gid filled by the rpc-auth module during the authentication
* phase.
*/
uid_t uid;
gid_t gid;
/* Might want to move this to AUTH_UNIX specifix state since this array
* is not available for every authenticatino scheme.
*/
gid_t auxgids[NGRPS];
int auxgidcount;
/* The RPC message payload, contains the data required
* by the program actors. This is the buffer that will need to
* be de-xdred by the actor.
*/
struct iovec msg;
/* The full message buffer allocated to store the RPC headers.
* This buffer is ref'd when allocated why RPC svc and unref'd after
* the buffer is handed to the actor. That means if the actor or any
* higher layer wants to keep this buffer around, they too must ref it
* right after entering the program actor.
*/
struct iobuf *recordiob;
/* Status of the RPC call, whether it was accepted or denied. */
int rpc_stat;
/* In case, the call was denied, the RPC error is stored here
* till the reply is sent.
*/
int rpc_err;
/* In case the failure happened because of an authentication problem
* , this value needs to be assigned the correct auth error number.
*/
int auth_err;
/* There can be cases of RPC requests where the reply needs to
* be built from multiple sources. For eg. where even the NFS reply can
* contain a payload, as in the NFSv3 read reply. Here the RPC header
* ,NFS header and the read data are brought together separately from
* different buffers, so we need to stage the buffers temporarily here
* before all of them get added to the connection's transmission list.
*/
struct list_head txlist;
/* While the reply record is being built, this variable keeps track
* of how many bytes have been added to the record.
*/
size_t payloadsize;
/* The credentials extracted from the rpc request */
rpcsvc_auth_data_t cred;
/* The verified extracted from the rpc request. In request side
* processing this contains the verifier sent by the client, on reply
* side processing, it is filled with the verified that will be
* sent to the client.
*/
rpcsvc_auth_data_t verf;
/* Container for a RPC program wanting to store a temp
* request-specific item.
*/
void *private;
};
#define rpcsvc_request_program(req) ((rpcsvc_program_t *)((req)->conn->program))
#define rpcsvc_request_program_private(req) (((rpcsvc_program_t *)((req)->conn->program))->private)
#define rpcsvc_request_conn(req) (req)->conn
#define rpcsvc_request_accepted(req) ((req)->rpc_stat == MSG_ACCEPTED)
#define rpcsvc_request_accepted_success(req) ((req)->rpc_err == SUCCESS)
#define rpcsvc_request_uid(req) ((req)->uid)
#define rpcsvc_request_gid(req) ((req)->gid)
#define rpcsvc_stage_service(stg) ((rpcsvc_t *)((stg)->svc))
#define rpcsvc_conn_stage(conn) ((conn)->stage)
#define rpcsvc_request_service(req) (rpcsvc_stage_service(rpcsvc_conn_stage(rpcsvc_request_conn(req))))
#define rpcsvc_request_prog_minauth(req) (rpcsvc_request_program(req)->min_auth)
#define rpcsvc_request_cred_flavour(req) (rpcsvc_auth_flavour(req->cred))
#define rpcsvc_request_verf_flavour(req) (rpcsvc_auth_flavour(req->verf))
#define rpcsvc_request_uid(req) ((req)->uid)
#define rpcsvc_request_gid(req) ((req)->gid)
#define rpcsvc_request_private(req) ((req)->private)
#define rpcsvc_request_xid(req) ((req)->xid)
#define rpcsvc_request_set_private(req,prv) (req)->private = (void *)(prv)
#define rpcsvc_request_record_iob(rq) ((rq)->recordiob)
#define rpcsvc_request_record_ref(req) (iobuf_ref ((req)->recordiob))
#define rpcsvc_request_record_unref(req) (iobuf_unref ((req)->recordiob))
#define RPCSVC_ACTOR_SUCCESS 0
#define RPCSVC_ACTOR_ERROR (-1)
/* Functor for every type of protocol actor
* must be defined like this.
*
* See the request structure for info on how to handle the request
* in the program actor.
*
* On successful santify checks inside the actor, it should return
* RPCSVC_ACTOR_SUCCESS.
* On an error, on which the RPC layer is expected to return a reply, the actor
* should return RPCSVC_ACTOR_ERROR.
*
*/
typedef int (*rpcsvc_actor) (rpcsvc_request_t *req);
typedef int (*rpcsvc_vector_actor) (rpcsvc_request_t *req, struct iobuf *iob);
typedef int (*rpcsvc_vector_sizer) (rpcsvc_request_t *req, ssize_t *readsize,
int *newiob);
/* Every protocol actor will also need to specify the function the RPC layer
* will use to serialize or encode the message into XDR format just before
* transmitting on the connection.
*/
typedef void *(*rpcsvc_encode_reply) (void *msg);
/* Once the reply has been transmitted, the message will have to be de-allocated
* , so every actor will need to provide a function that deallocates the message
* it had allocated as a response.
*/
typedef void (*rpcsvc_deallocate_reply) (void *msg);
#define RPCSVC_NAME_MAX 32
/* The descriptor for each procedure/actor that runs
* over the RPC service.
*/
typedef struct rpc_svc_actor_desc {
char procname[RPCSVC_NAME_MAX];
int procnum;
rpcsvc_actor actor;
/* Handler for cases where the RPC requests fragments are large enough
* to benefit from being decoded into aligned memory addresses. While
* decoding the request in a non-vectored manner, due to the nature of
* the XDR scheme, RPC cannot guarantee memory aligned addresses for
* the resulting message-specific structures. Allowing a specialized
* handler for letting the RPC program read the data from the network
* directly into its alligned buffers.
*/
rpcsvc_vector_actor vector_actor;
rpcsvc_vector_sizer vector_sizer;
} rpcsvc_actor_t;
typedef int (*rpcsvc_conn_notify_fn) (void *progpriv, rpcsvc_conn_t *conn);
/* Describes a program and its version along with the function pointers
* required to handle the procedures/actors of each program/version.
* Never changed ever by any thread so no need for a lock.
*/
struct rpc_svc_program {
char progname[RPCSVC_NAME_MAX];
int prognum;
int progver;
uint16_t progport; /* Registered with portmap */
int progaddrfamily; /* AF_INET or AF_INET6 */
char *proghost; /* Bind host, can be NULL */
rpcsvc_actor_t *actors; /* All procedure handlers */
int numactors; /* Num actors in actor array */
int proghighvers; /* Highest ver for program
supported by the system. */
int proglowvers; /* Lowest ver */
/* Program specific state handed to actors */
void *private;
/* This upcall is made when a connection's refcount reaches 0 and the
* connection is about to be destroyed. We want to let the RPC program
* know that it should also now free any state it is maintaining
* for this connection.
*/
rpcsvc_conn_notify_fn conn_destroy;
/* Used to tell RPC program to init the state it needs to associate
* with the new connection.
*/
rpcsvc_conn_notify_fn conn_init;
/* An integer that identifies the min auth strength that is required
* by this protocol, for eg. MOUNT3 needs AUTH_UNIX at least.
* See RFC 1813, Section 5.2.1.
*/
int min_auth;
};
/* Contains global state required for all the RPC services.
*/
typedef struct rpc_svc_state {
/* Contains the list of rpcsvc_stage_t
* list of (program, version) handlers.
* other options.
*/
/* At this point, lock is not used to protect anything. Later, it'll
* be used for protecting stages.
*/
pthread_mutex_t rpclock;
/* This is the first stage that is inited, so that any RPC based
* services that do not need multi-threaded support can just use the
* service right away. This is not added to the stages list
* declared later.
* This is also the stage over which all service listeners are run.
*/
rpcsvc_stage_t *defaultstage;
/* When we have multi-threaded RPC support, we'll use this to link
* to the multiple Stages.
*/
struct list_head stages; /* All stages */
unsigned int memfactor;
/* List of the authentication schemes available. */
struct list_head authschemes;
/* Reference to the options */
dict_t *options;
/* Allow insecure ports. */
int allow_insecure;
glusterfs_ctx_t *ctx;
} rpcsvc_t;
/* All users of RPC services should use this API to register their
* procedure handlers.
*/
extern int
rpcsvc_program_register (rpcsvc_t *svc, rpcsvc_program_t program);
extern int
rpcsvc_program_unregister (rpcsvc_t *svc, rpcsvc_program_t program);
/* Inits the global RPC service data structures.
* Called in main.
*/
extern rpcsvc_t *
rpcsvc_init (glusterfs_ctx_t *ctx, dict_t *options);
extern int
rpcsvc_submit_message (rpcsvc_request_t * req, struct iovec msg,
struct iobuf *iob);
int
rpcsvc_submit_generic (rpcsvc_request_t *req, struct iovec msgvec,
struct iobuf *msg);
#define rpcsvc_record_currentfrag_addr(rs) ((rs)->fragcurrent)
#define rpcsvc_record_currenthdr_addr(rs) ((rs)->hdrcurrent)
#define rpcsvc_record_update_currentfrag(rs, size) \
do { \
(rs)->fragcurrent += size; \
} while (0) \
#define rpcsvc_record_update_currenthdr(rs, size) \
do { \
(rs)->hdrcurrent += size; \
} while (0) \
/* These are used to differentiate between multiple txbufs which form
* a single RPC record. For eg, one purpose we use these for is to
* prevent dividing a RPC record over multiple TCP segments. Multiple
* TCP segments are possible for a single RPC record because we generally do not
* have control over how the kernel's TCP segments the buffers when putting
* them on the wire. So, on Linux, we use these to set TCP_CORK to create
* a single TCP segment from multiple txbufs that are part of the same RPC
* record. This improves network performance by reducing tiny message
* transmissions.
*/
#define RPCSVC_TXB_FIRST 0x1
#define RPCSVC_TXB_LAST 0x2
/* The list of buffers appended to a connection's pending
* transmission list.
*/
typedef struct rpcsvc_txbuf {
struct list_head txlist;
/* The iobuf which contains the full message to be transmitted */
struct iobuf *iob;
/* For vectored messages from an RPC program, we need to be able
* maintain a ref to an iobuf which we do not have access to directly
* except through the iobref which in turn could've been passed to
* the RPC program by a higher layer.
*
* So either the iob is defined or iobref is defined for a reply,
* never both.
*/
struct iobref *iobref;
/* In order to handle non-blocking writes, we'll need to keep track of
* how much data from an iobuf has been written and where the next
* transmission needs to start from. This iov.base points to the base of
* the iobuf, iov.len is the size of iobuf being used for the message
* from the total size in the iobuf.
*/
struct iovec buf;
/* offset is the point from where the next transmission for this buffer
* should start.
*/
size_t offset;
/* This is a special field that tells us what kind of transmission
* behaviour to provide to a particular buffer.
* See the RPCSVC_TXB_* defines for more info.
*/
int txbehave;
} rpcsvc_txbuf_t;
extern int
rpcsvc_error_reply (rpcsvc_request_t *req);
#define RPCSVC_PEER_STRLEN 1024
#define RPCSVC_AUTH_ACCEPT 1
#define RPCSVC_AUTH_REJECT 2
#define RPCSVC_AUTH_DONTCARE 3
extern int
rpcsvc_conn_peername (rpcsvc_conn_t *conn, char *hostname, int hostlen);
extern int
rpcsvc_conn_peeraddr (rpcsvc_conn_t *conn, char *addrstr, int addrlen,
struct sockaddr *returnsa, socklen_t sasize);
extern int
rpcsvc_conn_peer_check (dict_t *options, char *volname, rpcsvc_conn_t *conn);
extern int
rpcsvc_conn_privport_check (rpcsvc_t *svc, char *volname, rpcsvc_conn_t *conn);
#define rpcsvc_request_seterr(req, err) (req)->rpc_err = err
#define rpcsvc_request_set_autherr(req, err) (req)->auth_err = err
extern void
rpcsvc_conn_deinit (rpcsvc_conn_t *conn);
extern void rpcsvc_conn_ref (rpcsvc_conn_t *conn);
extern void rpcsvc_conn_unref (rpcsvc_conn_t *conn);
extern int rpcsvc_submit_vectors (rpcsvc_request_t *req);
extern int rpcsvc_request_attach_vector (rpcsvc_request_t *req,
struct iovec msgvec, struct iobuf *iob,
struct iobref *ioref, int finalvector);
typedef int (*auth_init_conn) (rpcsvc_conn_t *conn, void *priv);
typedef int (*auth_init_request) (rpcsvc_request_t *req, void *priv);
typedef int (*auth_request_authenticate) (rpcsvc_request_t *req, void *priv);
/* This structure needs to be registered by every authentication scheme.
* Our authentication schemes are stored per connection because
* each connection will end up using a different authentication scheme.
*/
typedef struct rpcsvc_auth_ops {
auth_init_conn conn_init;
auth_init_request request_init;
auth_request_authenticate authenticate;
} rpcsvc_auth_ops_t;
typedef struct rpcsvc_auth_flavour_desc {
char authname[RPCSVC_NAME_MAX];
int authnum;
rpcsvc_auth_ops_t *authops;
void *authprivate;
} rpcsvc_auth_t;
typedef void * (*rpcsvc_auth_initer_t) (rpcsvc_t *svc, dict_t *options);
struct rpcsvc_auth_list {
struct list_head authlist;
rpcsvc_auth_initer_t init;
/* Should be the name with which we identify the auth scheme given
* in the volfile options.
* This should be different from the authname in rpc_auth_t
* in way that makes it easier to specify this scheme in the volfile.
* This is because the technical names of the schemes can be a bit
* arcane.
*/
char name[RPCSVC_NAME_MAX];
rpcsvc_auth_t *auth;
int enable;
};
extern int
rpcsvc_auth_request_init (rpcsvc_request_t *req);
extern int
rpcsvc_auth_init (rpcsvc_t *svc, dict_t *options);
extern int
rpcsvc_auth_conn_init (rpcsvc_conn_t *conn);
extern int
rpcsvc_authenticate (rpcsvc_request_t *req);
extern int
rpcsvc_auth_array (rpcsvc_t *svc, char *volname, int *autharr, int arrlen);
/* If the request has been sent using AUTH_UNIX, this function returns the
* auxiliary gids as an array, otherwise, it returns NULL.
* Move to auth-unix specific source file when we need to modularize the
* authentication code even further to support mode auth schemes.
*/
extern gid_t *
rpcsvc_auth_unix_auxgids (rpcsvc_request_t *req, int *arrlen);
extern int
rpcsvc_combine_gen_spec_volume_checks (int gen, int spec);
extern char *
rpcsvc_volume_allowed (dict_t *options, char *volname);
#endif