summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2015-04-22 11:00:35 -0400
committerSteve Dickson <steved@redhat.com>2015-04-29 11:40:32 -0400
commitc55a77516fd0d226eb46f44b89fec966a682180f (patch)
treebef38d258fbd054d29fbeff372a00d9fc0d85a2c
parent184e7b7cfca09fc2ca9c19d66307d8888be0a876 (diff)
downloadti-rpc-c55a77516fd0d226eb46f44b89fec966a682180f.tar.gz
Add server-side rpc_gss_*() APIs
Introduce new RPCSEC API functions that match the same libtirpc API in FreeBSD and Solaris. This includes rpc_gss_getcred(3t), rpc_gss_svc_max_data_length(3t), rpc_gss_set_svc_name(3t), rpc_gss_set_callback(3t), and rpc_gss_get_principal_name(3t). The man pages, written by Doug Rabson, come from FreeBSD, with some adjustments by me. The new code was written from scratch based on FreeBSD's implementation, but adapted to invoke the existing legacy U-M APIs in our implementation. We will maintain the legacy APIs until consumers are switched to the new ones. FreeBSD never had the legacy U-M API. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: Steve Dickson <steved@redhat.com>
-rw-r--r--man/Makefile.am4
-rw-r--r--man/rpc_gss_get_principal_name.3t79
-rw-r--r--man/rpc_gss_getcred.3t82
-rw-r--r--man/rpc_gss_set_callback.3t112
-rw-r--r--man/rpc_gss_set_svc_name.3t84
-rw-r--r--man/rpc_gss_svc_max_data_length.3t61
-rw-r--r--src/svc_auth_gss.c370
7 files changed, 782 insertions, 10 deletions
diff --git a/man/Makefile.am b/man/Makefile.am
index 366c650..cf510e7 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -12,7 +12,9 @@ RPCSEC_MANS = rpcsec_gss.3t rpc_gss_get_error.3t \
rpc_gss_get_versions.3t rpc_gss_is_installed.3t \
rpc_gss_mech_to_oid.3t rpc_gss_qop_to_num.3t \
rpc_gss_max_data_length.3t rpc_gss_seccreate.3t \
- rpc_gss_set_defaults.3t
+ rpc_gss_set_defaults.3t rpc_gss_getcred.3t \
+ rpc_gss_get_principal_name.3t rpc_gss_set_callback.3t \
+ rpc_gss_set_svc_name.3t rpc_gss_svc_max_data_length.3t
dist_man5_MANS = netconfig.5
dist_man3_MANS = $(LOOKUP_MANS) $(NETCONFIG_MANS) \
diff --git a/man/rpc_gss_get_principal_name.3t b/man/rpc_gss_get_principal_name.3t
new file mode 100644
index 0000000..ba04239
--- /dev/null
+++ b/man/rpc_gss_get_principal_name.3t
@@ -0,0 +1,79 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr@rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd January 26, 2010
+.Dt RPC_GSS_GET_PRINCIPAL_NAME 3
+.Os
+.Sh NAME
+.Nm rpc_gss_get_principal_name
+.Nd "Get a principal name"
+.Sh SYNOPSIS
+.In rpc/rpcsec_gss.h
+.Ft bool_t
+.Fo rpc_gss_get_principal_name
+.Fa "rpc_gss_principal_t *principal"
+.Fa "const char *mech"
+.Fa "const char *name"
+.Fa "const char *node"
+.Fa "const char *domain"
+.Fc
+.Sh DESCRIPTION
+This function can be used to generate a client principal name from
+various strings.
+.Sh PARAMETERS
+.Bl -tag -width ".It principal"
+.It principal
+If the principal is created successfully,
+.Fa *principal
+will be set to point at the new principal in GSS-API exported name form
+.It mech
+The name of the mechanism for this principal
+.It name
+The name part of the principal
+.It node
+If non-null, the hostname or instance part of the principal
+.It domain
+If non-null, the domain or realm part of the principal
+.El
+.Sh RETURN VALUES
+Returns
+.Dv TRUE
+if the principal was created or
+.Dv FALSE
+otherwise
+.Sh AVAILABILITY
+The
+.Fn rpc_gss_get_principal_name
+function is part of libtirpc.
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr gssapi 3 ,
+.Xr gss_export_name 3 ,
+.Xr rpcsec_gss 3
+.Sh AUTHORS
+This
+manual page was written by
+.An Doug Rabson Aq dfr@FreeBSD.org .
diff --git a/man/rpc_gss_getcred.3t b/man/rpc_gss_getcred.3t
new file mode 100644
index 0000000..8589f08
--- /dev/null
+++ b/man/rpc_gss_getcred.3t
@@ -0,0 +1,82 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr@rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd January 26, 2010
+.Dt RPC_GSS_GETCRED 3
+.Os
+.Sh NAME
+.Nm rpc_gss_getcred
+.Nd "Get authorization information for an RPC request"
+.Sh SYNOPSIS
+.In rpc/rpcsec_gss.h
+.Ft AUTH *
+.Fo rpc_gss_getcred
+.Fa "struct svc_req *req"
+.Fa "rpc_gss_rawcred_t **rcred"
+.Fa "rpc_gss_ucred_t **ucred"
+.Fa "void **cookie"
+.Fc
+.Sh DESCRIPTION
+This function returns the RPCSEC_GSS authenticated credentials
+associated with an RPC request.
+.Sh PARAMETERS
+.Bl -tag -width ".It cookie"
+.It req
+The RPC request to query
+.It rcred
+If non-null,
+.Fa *rcred
+is set to point at the raw credentials for this request
+.It ucred
+.It rcred
+If non-null,
+.Fa *ucred
+is set to point at the corresponding unix credentials
+.It cookie
+If non-null,
+.Fa *cookie
+is set to the cookie value returned by a callback function registered with
+.Fn rpc_gss_set_callback
+.El
+.Sh RETURN VALUES
+Returns
+.Dv TRUE
+if successful,
+.Dv FALSE
+otherwise.
+.Sh AVAILABILITY
+The
+.Fn rpc_gss_getcred
+function is part of libtirpc.
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr gssapi 3 ,
+.Xr rpc_gss_set_callback 3 ,
+.Xr rpcsec_gss 3
+.Sh AUTHORS
+This
+manual page was written by
+.An Doug Rabson Aq dfr@FreeBSD.org .
diff --git a/man/rpc_gss_set_callback.3t b/man/rpc_gss_set_callback.3t
new file mode 100644
index 0000000..ee4ebdf
--- /dev/null
+++ b/man/rpc_gss_set_callback.3t
@@ -0,0 +1,112 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr@rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd January 26, 2010
+.Dt RPC_GSS_SET_CALLBACK 3
+.Os
+.Sh NAME
+.Nm rpc_gss_set_callback
+.Nd "Register a security context creation callback"
+.Sh SYNOPSIS
+.In rpc/rpcsec_gss.h
+.Ft bool_t
+.Fo (*callback)
+.Fa "struct svc_req *req"
+.Fa "gss_cred_id_t deleg"
+.Fa "gss_ctx_id_t gss_context"
+.Fa "rpc_gss_lock_t *lock"
+.Fa "void **cookie"
+.Fc
+.Ft bool_t
+.Fn rpc_gss_set_callback "rpc_gss_callback_t *cb"
+.Sh DESCRIPTION
+Register a function which will be called when new security contexts
+are created on a server.
+This function will be called on the first RPC request which uses that
+context and has the opportunity of rejecting the request (for instance
+after matching the request credentials to an access control list).
+To accept the new security context, the callback should return
+.Dv TRUE ,
+otherwise
+.Dv FALSE .
+If the callback accepts a context, it becomes responsible for the
+lifetime of the delegated client credentials (if any).
+.Pp
+It is also possible to 'lock' the values of service and quality of
+protection used by the context.
+If a context is locked, any subsequent requests which use different
+values for service and quality of protection will be rejected.
+.Sh PARAMETERS
+.Bl -tag -width ".It gss_context"
+.It cb
+A structure containing the RPC program and version for this callback
+and a function which will be called when new contexts are created for
+the given RPC program and version
+.It req
+The RPC request using the new context
+.It deleg
+GSS-API delegated credentials (if any)
+.It gss_context
+The GSS-API context
+.It lock
+A structure used to enforce a particular QOP and service. Set
+.Fa lock->locked
+to
+.Dv TRUE
+to lock the service and QOP values
+.It cookie
+The callback function may set
+.Fa *cookie
+to any pointer sized value.
+This value can be accessed during the lifetime of the context via
+.Fn rpc_gss_getcred .
+.El
+.Sh RETURN VALUES
+Returns
+.Dv TRUE
+if the callback was registered successfully or
+.Dv FALSE
+otherwise
+.Sh AVAILABILITY
+The
+.Fn rpc_gss_set_callback
+function is part of libtirpc.
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr gssapi 3 ,
+.Xr rpc_gss_getcred 3
+.Xr rpcsec_gss 3
+.Sh AUTHORS
+This
+manual page was written by
+.An Doug Rabson Aq dfr@FreeBSD.org .
+.Sh BUGS
+There is no mechanism for informing a server when a security context
+has been deleted.
+This makes it difficult to allocate resources (e.g. to return via the
+callback's
+.Fa cookie
+argument).
diff --git a/man/rpc_gss_set_svc_name.3t b/man/rpc_gss_set_svc_name.3t
new file mode 100644
index 0000000..b895920
--- /dev/null
+++ b/man/rpc_gss_set_svc_name.3t
@@ -0,0 +1,84 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr@rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd January 26, 2010
+.Dt RPC_GSS_SET_SVC_NAME 3
+.Os
+.Sh NAME
+.Nm rpc_gss_set_svc_name
+.Nd "Associate a GSS-API service principal with an RPC service"
+.Sh SYNOPSIS
+.In rpc/rpcsec_gss.h
+.Ft bool_t
+.Fo rpc_gss_set_svc_name
+.Fa "const char *principal"
+.Fa "const char *mechanism"
+.Fa "u_int req_time"
+.Fa "u_int program"
+.Fa "u_int version"
+.Fc
+.Sh DESCRIPTION
+This function registers a service principal which will be used to
+authenticate RPCSEC_GSS security contexts for a given RPC program and
+version.
+.Sh PARAMETERS
+.Bl -tag -width ".It mechanism"
+.It principal
+A string representing the service principal in the form
+.Qq service@hostname
+.It mechanism
+The name of the security mechanism
+.It req_time
+The time in seconds that the service credentials should remain
+valid.
+See
+.Xr gss_acquire_cred 3
+for more details.
+principal.
+.It program
+RPC program number for this service
+.It version
+RPC program version for this service
+.El
+.Sh RETURN VALUES
+Returns
+.Dv TRUE
+if the service principal was registered or
+.Dv FALSE
+otherwise.
+.Sh AVAILABILITY
+The
+.Fn rpc_gss_set_svc_name
+function is part of libtirpc.
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr gssapi 3 ,
+.Xr gss_acquire_cred 3 ,
+.Xr rpcsec_gss 3
+.Sh AUTHORS
+This
+manual page was written by
+.An Doug Rabson Aq dfr@FreeBSD.org .
diff --git a/man/rpc_gss_svc_max_data_length.3t b/man/rpc_gss_svc_max_data_length.3t
new file mode 100644
index 0000000..4b89716
--- /dev/null
+++ b/man/rpc_gss_svc_max_data_length.3t
@@ -0,0 +1,61 @@
+.\" Copyright (c) 2008 Isilon Inc http://www.isilon.com/
+.\" Authors: Doug Rabson <dfr@rabson.org>
+.\" Developed with Red Inc: Alfred Perlstein <alfred@FreeBSD.org>
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.Dd January 26, 2010
+.Dt RPC_GSS_SVC_MAX_DATA_LENGTH 3
+.Os
+.Sh NAME
+.Nm rpc_gss_svc_max_data_length
+.Nd "calculate maximum data size"
+.Sh SYNOPSIS
+.In rpc/rpcsec_gss.h
+.Ft int
+.Fn rpc_gss_svc_max_data_length "struct svc_req *req" "int max_tp_unit_len"
+.Sh DESCRIPTION
+Calculate the maximum message size that will fit into a packet of size
+.Fa max_tp_unit_len ,
+given the current service and QoP setting.
+.Sh PARAMETERS
+.Bl -tag -width ".It max_tp_unit_len"
+.It req
+An RPC request
+.It max_tp_unit_len
+Maximum packet size of the underlying transport protocol
+.El
+.Sh RETURN VALUES
+The maximum message size that can be encoded
+.Sh AVAILABILITY
+The
+.Fn rpc_gss_svc_max_data_length
+function is part of libtirpc.
+.Sh SEE ALSO
+.Xr rpc 3 ,
+.Xr gssapi 3 ,
+.Xr rpcsec_gss 3
+.Sh AUTHORS
+This
+manual page was written by
+.An Doug Rabson Aq dfr@FreeBSD.org .
diff --git a/src/svc_auth_gss.c b/src/svc_auth_gss.c
index 155c8de..f5165b5 100644
--- a/src/svc_auth_gss.c
+++ b/src/svc_auth_gss.c
@@ -34,14 +34,28 @@
*/
+#include <sys/types.h>
+
+#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+
#include <rpc/rpc.h>
-#include <gssapi/gssapi.h>
+#include <rpc/rpcsec_gss.h>
+
+#include <gssapi/gssapi_ext.h>
+
+#define UNUSED(x) UNUSED_ ## x __attribute__((unused))
extern SVCAUTH svc_auth_none;
+/* Internal only */
+bool_t rpc_gss_oid_to_mech(rpc_gss_OID, char **);
+bool_t rpc_gss_num_to_qop(char *, u_int, char **);
+
/*
* from mit-krb5-1.2.1 mechglue/mglueP.h:
* Array of context IDs typed by mechanism OID
@@ -73,6 +87,10 @@ struct svc_rpc_gss_data {
u_int seqlast; /* last sequence number */
u_int32_t seqmask; /* bitmask of seqnums */
gss_name_t client_name; /* unparsed name string */
+ rpc_gss_rawcred_t rcred; /* raw credential */
+ rpc_gss_ucred_t ucred; /* cooked credential */
+ gid_t gids[NGRPS]; /* list of groups */
+ void * cookie; /* callback cookie */
};
#define SVCAUTH_PRIVATE(auth) \
@@ -80,7 +98,8 @@ struct svc_rpc_gss_data {
/* Global server credentials. */
static gss_cred_id_t _svcauth_gss_creds;
-static gss_name_t _svcauth_gss_name = NULL;
+static gss_name_t _svcauth_gss_name = GSS_C_NO_NAME;
+static char * _svcauth_svc_name = NULL;
bool_t
svcauth_gss_set_svc_name(gss_name_t name)
@@ -89,7 +108,7 @@ svcauth_gss_set_svc_name(gss_name_t name)
gss_log_debug("in svcauth_gss_set_svc_name()");
- if (_svcauth_gss_name != NULL) {
+ if (_svcauth_gss_name != GSS_C_NO_NAME) {
maj_stat = gss_release_name(&min_stat, &_svcauth_gss_name);
if (maj_stat != GSS_S_COMPLETE) {
@@ -97,7 +116,7 @@ svcauth_gss_set_svc_name(gss_name_t name)
maj_stat, min_stat);
return (FALSE);
}
- _svcauth_gss_name = NULL;
+ _svcauth_gss_name = GSS_C_NO_NAME;
}
maj_stat = gss_duplicate_name(&min_stat, name, &_svcauth_gss_name);
@@ -138,14 +157,14 @@ svcauth_gss_import_name(char *service)
}
static bool_t
-svcauth_gss_acquire_cred(void)
+svcauth_gss_acquire_cred(u_int req_time, gss_OID_set_desc *oid_set)
{
OM_uint32 maj_stat, min_stat;
gss_log_debug("in svcauth_gss_acquire_cred()");
- maj_stat = gss_acquire_cred(&min_stat, _svcauth_gss_name, 0,
- GSS_C_NULL_OID_SET, GSS_C_ACCEPT,
+ maj_stat = gss_acquire_cred(&min_stat, _svcauth_gss_name, req_time,
+ oid_set, GSS_C_ACCEPT,
&_svcauth_gss_creds, NULL, NULL);
if (maj_stat != GSS_S_COMPLETE) {
@@ -176,6 +195,52 @@ svcauth_gss_release_cred(void)
return (TRUE);
}
+static rpc_gss_service_t
+_rpc_gss_svc_to_service(rpc_gss_svc_t svc)
+{
+ switch (svc) {
+ case RPCSEC_GSS_SVC_NONE:
+ return rpcsec_gss_svc_none;
+ case RPCSEC_GSS_SVC_INTEGRITY:
+ return rpcsec_gss_svc_integrity;
+ case RPCSEC_GSS_SVC_PRIVACY:
+ return rpcsec_gss_svc_privacy;
+ }
+ return rpcsec_gss_svc_default;
+}
+
+static bool_t
+_rpc_gss_fill_in_creds(struct svc_rpc_gss_data *gd, struct rpc_gss_cred *gc)
+{
+ rpc_gss_rawcred_t *rcred = &gd->rcred;
+ OM_uint32 maj_stat, min_stat;
+ gss_buffer_desc buf;
+
+ rcred->version = gc->gc_v;
+ if (!rpc_gss_oid_to_mech(gd->sec.mech, &rcred->mechanism))
+ return FALSE;
+ rcred->service = _rpc_gss_svc_to_service(gd->sec.svc);
+ maj_stat = gss_export_name(&min_stat, gd->client_name, &buf);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_export_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ rcred->client_principal = calloc(1, sizeof(rpc_gss_principal_t) +
+ buf.length);
+ if (rcred->client_principal == NULL) {
+ (void)gss_release_buffer(&min_stat, &buf);
+ return FALSE;
+ }
+ rcred->client_principal->len = buf.length;
+ (void)memcpy(rcred->client_principal->name, buf.value, buf.length);
+ (void)gss_release_buffer(&min_stat, &buf);
+
+ rcred->svc_principal = _svcauth_svc_name;
+
+ return TRUE;
+}
+
static bool_t
svcauth_gss_accept_sec_context(struct svc_req *rqst,
struct rpc_gss_init_res *gr)
@@ -248,6 +313,9 @@ svcauth_gss_accept_sec_context(struct svc_req *rqst,
maj_stat, min_stat);
return (FALSE);
}
+ if (!_rpc_gss_fill_in_creds(gd, gc))
+ return (FALSE);
+
#ifdef HAVE_KRB5
{
gss_buffer_desc mechname;
@@ -460,12 +528,12 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch)
if (rqst->rq_proc != NULLPROC)
return (AUTH_FAILED); /* XXX ? */
- if (_svcauth_gss_name == NULL) {
+ if (_svcauth_gss_name == GSS_C_NO_NAME) {
if (!svcauth_gss_import_name("nfs"))
return (AUTH_FAILED);
}
- if (!svcauth_gss_acquire_cred())
+ if (!svcauth_gss_acquire_cred(0, GSS_C_NULL_OID_SET))
return (AUTH_FAILED);
if (!svcauth_gss_accept_sec_context(rqst, &gr))
@@ -535,6 +603,8 @@ svcauth_gss_destroy(SVCAUTH *auth)
if (gd->client_name)
gss_release_name(&min_stat, &gd->client_name);
+ if (gd->rcred.client_principal != NULL)
+ free(gd->rcred.client_principal);
mem_free(gd, sizeof(*gd));
mem_free(auth, sizeof(*auth));
@@ -595,3 +665,285 @@ svcauth_gss_get_principal(SVCAUTH *auth)
return (pname);
}
+
+/*
+ * External API: Return maximum data size for a security mechanism and transport
+ *
+ * rqst: an incoming RPC request
+ * maxlen: transport's maximum data size, in bytes
+ *
+ * Returns maximum data size given transformations done by current
+ * security setting of "auth", in bytes, or zero if that value
+ * cannot be determined.
+ */
+int
+rpc_gss_svc_max_data_length(struct svc_req *rqst, int maxlen)
+{
+ OM_uint32 max_input_size, maj_stat, min_stat;
+ struct svc_rpc_gss_data *gd;
+ int conf_req_flag;
+ int result;
+
+ if (!rqst)
+ return 0;
+
+ gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth);
+
+ switch (gd->rcred.service) {
+ case rpcsec_gss_svc_none:
+ return maxlen;
+ case rpcsec_gss_svc_default:
+ case rpcsec_gss_svc_integrity:
+ conf_req_flag = 0;
+ break;
+ case rpcsec_gss_svc_privacy:
+ conf_req_flag = 1;
+ break;
+ default:
+ return 0;
+ }
+
+ result = 0;
+ maj_stat = gss_wrap_size_limit(&min_stat, gd->ctx, conf_req_flag,
+ gd->sec.qop, maxlen, &max_input_size);
+ if (maj_stat == GSS_S_COMPLETE)
+ if ((int)max_input_size > 0)
+ result = (int)max_input_size;
+ return result;
+}
+
+/*
+ * External API: Set server's GSS principal
+ *
+ * principal: NUL-terminated C string containing GSS principal
+ * mechanism: NUL-terminated C string containing GSS mechanism name
+ * req_time: time in seconds until credential expires
+ * program: program number of the RPC service
+ * version: version number of the RPC service
+ *
+ * Returns TRUE if successful, otherwise FALSE is returned.
+ */
+bool_t
+rpc_gss_set_svc_name(char *principal, char *mechanism, u_int req_time,
+ u_int UNUSED(program), u_int UNUSED(version))
+{
+ gss_OID_set_desc oid_set;
+ rpc_gss_OID oid;
+ char *save;
+
+ if (principal == NULL)
+ return FALSE;
+ save = strdup(principal);
+ if (save == NULL)
+ return FALSE;
+
+ if (!rpc_gss_mech_to_oid(mechanism, &oid))
+ goto out_err;
+ oid_set.count = 1;
+ oid_set.elements = (gss_OID)oid;
+
+ if (!svcauth_gss_import_name(principal))
+ goto out_err;
+ if (!svcauth_gss_acquire_cred(req_time, &oid_set))
+ goto out_err;
+
+ free(_svcauth_svc_name);
+ _svcauth_svc_name = save;
+ return TRUE;
+
+out_err:
+ free(save);
+ return FALSE;
+}
+
+static void
+_rpc_gss_fill_in_ucreds(struct svc_rpc_gss_data *gd)
+{
+ rpc_gss_ucred_t *ucred = &gd->ucred;
+ OM_uint32 maj_stat, min_stat;
+ struct passwd pwd, *pw;
+ long buflen;
+ uid_t uid;
+ char *buf;
+ int len;
+
+ /* default: "nfsnobody" */
+ ucred->uid = 65534;
+ ucred->gid = 65534;
+ ucred->gidlen = 0;
+ ucred->gidlist = gd->gids;
+
+ maj_stat = gss_pname_to_uid(&min_stat, gd->client_name,
+ gd->sec.mech, &uid);
+ if (maj_stat != GSS_S_COMPLETE)
+ return;
+
+ buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (buflen == -1)
+ return;
+ buf = malloc((size_t)buflen);
+ if (buf == NULL)
+ return;
+
+ (void)getpwuid_r(uid, &pwd, buf, buflen, &pw);
+ if (pw == NULL) {
+ free(buf);
+ return;
+ }
+
+ ucred->uid = pw->pw_uid;
+ ucred->gid = pw->pw_gid;
+ len = NGRPS;
+ (void)getgrouplist(pw->pw_name, pw->pw_gid, ucred->gidlist, &len);
+ ucred->gidlen = len;
+
+ free(buf);
+}
+
+/*
+ * External API: Retrieve requesting client's GSS credential
+ *
+ * rqst: an incoming RPC request
+ * rcred: address of pointer to fill in, or NULL
+ * ucred: address of pointer to fill in, or NULL
+ * cookie: address of pointer to fill in, or NULL
+ *
+ * Returns TRUE if successful. "rcred," "ucred," and "cookie"
+ * are filled in with pointers to the relevant structures.
+ * Caller must not free the memory returned by this API.
+ */
+bool_t
+rpc_gss_getcred(struct svc_req *rqst, rpc_gss_rawcred_t **rcred,
+ rpc_gss_ucred_t **ucred, void **cookie)
+{
+ struct svc_rpc_gss_data *gd;
+ SVCAUTH *auth;
+
+ if (rqst == NULL)
+ return FALSE;
+
+ if (rqst->rq_xprt->xp_verf.oa_flavor != RPCSEC_GSS)
+ return FALSE;
+
+ auth = rqst->rq_xprt->xp_auth;
+ gd = SVCAUTH_PRIVATE(auth);
+
+ if (rcred != NULL) {
+ auth->raw_cred = gd->rcred;
+ auth->raw_cred.service = _rpc_gss_svc_to_service(gd->sec.svc);
+ (void)rpc_gss_num_to_qop(auth->raw_cred.mechanism, gd->sec.qop,
+ &auth->raw_cred.qop);
+ *rcred = &auth->raw_cred;
+ }
+
+ if (ucred != NULL) {
+ _rpc_gss_fill_in_ucreds(gd);
+ *ucred = &gd->ucred;
+ }
+
+ if (cookie != NULL)
+ *cookie = gd->cookie;
+
+ return TRUE;
+}
+
+/*
+ * External API: Register a callback function
+ *
+ * callback: callback structure containing function and parameters
+ *
+ * Returns TRUE if successful, otherwise FALSE.
+ *
+ * "callback" is copied by rpc_gss_set_callback(), and may be freed
+ * immediately after it returns.
+ */
+bool_t
+rpc_gss_set_callback(rpc_gss_callback_t *callback)
+{
+ /* not yet supported */
+ return FALSE;
+}
+
+/*
+ * External API: Form a generic rpc_gss_principal
+ *
+ * principal: address of buffer to fill in
+ * mechanism: NUL-terminated C string containing GSS mechanism name
+ * user_name: NUL-terminated C string containing user or service principal
+ * node: NUL-terminated C string containing a hostname
+ * secdomain: NUL-terminated C string containing a security realm
+ *
+ * Returns TRUE if successful, otherwise FALSE. Caller must free
+ * returned "principal" with free(3).
+ */
+bool_t
+rpc_gss_get_principal_name(rpc_gss_principal_t *principal, char *mechanism,
+ char *user_name, char *node, char *secdomain)
+{
+ OM_uint32 maj_stat, min_stat;
+ rpc_gss_principal_t result;
+ size_t nodelen, secdomlen;
+ gss_name_t name, mechname;
+ gss_buffer_desc namebuf;
+ rpc_gss_OID oid;
+
+
+ if (principal == NULL || user_name == NULL || strlen(user_name) == 0)
+ return FALSE;
+ if (!rpc_gss_mech_to_oid(mechanism, &oid))
+ return FALSE;
+
+ nodelen = 0;
+ if (node != NULL)
+ nodelen = strlen(node) + 1;
+ secdomlen = 0;
+ if (secdomain != NULL)
+ secdomlen = strlen(secdomain) + 1;
+ namebuf.length = strlen(user_name) + nodelen + secdomlen;
+ namebuf.value = calloc(1, namebuf.length);
+ if (namebuf.value == NULL)
+ return FALSE;
+ (void)strcpy(namebuf.value, user_name);
+ if (nodelen > 0) {
+ (void)strcat(namebuf.value, "/");
+ (void)strcat(namebuf.value, node);
+ }
+ if (secdomlen > 0) {
+ (void)strcat(namebuf.value, "@");
+ (void)strcat(namebuf.value, secdomain);
+ }
+
+ maj_stat = gss_import_name(&min_stat, &namebuf,
+ GSS_C_NT_USER_NAME, &name);
+ free(namebuf.value);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_import_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ maj_stat = gss_canonicalize_name(&min_stat, name, oid, &mechname);
+ (void)gss_release_name(&min_stat, &name);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_canonicalize_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ maj_stat = gss_export_name(&min_stat, mechname, &namebuf);
+ (void)gss_release_name(&min_stat, &mechname);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_log_status("gss_export_name", maj_stat, min_stat);
+ return FALSE;
+ }
+
+ result = calloc(1, sizeof(*result) + namebuf.length);
+ if (result == NULL) {
+ (void)gss_release_buffer(&min_stat, &namebuf);
+ return FALSE;
+ }
+ result->len = namebuf.length;
+ (void)memcpy(result->name, namebuf.value, namebuf.length);
+ (void)gss_release_buffer(&min_stat, &namebuf);
+
+ *principal = result;
+ return TRUE;
+}