1a9148abdSDoug Rabson /*- 22e92ac56SJamie Gritton * Copyright (c) 2008 Doug Rabson 32e92ac56SJamie Gritton * All rights reserved. 4a9148abdSDoug Rabson * 5a9148abdSDoug Rabson * Redistribution and use in source and binary forms, with or without 6a9148abdSDoug Rabson * modification, are permitted provided that the following conditions 7a9148abdSDoug Rabson * are met: 8a9148abdSDoug Rabson * 1. Redistributions of source code must retain the above copyright 9a9148abdSDoug Rabson * notice, this list of conditions and the following disclaimer. 10a9148abdSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 11a9148abdSDoug Rabson * notice, this list of conditions and the following disclaimer in the 12a9148abdSDoug Rabson * documentation and/or other materials provided with the distribution. 13a9148abdSDoug Rabson * 142e92ac56SJamie Gritton * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15a9148abdSDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16a9148abdSDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172e92ac56SJamie Gritton * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18a9148abdSDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19a9148abdSDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20a9148abdSDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21a9148abdSDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22a9148abdSDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23a9148abdSDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24a9148abdSDoug Rabson * SUCH DAMAGE. 252e92ac56SJamie Gritton */ 262e92ac56SJamie Gritton /* 272e92ac56SJamie Gritton svc_rpcsec_gss.c 282e92ac56SJamie Gritton 292e92ac56SJamie Gritton Copyright (c) 2000 The Regents of the University of Michigan. 302e92ac56SJamie Gritton All rights reserved. 312e92ac56SJamie Gritton 322e92ac56SJamie Gritton Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 332e92ac56SJamie Gritton All rights reserved, all wrongs reversed. 342e92ac56SJamie Gritton 352e92ac56SJamie Gritton Redistribution and use in source and binary forms, with or without 362e92ac56SJamie Gritton modification, are permitted provided that the following conditions 372e92ac56SJamie Gritton are met: 382e92ac56SJamie Gritton 392e92ac56SJamie Gritton 1. Redistributions of source code must retain the above copyright 402e92ac56SJamie Gritton notice, this list of conditions and the following disclaimer. 412e92ac56SJamie Gritton 2. Redistributions in binary form must reproduce the above copyright 422e92ac56SJamie Gritton notice, this list of conditions and the following disclaimer in the 432e92ac56SJamie Gritton documentation and/or other materials provided with the distribution. 442e92ac56SJamie Gritton 3. Neither the name of the University nor the names of its 452e92ac56SJamie Gritton contributors may be used to endorse or promote products derived 462e92ac56SJamie Gritton from this software without specific prior written permission. 472e92ac56SJamie Gritton 482e92ac56SJamie Gritton THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 492e92ac56SJamie Gritton WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 502e92ac56SJamie Gritton MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 512e92ac56SJamie Gritton DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 522e92ac56SJamie Gritton FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 532e92ac56SJamie Gritton CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 542e92ac56SJamie Gritton SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 552e92ac56SJamie Gritton BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 562e92ac56SJamie Gritton LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 572e92ac56SJamie Gritton NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 582e92ac56SJamie Gritton SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 592e92ac56SJamie Gritton 602e92ac56SJamie Gritton $Id: svc_auth_gss.c,v 1.27 2002/01/15 15:43:00 andros Exp $ 61a9148abdSDoug Rabson */ 62a9148abdSDoug Rabson 63a9148abdSDoug Rabson #include <sys/cdefs.h> 64a9148abdSDoug Rabson __FBSDID("$FreeBSD$"); 65a9148abdSDoug Rabson 66a9148abdSDoug Rabson #include <sys/param.h> 672e92ac56SJamie Gritton #include <sys/systm.h> 68ae883d55SRick Macklem #include <sys/jail.h> 69a9148abdSDoug Rabson #include <sys/kernel.h> 702e92ac56SJamie Gritton #include <sys/kobj.h> 71a9148abdSDoug Rabson #include <sys/lock.h> 72a9148abdSDoug Rabson #include <sys/malloc.h> 73a9148abdSDoug Rabson #include <sys/mbuf.h> 74a9148abdSDoug Rabson #include <sys/mutex.h> 752e92ac56SJamie Gritton #include <sys/proc.h> 762e92ac56SJamie Gritton #include <sys/sx.h> 772e92ac56SJamie Gritton #include <sys/ucred.h> 78a9148abdSDoug Rabson 792e92ac56SJamie Gritton #include <rpc/rpc.h> 802e92ac56SJamie Gritton #include <rpc/rpcsec_gss.h> 81a9148abdSDoug Rabson 822e92ac56SJamie Gritton #include "rpcsec_gss_int.h" 83a9148abdSDoug Rabson 842e92ac56SJamie Gritton static bool_t svc_rpc_gss_wrap(SVCAUTH *, struct mbuf **); 852e92ac56SJamie Gritton static bool_t svc_rpc_gss_unwrap(SVCAUTH *, struct mbuf **); 862e92ac56SJamie Gritton static void svc_rpc_gss_release(SVCAUTH *); 872e92ac56SJamie Gritton static enum auth_stat svc_rpc_gss(struct svc_req *, struct rpc_msg *); 882e92ac56SJamie Gritton static int rpc_gss_svc_getcred(struct svc_req *, struct ucred **, int *); 89a9148abdSDoug Rabson 902e92ac56SJamie Gritton static struct svc_auth_ops svc_auth_gss_ops = { 912e92ac56SJamie Gritton svc_rpc_gss_wrap, 922e92ac56SJamie Gritton svc_rpc_gss_unwrap, 932e92ac56SJamie Gritton svc_rpc_gss_release, 94a9148abdSDoug Rabson }; 95a9148abdSDoug Rabson 962e92ac56SJamie Gritton struct sx svc_rpc_gss_lock; 972e92ac56SJamie Gritton 982e92ac56SJamie Gritton struct svc_rpc_gss_callback { 992e92ac56SJamie Gritton SLIST_ENTRY(svc_rpc_gss_callback) cb_link; 1002e92ac56SJamie Gritton rpc_gss_callback_t cb_callback; 1012e92ac56SJamie Gritton }; 1022e92ac56SJamie Gritton static SLIST_HEAD(svc_rpc_gss_callback_list, svc_rpc_gss_callback) 1032e92ac56SJamie Gritton svc_rpc_gss_callbacks = SLIST_HEAD_INITIALIZER(&svc_rpc_gss_callbacks); 1042e92ac56SJamie Gritton 1052e92ac56SJamie Gritton struct svc_rpc_gss_svc_name { 1062e92ac56SJamie Gritton SLIST_ENTRY(svc_rpc_gss_svc_name) sn_link; 1072e92ac56SJamie Gritton char *sn_principal; 1082e92ac56SJamie Gritton gss_OID sn_mech; 1092e92ac56SJamie Gritton u_int sn_req_time; 1102e92ac56SJamie Gritton gss_cred_id_t sn_cred; 1112e92ac56SJamie Gritton u_int sn_program; 1122e92ac56SJamie Gritton u_int sn_version; 1132e92ac56SJamie Gritton }; 1142e92ac56SJamie Gritton static SLIST_HEAD(svc_rpc_gss_svc_name_list, svc_rpc_gss_svc_name) 1152e92ac56SJamie Gritton svc_rpc_gss_svc_names = SLIST_HEAD_INITIALIZER(&svc_rpc_gss_svc_names); 1162e92ac56SJamie Gritton 1172e92ac56SJamie Gritton enum svc_rpc_gss_client_state { 1182e92ac56SJamie Gritton CLIENT_NEW, /* still authenticating */ 1192e92ac56SJamie Gritton CLIENT_ESTABLISHED, /* context established */ 1202e92ac56SJamie Gritton CLIENT_STALE /* garbage to collect */ 121d4468577SJamie Gritton }; 122a9148abdSDoug Rabson 1232e92ac56SJamie Gritton #define SVC_RPC_GSS_SEQWINDOW 128 1242e92ac56SJamie Gritton 1252e92ac56SJamie Gritton struct svc_rpc_gss_clientid { 1262e92ac56SJamie Gritton unsigned long ci_hostid; 1272e92ac56SJamie Gritton uint32_t ci_boottime; 1282e92ac56SJamie Gritton uint32_t ci_id; 1292e92ac56SJamie Gritton }; 1302e92ac56SJamie Gritton 1312e92ac56SJamie Gritton struct svc_rpc_gss_client { 1322e92ac56SJamie Gritton TAILQ_ENTRY(svc_rpc_gss_client) cl_link; 1332e92ac56SJamie Gritton TAILQ_ENTRY(svc_rpc_gss_client) cl_alllink; 1342e92ac56SJamie Gritton volatile u_int cl_refs; 1352e92ac56SJamie Gritton struct sx cl_lock; 1362e92ac56SJamie Gritton struct svc_rpc_gss_clientid cl_id; 1372e92ac56SJamie Gritton time_t cl_expiration; /* when to gc */ 1382e92ac56SJamie Gritton enum svc_rpc_gss_client_state cl_state; /* client state */ 1392e92ac56SJamie Gritton bool_t cl_locked; /* fixed service+qop */ 1402e92ac56SJamie Gritton gss_ctx_id_t cl_ctx; /* context id */ 1412e92ac56SJamie Gritton gss_cred_id_t cl_creds; /* delegated creds */ 1422e92ac56SJamie Gritton gss_name_t cl_cname; /* client name */ 1432e92ac56SJamie Gritton struct svc_rpc_gss_svc_name *cl_sname; /* server name used */ 1442e92ac56SJamie Gritton rpc_gss_rawcred_t cl_rawcred; /* raw credentials */ 1452e92ac56SJamie Gritton rpc_gss_ucred_t cl_ucred; /* unix-style credentials */ 1462e92ac56SJamie Gritton struct ucred *cl_cred; /* kernel-style credentials */ 1472e92ac56SJamie Gritton int cl_rpcflavor; /* RPC pseudo sec flavor */ 1482e92ac56SJamie Gritton bool_t cl_done_callback; /* TRUE after call */ 1492e92ac56SJamie Gritton void *cl_cookie; /* user cookie from callback */ 1502e92ac56SJamie Gritton gid_t cl_gid_storage[NGROUPS]; 1512e92ac56SJamie Gritton gss_OID cl_mech; /* mechanism */ 1522e92ac56SJamie Gritton gss_qop_t cl_qop; /* quality of protection */ 1532e92ac56SJamie Gritton uint32_t cl_seqlast; /* sequence window origin */ 1542e92ac56SJamie Gritton uint32_t cl_seqmask[SVC_RPC_GSS_SEQWINDOW/32]; /* bitmask of seqnums */ 1552e92ac56SJamie Gritton }; 1562e92ac56SJamie Gritton TAILQ_HEAD(svc_rpc_gss_client_list, svc_rpc_gss_client); 1572e92ac56SJamie Gritton 158a9148abdSDoug Rabson /* 1592e92ac56SJamie Gritton * This structure holds enough information to unwrap arguments or wrap 1602e92ac56SJamie Gritton * results for a given request. We use the rq_clntcred area for this 1612e92ac56SJamie Gritton * (which is a per-request buffer). 1622e92ac56SJamie Gritton */ 1632e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred { 1642e92ac56SJamie Gritton struct svc_rpc_gss_client *cc_client; 1652e92ac56SJamie Gritton rpc_gss_service_t cc_service; 1662e92ac56SJamie Gritton uint32_t cc_seq; 1672e92ac56SJamie Gritton }; 1682e92ac56SJamie Gritton 1692e92ac56SJamie Gritton #define CLIENT_HASH_SIZE 256 1702e92ac56SJamie Gritton #define CLIENT_MAX 128 1712e92ac56SJamie Gritton struct svc_rpc_gss_client_list svc_rpc_gss_client_hash[CLIENT_HASH_SIZE]; 1722e92ac56SJamie Gritton struct svc_rpc_gss_client_list svc_rpc_gss_clients; 1732e92ac56SJamie Gritton static size_t svc_rpc_gss_client_count; 1742e92ac56SJamie Gritton static uint32_t svc_rpc_gss_next_clientid = 1; 1752e92ac56SJamie Gritton 1762e92ac56SJamie Gritton static void 1772e92ac56SJamie Gritton svc_rpc_gss_init(void *arg) 1782e92ac56SJamie Gritton { 1792e92ac56SJamie Gritton int i; 1802e92ac56SJamie Gritton 1812e92ac56SJamie Gritton for (i = 0; i < CLIENT_HASH_SIZE; i++) 1822e92ac56SJamie Gritton TAILQ_INIT(&svc_rpc_gss_client_hash[i]); 1832e92ac56SJamie Gritton TAILQ_INIT(&svc_rpc_gss_clients); 1842e92ac56SJamie Gritton svc_auth_reg(RPCSEC_GSS, svc_rpc_gss, rpc_gss_svc_getcred); 1852e92ac56SJamie Gritton sx_init(&svc_rpc_gss_lock, "gsslock"); 1862e92ac56SJamie Gritton } 1872e92ac56SJamie Gritton SYSINIT(svc_rpc_gss_init, SI_SUB_KMEM, SI_ORDER_ANY, svc_rpc_gss_init, NULL); 1882e92ac56SJamie Gritton 1892e92ac56SJamie Gritton bool_t 1902e92ac56SJamie Gritton rpc_gss_set_callback(rpc_gss_callback_t *cb) 1912e92ac56SJamie Gritton { 1922e92ac56SJamie Gritton struct svc_rpc_gss_callback *scb; 1932e92ac56SJamie Gritton 1942e92ac56SJamie Gritton scb = mem_alloc(sizeof(struct svc_rpc_gss_callback)); 1952e92ac56SJamie Gritton if (!scb) { 1962e92ac56SJamie Gritton _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 1972e92ac56SJamie Gritton return (FALSE); 1982e92ac56SJamie Gritton } 1992e92ac56SJamie Gritton scb->cb_callback = *cb; 2002e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 2012e92ac56SJamie Gritton SLIST_INSERT_HEAD(&svc_rpc_gss_callbacks, scb, cb_link); 2022e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 2032e92ac56SJamie Gritton 2042e92ac56SJamie Gritton return (TRUE); 2052e92ac56SJamie Gritton } 2062e92ac56SJamie Gritton 2072e92ac56SJamie Gritton void 2082e92ac56SJamie Gritton rpc_gss_clear_callback(rpc_gss_callback_t *cb) 2092e92ac56SJamie Gritton { 2102e92ac56SJamie Gritton struct svc_rpc_gss_callback *scb; 2112e92ac56SJamie Gritton 2122e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 2132e92ac56SJamie Gritton SLIST_FOREACH(scb, &svc_rpc_gss_callbacks, cb_link) { 2142e92ac56SJamie Gritton if (scb->cb_callback.program == cb->program 2152e92ac56SJamie Gritton && scb->cb_callback.version == cb->version 2162e92ac56SJamie Gritton && scb->cb_callback.callback == cb->callback) { 2172e92ac56SJamie Gritton SLIST_REMOVE(&svc_rpc_gss_callbacks, scb, 2182e92ac56SJamie Gritton svc_rpc_gss_callback, cb_link); 2192e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 2202e92ac56SJamie Gritton mem_free(scb, sizeof(*scb)); 2212e92ac56SJamie Gritton return; 2222e92ac56SJamie Gritton } 2232e92ac56SJamie Gritton } 2242e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 2252e92ac56SJamie Gritton } 2262e92ac56SJamie Gritton 2272e92ac56SJamie Gritton static bool_t 2282e92ac56SJamie Gritton rpc_gss_acquire_svc_cred(struct svc_rpc_gss_svc_name *sname) 2292e92ac56SJamie Gritton { 2302e92ac56SJamie Gritton OM_uint32 maj_stat, min_stat; 2312e92ac56SJamie Gritton gss_buffer_desc namebuf; 2322e92ac56SJamie Gritton gss_name_t name; 2332e92ac56SJamie Gritton gss_OID_set_desc oid_set; 2342e92ac56SJamie Gritton 2352e92ac56SJamie Gritton oid_set.count = 1; 2362e92ac56SJamie Gritton oid_set.elements = sname->sn_mech; 2372e92ac56SJamie Gritton 2382e92ac56SJamie Gritton namebuf.value = (void *) sname->sn_principal; 2392e92ac56SJamie Gritton namebuf.length = strlen(sname->sn_principal); 2402e92ac56SJamie Gritton 2412e92ac56SJamie Gritton maj_stat = gss_import_name(&min_stat, &namebuf, 2422e92ac56SJamie Gritton GSS_C_NT_HOSTBASED_SERVICE, &name); 2432e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) 2442e92ac56SJamie Gritton return (FALSE); 2452e92ac56SJamie Gritton 2462e92ac56SJamie Gritton if (sname->sn_cred != GSS_C_NO_CREDENTIAL) 2472e92ac56SJamie Gritton gss_release_cred(&min_stat, &sname->sn_cred); 2482e92ac56SJamie Gritton 2492e92ac56SJamie Gritton maj_stat = gss_acquire_cred(&min_stat, name, 2502e92ac56SJamie Gritton sname->sn_req_time, &oid_set, GSS_C_ACCEPT, &sname->sn_cred, 2512e92ac56SJamie Gritton NULL, NULL); 2522e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 2532e92ac56SJamie Gritton gss_release_name(&min_stat, &name); 2542e92ac56SJamie Gritton return (FALSE); 2552e92ac56SJamie Gritton } 2562e92ac56SJamie Gritton gss_release_name(&min_stat, &name); 2572e92ac56SJamie Gritton 2582e92ac56SJamie Gritton return (TRUE); 2592e92ac56SJamie Gritton } 2602e92ac56SJamie Gritton 2612e92ac56SJamie Gritton bool_t 2622e92ac56SJamie Gritton rpc_gss_set_svc_name(const char *principal, const char *mechanism, 2632e92ac56SJamie Gritton u_int req_time, u_int program, u_int version) 2642e92ac56SJamie Gritton { 2652e92ac56SJamie Gritton struct svc_rpc_gss_svc_name *sname; 2662e92ac56SJamie Gritton gss_OID mech_oid; 2672e92ac56SJamie Gritton 2682e92ac56SJamie Gritton if (!rpc_gss_mech_to_oid(mechanism, &mech_oid)) 2692e92ac56SJamie Gritton return (FALSE); 2702e92ac56SJamie Gritton 2712e92ac56SJamie Gritton sname = mem_alloc(sizeof(*sname)); 2722e92ac56SJamie Gritton if (!sname) 2732e92ac56SJamie Gritton return (FALSE); 2742e92ac56SJamie Gritton sname->sn_principal = strdup(principal, M_RPC); 2752e92ac56SJamie Gritton sname->sn_mech = mech_oid; 2762e92ac56SJamie Gritton sname->sn_req_time = req_time; 2772e92ac56SJamie Gritton sname->sn_cred = GSS_C_NO_CREDENTIAL; 2782e92ac56SJamie Gritton sname->sn_program = program; 2792e92ac56SJamie Gritton sname->sn_version = version; 2802e92ac56SJamie Gritton 2812e92ac56SJamie Gritton if (!rpc_gss_acquire_svc_cred(sname)) { 2822e92ac56SJamie Gritton free(sname->sn_principal, M_RPC); 2832e92ac56SJamie Gritton mem_free(sname, sizeof(*sname)); 2842e92ac56SJamie Gritton return (FALSE); 2852e92ac56SJamie Gritton } 2862e92ac56SJamie Gritton 2872e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 2882e92ac56SJamie Gritton SLIST_INSERT_HEAD(&svc_rpc_gss_svc_names, sname, sn_link); 2892e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 2902e92ac56SJamie Gritton 2912e92ac56SJamie Gritton return (TRUE); 2922e92ac56SJamie Gritton } 2932e92ac56SJamie Gritton 2942e92ac56SJamie Gritton void 2952e92ac56SJamie Gritton rpc_gss_clear_svc_name(u_int program, u_int version) 2962e92ac56SJamie Gritton { 2972e92ac56SJamie Gritton OM_uint32 min_stat; 2982e92ac56SJamie Gritton struct svc_rpc_gss_svc_name *sname; 2992e92ac56SJamie Gritton 3002e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 3012e92ac56SJamie Gritton SLIST_FOREACH(sname, &svc_rpc_gss_svc_names, sn_link) { 3022e92ac56SJamie Gritton if (sname->sn_program == program 3032e92ac56SJamie Gritton && sname->sn_version == version) { 3042e92ac56SJamie Gritton SLIST_REMOVE(&svc_rpc_gss_svc_names, sname, 3052e92ac56SJamie Gritton svc_rpc_gss_svc_name, sn_link); 3062e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 3072e92ac56SJamie Gritton gss_release_cred(&min_stat, &sname->sn_cred); 3082e92ac56SJamie Gritton free(sname->sn_principal, M_RPC); 3092e92ac56SJamie Gritton mem_free(sname, sizeof(*sname)); 3102e92ac56SJamie Gritton return; 3112e92ac56SJamie Gritton } 3122e92ac56SJamie Gritton } 3132e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 3142e92ac56SJamie Gritton } 3152e92ac56SJamie Gritton 3162e92ac56SJamie Gritton bool_t 3172e92ac56SJamie Gritton rpc_gss_get_principal_name(rpc_gss_principal_t *principal, 3182e92ac56SJamie Gritton const char *mech, const char *name, const char *node, const char *domain) 3192e92ac56SJamie Gritton { 3202e92ac56SJamie Gritton OM_uint32 maj_stat, min_stat; 3212e92ac56SJamie Gritton gss_OID mech_oid; 3222e92ac56SJamie Gritton size_t namelen; 3232e92ac56SJamie Gritton gss_buffer_desc buf; 3242e92ac56SJamie Gritton gss_name_t gss_name, gss_mech_name; 3252e92ac56SJamie Gritton rpc_gss_principal_t result; 3262e92ac56SJamie Gritton 3272e92ac56SJamie Gritton if (!rpc_gss_mech_to_oid(mech, &mech_oid)) 3282e92ac56SJamie Gritton return (FALSE); 3292e92ac56SJamie Gritton 3302e92ac56SJamie Gritton /* 3312e92ac56SJamie Gritton * Construct a gss_buffer containing the full name formatted 3322e92ac56SJamie Gritton * as "name/node@domain" where node and domain are optional. 3332e92ac56SJamie Gritton */ 3342e92ac56SJamie Gritton namelen = strlen(name); 3352e92ac56SJamie Gritton if (node) { 3362e92ac56SJamie Gritton namelen += strlen(node) + 1; 3372e92ac56SJamie Gritton } 3382e92ac56SJamie Gritton if (domain) { 3392e92ac56SJamie Gritton namelen += strlen(domain) + 1; 3402e92ac56SJamie Gritton } 3412e92ac56SJamie Gritton 3422e92ac56SJamie Gritton buf.value = mem_alloc(namelen); 3432e92ac56SJamie Gritton buf.length = namelen; 3442e92ac56SJamie Gritton strcpy((char *) buf.value, name); 3452e92ac56SJamie Gritton if (node) { 3462e92ac56SJamie Gritton strcat((char *) buf.value, "/"); 3472e92ac56SJamie Gritton strcat((char *) buf.value, node); 3482e92ac56SJamie Gritton } 3492e92ac56SJamie Gritton if (domain) { 3502e92ac56SJamie Gritton strcat((char *) buf.value, "@"); 3512e92ac56SJamie Gritton strcat((char *) buf.value, domain); 3522e92ac56SJamie Gritton } 3532e92ac56SJamie Gritton 3542e92ac56SJamie Gritton /* 3552e92ac56SJamie Gritton * Convert that to a gss_name_t and then convert that to a 3562e92ac56SJamie Gritton * mechanism name in the selected mechanism. 3572e92ac56SJamie Gritton */ 3582e92ac56SJamie Gritton maj_stat = gss_import_name(&min_stat, &buf, 3592e92ac56SJamie Gritton GSS_C_NT_USER_NAME, &gss_name); 3602e92ac56SJamie Gritton mem_free(buf.value, buf.length); 3612e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 3622e92ac56SJamie Gritton rpc_gss_log_status("gss_import_name", mech_oid, maj_stat, min_stat); 3632e92ac56SJamie Gritton return (FALSE); 3642e92ac56SJamie Gritton } 3652e92ac56SJamie Gritton maj_stat = gss_canonicalize_name(&min_stat, gss_name, mech_oid, 3662e92ac56SJamie Gritton &gss_mech_name); 3672e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 3682e92ac56SJamie Gritton rpc_gss_log_status("gss_canonicalize_name", mech_oid, maj_stat, 3692e92ac56SJamie Gritton min_stat); 3702e92ac56SJamie Gritton gss_release_name(&min_stat, &gss_name); 3712e92ac56SJamie Gritton return (FALSE); 3722e92ac56SJamie Gritton } 3732e92ac56SJamie Gritton gss_release_name(&min_stat, &gss_name); 3742e92ac56SJamie Gritton 3752e92ac56SJamie Gritton /* 3762e92ac56SJamie Gritton * Export the mechanism name and use that to construct the 3772e92ac56SJamie Gritton * rpc_gss_principal_t result. 3782e92ac56SJamie Gritton */ 3792e92ac56SJamie Gritton maj_stat = gss_export_name(&min_stat, gss_mech_name, &buf); 3802e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 3812e92ac56SJamie Gritton rpc_gss_log_status("gss_export_name", mech_oid, maj_stat, min_stat); 3822e92ac56SJamie Gritton gss_release_name(&min_stat, &gss_mech_name); 3832e92ac56SJamie Gritton return (FALSE); 3842e92ac56SJamie Gritton } 3852e92ac56SJamie Gritton gss_release_name(&min_stat, &gss_mech_name); 3862e92ac56SJamie Gritton 3872e92ac56SJamie Gritton result = mem_alloc(sizeof(int) + buf.length); 3882e92ac56SJamie Gritton if (!result) { 3892e92ac56SJamie Gritton gss_release_buffer(&min_stat, &buf); 3902e92ac56SJamie Gritton return (FALSE); 3912e92ac56SJamie Gritton } 3922e92ac56SJamie Gritton result->len = buf.length; 3932e92ac56SJamie Gritton memcpy(result->name, buf.value, buf.length); 3942e92ac56SJamie Gritton gss_release_buffer(&min_stat, &buf); 3952e92ac56SJamie Gritton 3962e92ac56SJamie Gritton *principal = result; 3972e92ac56SJamie Gritton return (TRUE); 3982e92ac56SJamie Gritton } 3992e92ac56SJamie Gritton 4002e92ac56SJamie Gritton bool_t 4012e92ac56SJamie Gritton rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred, 4022e92ac56SJamie Gritton rpc_gss_ucred_t **ucred, void **cookie) 4032e92ac56SJamie Gritton { 4042e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc; 4052e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 4062e92ac56SJamie Gritton 4072e92ac56SJamie Gritton if (req->rq_cred.oa_flavor != RPCSEC_GSS) 4082e92ac56SJamie Gritton return (FALSE); 4092e92ac56SJamie Gritton 4102e92ac56SJamie Gritton cc = req->rq_clntcred; 4112e92ac56SJamie Gritton client = cc->cc_client; 4122e92ac56SJamie Gritton if (rcred) 4132e92ac56SJamie Gritton *rcred = &client->cl_rawcred; 4142e92ac56SJamie Gritton if (ucred) 4152e92ac56SJamie Gritton *ucred = &client->cl_ucred; 4162e92ac56SJamie Gritton if (cookie) 4172e92ac56SJamie Gritton *cookie = client->cl_cookie; 4182e92ac56SJamie Gritton return (TRUE); 4192e92ac56SJamie Gritton } 4202e92ac56SJamie Gritton 4212e92ac56SJamie Gritton /* 4222e92ac56SJamie Gritton * This simpler interface is used by svc_getcred to copy the cred data 4232e92ac56SJamie Gritton * into a kernel cred structure. 424a9148abdSDoug Rabson */ 425a9148abdSDoug Rabson static int 4262e92ac56SJamie Gritton rpc_gss_svc_getcred(struct svc_req *req, struct ucred **crp, int *flavorp) 427a9148abdSDoug Rabson { 4282e92ac56SJamie Gritton struct ucred *cr; 4292e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc; 4302e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 4312e92ac56SJamie Gritton rpc_gss_ucred_t *uc; 432a9148abdSDoug Rabson 4332e92ac56SJamie Gritton if (req->rq_cred.oa_flavor != RPCSEC_GSS) 4342e92ac56SJamie Gritton return (FALSE); 4352e92ac56SJamie Gritton 4362e92ac56SJamie Gritton cc = req->rq_clntcred; 4372e92ac56SJamie Gritton client = cc->cc_client; 4382e92ac56SJamie Gritton 4392e92ac56SJamie Gritton if (flavorp) 4402e92ac56SJamie Gritton *flavorp = client->cl_rpcflavor; 4412e92ac56SJamie Gritton 4422e92ac56SJamie Gritton if (client->cl_cred) { 4432e92ac56SJamie Gritton *crp = crhold(client->cl_cred); 4442e92ac56SJamie Gritton return (TRUE); 445a9148abdSDoug Rabson } 446a9148abdSDoug Rabson 4472e92ac56SJamie Gritton uc = &client->cl_ucred; 4482e92ac56SJamie Gritton cr = client->cl_cred = crget(); 4492e92ac56SJamie Gritton cr->cr_uid = cr->cr_ruid = cr->cr_svuid = uc->uid; 4502e92ac56SJamie Gritton cr->cr_rgid = cr->cr_svgid = uc->gid; 4512e92ac56SJamie Gritton crsetgroups(cr, uc->gidlen, uc->gidlist); 4522e92ac56SJamie Gritton *crp = crhold(cr); 4532e92ac56SJamie Gritton 4542e92ac56SJamie Gritton return (TRUE); 455a9148abdSDoug Rabson } 4562e92ac56SJamie Gritton 4572e92ac56SJamie Gritton int 4582e92ac56SJamie Gritton rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len) 4592e92ac56SJamie Gritton { 4602e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc = req->rq_clntcred; 4612e92ac56SJamie Gritton struct svc_rpc_gss_client *client = cc->cc_client; 4622e92ac56SJamie Gritton int want_conf; 4632e92ac56SJamie Gritton OM_uint32 max; 4642e92ac56SJamie Gritton OM_uint32 maj_stat, min_stat; 4652e92ac56SJamie Gritton int result; 4662e92ac56SJamie Gritton 4672e92ac56SJamie Gritton switch (client->cl_rawcred.service) { 4682e92ac56SJamie Gritton case rpc_gss_svc_none: 4692e92ac56SJamie Gritton return (max_tp_unit_len); 4702e92ac56SJamie Gritton break; 4712e92ac56SJamie Gritton 4722e92ac56SJamie Gritton case rpc_gss_svc_default: 4732e92ac56SJamie Gritton case rpc_gss_svc_integrity: 4742e92ac56SJamie Gritton want_conf = FALSE; 4752e92ac56SJamie Gritton break; 4762e92ac56SJamie Gritton 4772e92ac56SJamie Gritton case rpc_gss_svc_privacy: 4782e92ac56SJamie Gritton want_conf = TRUE; 4792e92ac56SJamie Gritton break; 4802e92ac56SJamie Gritton 4812e92ac56SJamie Gritton default: 482a9148abdSDoug Rabson return (0); 483a9148abdSDoug Rabson } 484a9148abdSDoug Rabson 4852e92ac56SJamie Gritton maj_stat = gss_wrap_size_limit(&min_stat, client->cl_ctx, want_conf, 4862e92ac56SJamie Gritton client->cl_qop, max_tp_unit_len, &max); 4872e92ac56SJamie Gritton 4882e92ac56SJamie Gritton if (maj_stat == GSS_S_COMPLETE) { 4892e92ac56SJamie Gritton result = (int) max; 4902e92ac56SJamie Gritton if (result < 0) 4912e92ac56SJamie Gritton result = 0; 4922e92ac56SJamie Gritton return (result); 4932e92ac56SJamie Gritton } else { 4942e92ac56SJamie Gritton rpc_gss_log_status("gss_wrap_size_limit", client->cl_mech, 4952e92ac56SJamie Gritton maj_stat, min_stat); 4962e92ac56SJamie Gritton return (0); 4972e92ac56SJamie Gritton } 4982e92ac56SJamie Gritton } 4992e92ac56SJamie Gritton 5002e92ac56SJamie Gritton static struct svc_rpc_gss_client * 5012e92ac56SJamie Gritton svc_rpc_gss_find_client(struct svc_rpc_gss_clientid *id) 5022e92ac56SJamie Gritton { 5032e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 5042e92ac56SJamie Gritton struct svc_rpc_gss_client_list *list; 5052e92ac56SJamie Gritton unsigned long hostid; 5062e92ac56SJamie Gritton 5072e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_find_client(%d)", id->ci_id); 5082e92ac56SJamie Gritton 5092e92ac56SJamie Gritton getcredhostid(curthread->td_ucred, &hostid); 5102e92ac56SJamie Gritton if (id->ci_hostid != hostid || id->ci_boottime != boottime.tv_sec) 5112e92ac56SJamie Gritton return (NULL); 5122e92ac56SJamie Gritton 5132e92ac56SJamie Gritton list = &svc_rpc_gss_client_hash[id->ci_id % CLIENT_HASH_SIZE]; 5142e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 5152e92ac56SJamie Gritton TAILQ_FOREACH(client, list, cl_link) { 5162e92ac56SJamie Gritton if (client->cl_id.ci_id == id->ci_id) { 5172e92ac56SJamie Gritton /* 5182e92ac56SJamie Gritton * Move this client to the front of the LRU 5192e92ac56SJamie Gritton * list. 5202e92ac56SJamie Gritton */ 5212e92ac56SJamie Gritton TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); 5222e92ac56SJamie Gritton TAILQ_INSERT_HEAD(&svc_rpc_gss_clients, client, 5232e92ac56SJamie Gritton cl_alllink); 5242e92ac56SJamie Gritton refcount_acquire(&client->cl_refs); 5252e92ac56SJamie Gritton break; 5262e92ac56SJamie Gritton } 5272e92ac56SJamie Gritton } 5282e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 5292e92ac56SJamie Gritton 5302e92ac56SJamie Gritton return (client); 5312e92ac56SJamie Gritton } 5322e92ac56SJamie Gritton 5332e92ac56SJamie Gritton static struct svc_rpc_gss_client * 5342e92ac56SJamie Gritton svc_rpc_gss_create_client(void) 5352e92ac56SJamie Gritton { 5362e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 5372e92ac56SJamie Gritton struct svc_rpc_gss_client_list *list; 5382e92ac56SJamie Gritton unsigned long hostid; 5392e92ac56SJamie Gritton 5402e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_create_client()"); 5412e92ac56SJamie Gritton 5422e92ac56SJamie Gritton client = mem_alloc(sizeof(struct svc_rpc_gss_client)); 5432e92ac56SJamie Gritton memset(client, 0, sizeof(struct svc_rpc_gss_client)); 5442e92ac56SJamie Gritton refcount_init(&client->cl_refs, 1); 5452e92ac56SJamie Gritton sx_init(&client->cl_lock, "GSS-client"); 5462e92ac56SJamie Gritton getcredhostid(curthread->td_ucred, &hostid); 5472e92ac56SJamie Gritton client->cl_id.ci_hostid = hostid; 5482e92ac56SJamie Gritton client->cl_id.ci_boottime = boottime.tv_sec; 5492e92ac56SJamie Gritton client->cl_id.ci_id = svc_rpc_gss_next_clientid++; 5502e92ac56SJamie Gritton list = &svc_rpc_gss_client_hash[client->cl_id.ci_id % CLIENT_HASH_SIZE]; 5512e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 5522e92ac56SJamie Gritton TAILQ_INSERT_HEAD(list, client, cl_link); 5532e92ac56SJamie Gritton TAILQ_INSERT_HEAD(&svc_rpc_gss_clients, client, cl_alllink); 5542e92ac56SJamie Gritton svc_rpc_gss_client_count++; 5552e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 5562e92ac56SJamie Gritton 5572e92ac56SJamie Gritton /* 5582e92ac56SJamie Gritton * Start the client off with a short expiration time. We will 5592e92ac56SJamie Gritton * try to get a saner value from the client creds later. 5602e92ac56SJamie Gritton */ 5612e92ac56SJamie Gritton client->cl_state = CLIENT_NEW; 5622e92ac56SJamie Gritton client->cl_locked = FALSE; 5632e92ac56SJamie Gritton client->cl_expiration = time_uptime + 5*60; 5642e92ac56SJamie Gritton 5652e92ac56SJamie Gritton return (client); 5662e92ac56SJamie Gritton } 5672e92ac56SJamie Gritton 5682e92ac56SJamie Gritton static void 5692e92ac56SJamie Gritton svc_rpc_gss_destroy_client(struct svc_rpc_gss_client *client) 5702e92ac56SJamie Gritton { 5712e92ac56SJamie Gritton OM_uint32 min_stat; 5722e92ac56SJamie Gritton 5732e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_destroy_client()"); 5742e92ac56SJamie Gritton 5752e92ac56SJamie Gritton if (client->cl_ctx) 5762e92ac56SJamie Gritton gss_delete_sec_context(&min_stat, 5772e92ac56SJamie Gritton &client->cl_ctx, GSS_C_NO_BUFFER); 5782e92ac56SJamie Gritton 5792e92ac56SJamie Gritton if (client->cl_cname) 5802e92ac56SJamie Gritton gss_release_name(&min_stat, &client->cl_cname); 5812e92ac56SJamie Gritton 5822e92ac56SJamie Gritton if (client->cl_rawcred.client_principal) 5832e92ac56SJamie Gritton mem_free(client->cl_rawcred.client_principal, 5842e92ac56SJamie Gritton sizeof(*client->cl_rawcred.client_principal) 5852e92ac56SJamie Gritton + client->cl_rawcred.client_principal->len); 5862e92ac56SJamie Gritton 5872e92ac56SJamie Gritton if (client->cl_cred) 5882e92ac56SJamie Gritton crfree(client->cl_cred); 5892e92ac56SJamie Gritton 5902e92ac56SJamie Gritton sx_destroy(&client->cl_lock); 5912e92ac56SJamie Gritton mem_free(client, sizeof(*client)); 5922e92ac56SJamie Gritton } 5932e92ac56SJamie Gritton 5942e92ac56SJamie Gritton /* 5952e92ac56SJamie Gritton * Drop a reference to a client and free it if that was the last reference. 5962e92ac56SJamie Gritton */ 5972e92ac56SJamie Gritton static void 5982e92ac56SJamie Gritton svc_rpc_gss_release_client(struct svc_rpc_gss_client *client) 5992e92ac56SJamie Gritton { 6002e92ac56SJamie Gritton 6012e92ac56SJamie Gritton if (!refcount_release(&client->cl_refs)) 6022e92ac56SJamie Gritton return; 6032e92ac56SJamie Gritton svc_rpc_gss_destroy_client(client); 6042e92ac56SJamie Gritton } 6052e92ac56SJamie Gritton 6062e92ac56SJamie Gritton /* 6072e92ac56SJamie Gritton * Remove a client from our global lists and free it if we can. 6082e92ac56SJamie Gritton */ 6092e92ac56SJamie Gritton static void 6102e92ac56SJamie Gritton svc_rpc_gss_forget_client(struct svc_rpc_gss_client *client) 6112e92ac56SJamie Gritton { 6122e92ac56SJamie Gritton struct svc_rpc_gss_client_list *list; 6132e92ac56SJamie Gritton 6142e92ac56SJamie Gritton list = &svc_rpc_gss_client_hash[client->cl_id.ci_id % CLIENT_HASH_SIZE]; 6152e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 6162e92ac56SJamie Gritton TAILQ_REMOVE(list, client, cl_link); 6172e92ac56SJamie Gritton TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); 6182e92ac56SJamie Gritton svc_rpc_gss_client_count--; 6192e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 6202e92ac56SJamie Gritton svc_rpc_gss_release_client(client); 6212e92ac56SJamie Gritton } 6222e92ac56SJamie Gritton 6232e92ac56SJamie Gritton static void 6242e92ac56SJamie Gritton svc_rpc_gss_timeout_clients(void) 6252e92ac56SJamie Gritton { 6262e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 6272e92ac56SJamie Gritton struct svc_rpc_gss_client *nclient; 6282e92ac56SJamie Gritton time_t now = time_uptime; 6292e92ac56SJamie Gritton 6302e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_timeout_clients()"); 6312e92ac56SJamie Gritton 6322e92ac56SJamie Gritton /* 6332e92ac56SJamie Gritton * First enforce the max client limit. We keep 6342e92ac56SJamie Gritton * svc_rpc_gss_clients in LRU order. 6352e92ac56SJamie Gritton */ 6362e92ac56SJamie Gritton while (svc_rpc_gss_client_count > CLIENT_MAX) 6372e92ac56SJamie Gritton svc_rpc_gss_forget_client(TAILQ_LAST(&svc_rpc_gss_clients, 6382e92ac56SJamie Gritton svc_rpc_gss_client_list)); 6392e92ac56SJamie Gritton TAILQ_FOREACH_SAFE(client, &svc_rpc_gss_clients, cl_alllink, nclient) { 6402e92ac56SJamie Gritton if (client->cl_state == CLIENT_STALE 6412e92ac56SJamie Gritton || now > client->cl_expiration) { 6422e92ac56SJamie Gritton rpc_gss_log_debug("expiring client %p", client); 6432e92ac56SJamie Gritton svc_rpc_gss_forget_client(client); 6442e92ac56SJamie Gritton } 6452e92ac56SJamie Gritton } 6462e92ac56SJamie Gritton } 6472e92ac56SJamie Gritton 6482e92ac56SJamie Gritton #ifdef DEBUG 6492e92ac56SJamie Gritton /* 6502e92ac56SJamie Gritton * OID<->string routines. These are uuuuugly. 6512e92ac56SJamie Gritton */ 6522e92ac56SJamie Gritton static OM_uint32 6532e92ac56SJamie Gritton gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) 6542e92ac56SJamie Gritton { 6552e92ac56SJamie Gritton char numstr[128]; 6562e92ac56SJamie Gritton unsigned long number; 6572e92ac56SJamie Gritton int numshift; 6582e92ac56SJamie Gritton size_t string_length; 6592e92ac56SJamie Gritton size_t i; 6602e92ac56SJamie Gritton unsigned char *cp; 6612e92ac56SJamie Gritton char *bp; 6622e92ac56SJamie Gritton 6632e92ac56SJamie Gritton /* Decoded according to krb5/gssapi_krb5.c */ 6642e92ac56SJamie Gritton 6652e92ac56SJamie Gritton /* First determine the size of the string */ 6662e92ac56SJamie Gritton string_length = 0; 6672e92ac56SJamie Gritton number = 0; 6682e92ac56SJamie Gritton numshift = 0; 6692e92ac56SJamie Gritton cp = (unsigned char *) oid->elements; 6702e92ac56SJamie Gritton number = (unsigned long) cp[0]; 6712e92ac56SJamie Gritton sprintf(numstr, "%ld ", number/40); 6722e92ac56SJamie Gritton string_length += strlen(numstr); 6732e92ac56SJamie Gritton sprintf(numstr, "%ld ", number%40); 6742e92ac56SJamie Gritton string_length += strlen(numstr); 6752e92ac56SJamie Gritton for (i=1; i<oid->length; i++) { 6762e92ac56SJamie Gritton if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) { 6772e92ac56SJamie Gritton number = (number << 7) | (cp[i] & 0x7f); 6782e92ac56SJamie Gritton numshift += 7; 6792e92ac56SJamie Gritton } 6802e92ac56SJamie Gritton else { 6812e92ac56SJamie Gritton *minor_status = 0; 6822e92ac56SJamie Gritton return(GSS_S_FAILURE); 6832e92ac56SJamie Gritton } 6842e92ac56SJamie Gritton if ((cp[i] & 0x80) == 0) { 6852e92ac56SJamie Gritton sprintf(numstr, "%ld ", number); 6862e92ac56SJamie Gritton string_length += strlen(numstr); 6872e92ac56SJamie Gritton number = 0; 6882e92ac56SJamie Gritton numshift = 0; 6892e92ac56SJamie Gritton } 6902e92ac56SJamie Gritton } 6912e92ac56SJamie Gritton /* 6922e92ac56SJamie Gritton * If we get here, we've calculated the length of "n n n ... n ". Add 4 6932e92ac56SJamie Gritton * here for "{ " and "}\0". 6942e92ac56SJamie Gritton */ 6952e92ac56SJamie Gritton string_length += 4; 6962e92ac56SJamie Gritton if ((bp = (char *) mem_alloc(string_length))) { 6972e92ac56SJamie Gritton strcpy(bp, "{ "); 6982e92ac56SJamie Gritton number = (unsigned long) cp[0]; 6992e92ac56SJamie Gritton sprintf(numstr, "%ld ", number/40); 7002e92ac56SJamie Gritton strcat(bp, numstr); 7012e92ac56SJamie Gritton sprintf(numstr, "%ld ", number%40); 7022e92ac56SJamie Gritton strcat(bp, numstr); 7032e92ac56SJamie Gritton number = 0; 7042e92ac56SJamie Gritton cp = (unsigned char *) oid->elements; 7052e92ac56SJamie Gritton for (i=1; i<oid->length; i++) { 7062e92ac56SJamie Gritton number = (number << 7) | (cp[i] & 0x7f); 7072e92ac56SJamie Gritton if ((cp[i] & 0x80) == 0) { 7082e92ac56SJamie Gritton sprintf(numstr, "%ld ", number); 7092e92ac56SJamie Gritton strcat(bp, numstr); 7102e92ac56SJamie Gritton number = 0; 7112e92ac56SJamie Gritton } 7122e92ac56SJamie Gritton } 7132e92ac56SJamie Gritton strcat(bp, "}"); 7142e92ac56SJamie Gritton oid_str->length = strlen(bp)+1; 7152e92ac56SJamie Gritton oid_str->value = (void *) bp; 7162e92ac56SJamie Gritton *minor_status = 0; 7172e92ac56SJamie Gritton return(GSS_S_COMPLETE); 7182e92ac56SJamie Gritton } 7192e92ac56SJamie Gritton *minor_status = 0; 7202e92ac56SJamie Gritton return(GSS_S_FAILURE); 721a9148abdSDoug Rabson } 722a9148abdSDoug Rabson #endif 723a9148abdSDoug Rabson 724a9148abdSDoug Rabson static void 7252e92ac56SJamie Gritton svc_rpc_gss_build_ucred(struct svc_rpc_gss_client *client, 7262e92ac56SJamie Gritton const gss_name_t name) 727a9148abdSDoug Rabson { 7282e92ac56SJamie Gritton OM_uint32 maj_stat, min_stat; 7292e92ac56SJamie Gritton rpc_gss_ucred_t *uc = &client->cl_ucred; 7302e92ac56SJamie Gritton int numgroups; 731a9148abdSDoug Rabson 7322e92ac56SJamie Gritton uc->uid = 65534; 7332e92ac56SJamie Gritton uc->gid = 65534; 7342e92ac56SJamie Gritton uc->gidlist = client->cl_gid_storage; 735d4468577SJamie Gritton 7362e92ac56SJamie Gritton numgroups = NGROUPS; 7372e92ac56SJamie Gritton maj_stat = gss_pname_to_unix_cred(&min_stat, name, client->cl_mech, 7382e92ac56SJamie Gritton &uc->uid, &uc->gid, &numgroups, &uc->gidlist[0]); 7392e92ac56SJamie Gritton if (GSS_ERROR(maj_stat)) 7402e92ac56SJamie Gritton uc->gidlen = 0; 7412e92ac56SJamie Gritton else 7422e92ac56SJamie Gritton uc->gidlen = numgroups; 743d4468577SJamie Gritton } 744d4468577SJamie Gritton 7452e92ac56SJamie Gritton static void 7462e92ac56SJamie Gritton svc_rpc_gss_set_flavor(struct svc_rpc_gss_client *client) 747a9148abdSDoug Rabson { 7482e92ac56SJamie Gritton static gss_OID_desc krb5_mech_oid = 7492e92ac56SJamie Gritton {9, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02" }; 750a9148abdSDoug Rabson 751d4468577SJamie Gritton /* 7522e92ac56SJamie Gritton * Attempt to translate mech type and service into a 7532e92ac56SJamie Gritton * 'pseudo flavor'. Hardwire in krb5 support for now. 754d4468577SJamie Gritton */ 7552e92ac56SJamie Gritton if (kgss_oid_equal(client->cl_mech, &krb5_mech_oid)) { 7562e92ac56SJamie Gritton switch (client->cl_rawcred.service) { 7572e92ac56SJamie Gritton case rpc_gss_svc_default: 7582e92ac56SJamie Gritton case rpc_gss_svc_none: 7592e92ac56SJamie Gritton client->cl_rpcflavor = RPCSEC_GSS_KRB5; 7602e92ac56SJamie Gritton break; 7612e92ac56SJamie Gritton case rpc_gss_svc_integrity: 7622e92ac56SJamie Gritton client->cl_rpcflavor = RPCSEC_GSS_KRB5I; 7632e92ac56SJamie Gritton break; 7642e92ac56SJamie Gritton case rpc_gss_svc_privacy: 7652e92ac56SJamie Gritton client->cl_rpcflavor = RPCSEC_GSS_KRB5P; 7662e92ac56SJamie Gritton break; 7672e92ac56SJamie Gritton } 7682e92ac56SJamie Gritton } else { 7692e92ac56SJamie Gritton client->cl_rpcflavor = RPCSEC_GSS; 7702e92ac56SJamie Gritton } 7712e92ac56SJamie Gritton } 7722e92ac56SJamie Gritton 7732e92ac56SJamie Gritton static bool_t 7742e92ac56SJamie Gritton svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client, 7752e92ac56SJamie Gritton struct svc_req *rqst, 7762e92ac56SJamie Gritton struct rpc_gss_init_res *gr, 7772e92ac56SJamie Gritton struct rpc_gss_cred *gc) 778a9148abdSDoug Rabson { 7792e92ac56SJamie Gritton gss_buffer_desc recv_tok; 7802e92ac56SJamie Gritton gss_OID mech; 7812e92ac56SJamie Gritton OM_uint32 maj_stat = 0, min_stat = 0, ret_flags; 7822e92ac56SJamie Gritton OM_uint32 cred_lifetime; 7832e92ac56SJamie Gritton struct svc_rpc_gss_svc_name *sname; 784a9148abdSDoug Rabson 7852e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_accept_context()"); 7862e92ac56SJamie Gritton 7872e92ac56SJamie Gritton /* Deserialize arguments. */ 7882e92ac56SJamie Gritton memset(&recv_tok, 0, sizeof(recv_tok)); 7892e92ac56SJamie Gritton 7902e92ac56SJamie Gritton if (!svc_getargs(rqst, 7912e92ac56SJamie Gritton (xdrproc_t) xdr_gss_buffer_desc, 7922e92ac56SJamie Gritton (caddr_t) &recv_tok)) { 7932e92ac56SJamie Gritton client->cl_state = CLIENT_STALE; 7942e92ac56SJamie Gritton return (FALSE); 795a9148abdSDoug Rabson } 796a9148abdSDoug Rabson 797d4468577SJamie Gritton /* 7982e92ac56SJamie Gritton * First time round, try all the server names we have until 7992e92ac56SJamie Gritton * one matches. Afterwards, stick with that one. 800d4468577SJamie Gritton */ 8012e92ac56SJamie Gritton sx_xlock(&svc_rpc_gss_lock); 8022e92ac56SJamie Gritton if (!client->cl_sname) { 8032e92ac56SJamie Gritton SLIST_FOREACH(sname, &svc_rpc_gss_svc_names, sn_link) { 8042e92ac56SJamie Gritton if (sname->sn_program == rqst->rq_prog 8052e92ac56SJamie Gritton && sname->sn_version == rqst->rq_vers) { 8062e92ac56SJamie Gritton retry: 8072e92ac56SJamie Gritton gr->gr_major = gss_accept_sec_context( 8082e92ac56SJamie Gritton &gr->gr_minor, 8092e92ac56SJamie Gritton &client->cl_ctx, 8102e92ac56SJamie Gritton sname->sn_cred, 8112e92ac56SJamie Gritton &recv_tok, 8122e92ac56SJamie Gritton GSS_C_NO_CHANNEL_BINDINGS, 8132e92ac56SJamie Gritton &client->cl_cname, 8142e92ac56SJamie Gritton &mech, 8152e92ac56SJamie Gritton &gr->gr_token, 8162e92ac56SJamie Gritton &ret_flags, 8172e92ac56SJamie Gritton &cred_lifetime, 8182e92ac56SJamie Gritton &client->cl_creds); 8192e92ac56SJamie Gritton if (gr->gr_major == 8202e92ac56SJamie Gritton GSS_S_CREDENTIALS_EXPIRED) { 821d4468577SJamie Gritton /* 8222e92ac56SJamie Gritton * Either our creds really did 8232e92ac56SJamie Gritton * expire or gssd was 8242e92ac56SJamie Gritton * restarted. 825d4468577SJamie Gritton */ 8262e92ac56SJamie Gritton if (rpc_gss_acquire_svc_cred(sname)) 8272e92ac56SJamie Gritton goto retry; 8282e92ac56SJamie Gritton } 8292e92ac56SJamie Gritton client->cl_sname = sname; 830d4468577SJamie Gritton break; 831d4468577SJamie Gritton } 832d4468577SJamie Gritton } 8332e92ac56SJamie Gritton if (!sname) { 8342e92ac56SJamie Gritton xdr_free((xdrproc_t) xdr_gss_buffer_desc, 8352e92ac56SJamie Gritton (char *) &recv_tok); 8362e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 8372e92ac56SJamie Gritton return (FALSE); 838d4468577SJamie Gritton } 8392e92ac56SJamie Gritton } else { 8402e92ac56SJamie Gritton gr->gr_major = gss_accept_sec_context( 8412e92ac56SJamie Gritton &gr->gr_minor, 8422e92ac56SJamie Gritton &client->cl_ctx, 8432e92ac56SJamie Gritton client->cl_sname->sn_cred, 8442e92ac56SJamie Gritton &recv_tok, 8452e92ac56SJamie Gritton GSS_C_NO_CHANNEL_BINDINGS, 8462e92ac56SJamie Gritton &client->cl_cname, 8472e92ac56SJamie Gritton &mech, 8482e92ac56SJamie Gritton &gr->gr_token, 8492e92ac56SJamie Gritton &ret_flags, 8502e92ac56SJamie Gritton &cred_lifetime, 8512e92ac56SJamie Gritton NULL); 852d4468577SJamie Gritton } 8532e92ac56SJamie Gritton sx_xunlock(&svc_rpc_gss_lock); 854a9148abdSDoug Rabson 8552e92ac56SJamie Gritton xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &recv_tok); 856d4468577SJamie Gritton 857d4468577SJamie Gritton /* 8582e92ac56SJamie Gritton * If we get an error from gss_accept_sec_context, send the 8592e92ac56SJamie Gritton * reply anyway so that the client gets a chance to see what 8602e92ac56SJamie Gritton * is wrong. 861d4468577SJamie Gritton */ 8622e92ac56SJamie Gritton if (gr->gr_major != GSS_S_COMPLETE && 8632e92ac56SJamie Gritton gr->gr_major != GSS_S_CONTINUE_NEEDED) { 8642e92ac56SJamie Gritton rpc_gss_log_status("accept_sec_context", client->cl_mech, 8652e92ac56SJamie Gritton gr->gr_major, gr->gr_minor); 8662e92ac56SJamie Gritton client->cl_state = CLIENT_STALE; 8672e92ac56SJamie Gritton return (TRUE); 8682e92ac56SJamie Gritton } 8692e92ac56SJamie Gritton 8702e92ac56SJamie Gritton gr->gr_handle.value = &client->cl_id; 8712e92ac56SJamie Gritton gr->gr_handle.length = sizeof(client->cl_id); 8722e92ac56SJamie Gritton gr->gr_win = SVC_RPC_GSS_SEQWINDOW; 8732e92ac56SJamie Gritton 8742e92ac56SJamie Gritton /* Save client info. */ 8752e92ac56SJamie Gritton client->cl_mech = mech; 8762e92ac56SJamie Gritton client->cl_qop = GSS_C_QOP_DEFAULT; 8772e92ac56SJamie Gritton client->cl_done_callback = FALSE; 8782e92ac56SJamie Gritton 8792e92ac56SJamie Gritton if (gr->gr_major == GSS_S_COMPLETE) { 8802e92ac56SJamie Gritton gss_buffer_desc export_name; 8812e92ac56SJamie Gritton 8822e92ac56SJamie Gritton /* 8832e92ac56SJamie Gritton * Change client expiration time to be near when the 8842e92ac56SJamie Gritton * client creds expire (or 24 hours if we can't figure 8852e92ac56SJamie Gritton * that out). 8862e92ac56SJamie Gritton */ 8872e92ac56SJamie Gritton if (cred_lifetime == GSS_C_INDEFINITE) 8882e92ac56SJamie Gritton cred_lifetime = time_uptime + 24*60*60; 8892e92ac56SJamie Gritton 8902e92ac56SJamie Gritton client->cl_expiration = time_uptime + cred_lifetime; 8912e92ac56SJamie Gritton 8922e92ac56SJamie Gritton /* 8932e92ac56SJamie Gritton * Fill in cred details in the rawcred structure. 8942e92ac56SJamie Gritton */ 8952e92ac56SJamie Gritton client->cl_rawcred.version = RPCSEC_GSS_VERSION; 8962e92ac56SJamie Gritton rpc_gss_oid_to_mech(mech, &client->cl_rawcred.mechanism); 8972e92ac56SJamie Gritton maj_stat = gss_export_name(&min_stat, client->cl_cname, 8982e92ac56SJamie Gritton &export_name); 8992e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 9002e92ac56SJamie Gritton rpc_gss_log_status("gss_export_name", client->cl_mech, 9012e92ac56SJamie Gritton maj_stat, min_stat); 9022e92ac56SJamie Gritton return (FALSE); 9032e92ac56SJamie Gritton } 9042e92ac56SJamie Gritton client->cl_rawcred.client_principal = 9052e92ac56SJamie Gritton mem_alloc(sizeof(*client->cl_rawcred.client_principal) 9062e92ac56SJamie Gritton + export_name.length); 9072e92ac56SJamie Gritton client->cl_rawcred.client_principal->len = export_name.length; 9082e92ac56SJamie Gritton memcpy(client->cl_rawcred.client_principal->name, 9092e92ac56SJamie Gritton export_name.value, export_name.length); 9102e92ac56SJamie Gritton gss_release_buffer(&min_stat, &export_name); 9112e92ac56SJamie Gritton client->cl_rawcred.svc_principal = 9122e92ac56SJamie Gritton client->cl_sname->sn_principal; 9132e92ac56SJamie Gritton client->cl_rawcred.service = gc->gc_svc; 9142e92ac56SJamie Gritton 9152e92ac56SJamie Gritton /* 9162e92ac56SJamie Gritton * Use gss_pname_to_uid to map to unix creds. For 9172e92ac56SJamie Gritton * kerberos5, this uses krb5_aname_to_localname. 9182e92ac56SJamie Gritton */ 9192e92ac56SJamie Gritton svc_rpc_gss_build_ucred(client, client->cl_cname); 9202e92ac56SJamie Gritton svc_rpc_gss_set_flavor(client); 9212e92ac56SJamie Gritton gss_release_name(&min_stat, &client->cl_cname); 9222e92ac56SJamie Gritton 9232e92ac56SJamie Gritton #ifdef DEBUG 924a9148abdSDoug Rabson { 9252e92ac56SJamie Gritton gss_buffer_desc mechname; 926a9148abdSDoug Rabson 9272e92ac56SJamie Gritton gss_oid_to_str(&min_stat, mech, &mechname); 9282e92ac56SJamie Gritton 9292e92ac56SJamie Gritton rpc_gss_log_debug("accepted context for %s with " 9302e92ac56SJamie Gritton "<mech %.*s, qop %d, svc %d>", 9312e92ac56SJamie Gritton client->cl_rawcred.client_principal->name, 9322e92ac56SJamie Gritton mechname.length, (char *)mechname.value, 9332e92ac56SJamie Gritton client->cl_qop, client->rawcred.service); 9342e92ac56SJamie Gritton 9352e92ac56SJamie Gritton gss_release_buffer(&min_stat, &mechname); 936d4468577SJamie Gritton } 9372e92ac56SJamie Gritton #endif /* DEBUG */ 938d4468577SJamie Gritton } 9392e92ac56SJamie Gritton return (TRUE); 940a9148abdSDoug Rabson } 941a9148abdSDoug Rabson 9422e92ac56SJamie Gritton static bool_t 9432e92ac56SJamie Gritton svc_rpc_gss_validate(struct svc_rpc_gss_client *client, struct rpc_msg *msg, 9442e92ac56SJamie Gritton gss_qop_t *qop) 945a9148abdSDoug Rabson { 9462e92ac56SJamie Gritton struct opaque_auth *oa; 9472e92ac56SJamie Gritton gss_buffer_desc rpcbuf, checksum; 9482e92ac56SJamie Gritton OM_uint32 maj_stat, min_stat; 9492e92ac56SJamie Gritton gss_qop_t qop_state; 9502e92ac56SJamie Gritton int32_t rpchdr[128 / sizeof(int32_t)]; 9512e92ac56SJamie Gritton int32_t *buf; 952a9148abdSDoug Rabson 9532e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_validate()"); 9542e92ac56SJamie Gritton 9552e92ac56SJamie Gritton memset(rpchdr, 0, sizeof(rpchdr)); 9562e92ac56SJamie Gritton 9572e92ac56SJamie Gritton /* Reconstruct RPC header for signing (from xdr_callmsg). */ 9582e92ac56SJamie Gritton buf = rpchdr; 9592e92ac56SJamie Gritton IXDR_PUT_LONG(buf, msg->rm_xid); 9602e92ac56SJamie Gritton IXDR_PUT_ENUM(buf, msg->rm_direction); 9612e92ac56SJamie Gritton IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); 9622e92ac56SJamie Gritton IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); 9632e92ac56SJamie Gritton IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); 9642e92ac56SJamie Gritton IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); 9652e92ac56SJamie Gritton oa = &msg->rm_call.cb_cred; 9662e92ac56SJamie Gritton IXDR_PUT_ENUM(buf, oa->oa_flavor); 9672e92ac56SJamie Gritton IXDR_PUT_LONG(buf, oa->oa_length); 9682e92ac56SJamie Gritton if (oa->oa_length) { 9692e92ac56SJamie Gritton memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); 9702e92ac56SJamie Gritton buf += RNDUP(oa->oa_length) / sizeof(int32_t); 971a9148abdSDoug Rabson } 9722e92ac56SJamie Gritton rpcbuf.value = rpchdr; 9732e92ac56SJamie Gritton rpcbuf.length = (u_char *)buf - (u_char *)rpchdr; 9742e92ac56SJamie Gritton 9752e92ac56SJamie Gritton checksum.value = msg->rm_call.cb_verf.oa_base; 9762e92ac56SJamie Gritton checksum.length = msg->rm_call.cb_verf.oa_length; 9772e92ac56SJamie Gritton 9782e92ac56SJamie Gritton maj_stat = gss_verify_mic(&min_stat, client->cl_ctx, &rpcbuf, &checksum, 9792e92ac56SJamie Gritton &qop_state); 9802e92ac56SJamie Gritton 9812e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 9822e92ac56SJamie Gritton rpc_gss_log_status("gss_verify_mic", client->cl_mech, 9832e92ac56SJamie Gritton maj_stat, min_stat); 9842e92ac56SJamie Gritton client->cl_state = CLIENT_STALE; 9852e92ac56SJamie Gritton return (FALSE); 986d4468577SJamie Gritton } 987d4468577SJamie Gritton 9882e92ac56SJamie Gritton *qop = qop_state; 9892e92ac56SJamie Gritton return (TRUE); 9902e92ac56SJamie Gritton } 9912e92ac56SJamie Gritton 9922e92ac56SJamie Gritton static bool_t 9932e92ac56SJamie Gritton svc_rpc_gss_nextverf(struct svc_rpc_gss_client *client, 9942e92ac56SJamie Gritton struct svc_req *rqst, u_int seq) 9952e92ac56SJamie Gritton { 9962e92ac56SJamie Gritton gss_buffer_desc signbuf; 9972e92ac56SJamie Gritton gss_buffer_desc mic; 9982e92ac56SJamie Gritton OM_uint32 maj_stat, min_stat; 9992e92ac56SJamie Gritton uint32_t nseq; 10002e92ac56SJamie Gritton 10012e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_nextverf()"); 10022e92ac56SJamie Gritton 10032e92ac56SJamie Gritton nseq = htonl(seq); 10042e92ac56SJamie Gritton signbuf.value = &nseq; 10052e92ac56SJamie Gritton signbuf.length = sizeof(nseq); 10062e92ac56SJamie Gritton 10072e92ac56SJamie Gritton maj_stat = gss_get_mic(&min_stat, client->cl_ctx, client->cl_qop, 10082e92ac56SJamie Gritton &signbuf, &mic); 10092e92ac56SJamie Gritton 10102e92ac56SJamie Gritton if (maj_stat != GSS_S_COMPLETE) { 10112e92ac56SJamie Gritton rpc_gss_log_status("gss_get_mic", client->cl_mech, maj_stat, min_stat); 10122e92ac56SJamie Gritton client->cl_state = CLIENT_STALE; 10132e92ac56SJamie Gritton return (FALSE); 10142e92ac56SJamie Gritton } 10152e92ac56SJamie Gritton 10162e92ac56SJamie Gritton KASSERT(mic.length <= MAX_AUTH_BYTES, 10172e92ac56SJamie Gritton ("MIC too large for RPCSEC_GSS")); 10182e92ac56SJamie Gritton 10192e92ac56SJamie Gritton rqst->rq_verf.oa_flavor = RPCSEC_GSS; 10202e92ac56SJamie Gritton rqst->rq_verf.oa_length = mic.length; 10212e92ac56SJamie Gritton bcopy(mic.value, rqst->rq_verf.oa_base, mic.length); 10222e92ac56SJamie Gritton 10232e92ac56SJamie Gritton gss_release_buffer(&min_stat, &mic); 10242e92ac56SJamie Gritton 10252e92ac56SJamie Gritton return (TRUE); 10262e92ac56SJamie Gritton } 10272e92ac56SJamie Gritton 10282e92ac56SJamie Gritton static bool_t 10292e92ac56SJamie Gritton svc_rpc_gss_callback(struct svc_rpc_gss_client *client, struct svc_req *rqst) 10302e92ac56SJamie Gritton { 10312e92ac56SJamie Gritton struct svc_rpc_gss_callback *scb; 10322e92ac56SJamie Gritton rpc_gss_lock_t lock; 10332e92ac56SJamie Gritton void *cookie; 10342e92ac56SJamie Gritton bool_t cb_res; 10352e92ac56SJamie Gritton bool_t result; 10362e92ac56SJamie Gritton 10372e92ac56SJamie Gritton /* 10382e92ac56SJamie Gritton * See if we have a callback for this guy. 10392e92ac56SJamie Gritton */ 10402e92ac56SJamie Gritton result = TRUE; 10412e92ac56SJamie Gritton SLIST_FOREACH(scb, &svc_rpc_gss_callbacks, cb_link) { 10422e92ac56SJamie Gritton if (scb->cb_callback.program == rqst->rq_prog 10432e92ac56SJamie Gritton && scb->cb_callback.version == rqst->rq_vers) { 10442e92ac56SJamie Gritton /* 10452e92ac56SJamie Gritton * This one matches. Call the callback and see 10462e92ac56SJamie Gritton * if it wants to veto or something. 10472e92ac56SJamie Gritton */ 10482e92ac56SJamie Gritton lock.locked = FALSE; 10492e92ac56SJamie Gritton lock.raw_cred = &client->cl_rawcred; 10502e92ac56SJamie Gritton cb_res = scb->cb_callback.callback(rqst, 10512e92ac56SJamie Gritton client->cl_creds, 10522e92ac56SJamie Gritton client->cl_ctx, 10532e92ac56SJamie Gritton &lock, 10542e92ac56SJamie Gritton &cookie); 10552e92ac56SJamie Gritton 10562e92ac56SJamie Gritton if (!cb_res) { 10572e92ac56SJamie Gritton client->cl_state = CLIENT_STALE; 10582e92ac56SJamie Gritton result = FALSE; 10592e92ac56SJamie Gritton break; 10602e92ac56SJamie Gritton } 10612e92ac56SJamie Gritton 10622e92ac56SJamie Gritton /* 10632e92ac56SJamie Gritton * The callback accepted the connection - it 10642e92ac56SJamie Gritton * is responsible for freeing client->cl_creds 10652e92ac56SJamie Gritton * now. 10662e92ac56SJamie Gritton */ 10672e92ac56SJamie Gritton client->cl_creds = GSS_C_NO_CREDENTIAL; 10682e92ac56SJamie Gritton client->cl_locked = lock.locked; 10692e92ac56SJamie Gritton client->cl_cookie = cookie; 10702e92ac56SJamie Gritton return (TRUE); 10712e92ac56SJamie Gritton } 10722e92ac56SJamie Gritton } 10732e92ac56SJamie Gritton 10742e92ac56SJamie Gritton /* 10752e92ac56SJamie Gritton * Either no callback exists for this program/version or one 10762e92ac56SJamie Gritton * of the callbacks rejected the connection. We just need to 10772e92ac56SJamie Gritton * clean up the delegated client creds, if any. 10782e92ac56SJamie Gritton */ 10792e92ac56SJamie Gritton if (client->cl_creds) { 10802e92ac56SJamie Gritton OM_uint32 min_ver; 10812e92ac56SJamie Gritton gss_release_cred(&min_ver, &client->cl_creds); 10822e92ac56SJamie Gritton } 10832e92ac56SJamie Gritton return (result); 10842e92ac56SJamie Gritton } 10852e92ac56SJamie Gritton 10862e92ac56SJamie Gritton static bool_t 10872e92ac56SJamie Gritton svc_rpc_gss_check_replay(struct svc_rpc_gss_client *client, uint32_t seq) 10882e92ac56SJamie Gritton { 10892e92ac56SJamie Gritton u_int32_t offset; 10902e92ac56SJamie Gritton int word, bit; 10912e92ac56SJamie Gritton bool_t result; 10922e92ac56SJamie Gritton 10932e92ac56SJamie Gritton sx_xlock(&client->cl_lock); 10942e92ac56SJamie Gritton if (seq <= client->cl_seqlast) { 10952e92ac56SJamie Gritton /* 10962e92ac56SJamie Gritton * The request sequence number is less than 10972e92ac56SJamie Gritton * the largest we have seen so far. If it is 10982e92ac56SJamie Gritton * outside the window or if we have seen a 10992e92ac56SJamie Gritton * request with this sequence before, silently 11002e92ac56SJamie Gritton * discard it. 11012e92ac56SJamie Gritton */ 11022e92ac56SJamie Gritton offset = client->cl_seqlast - seq; 11032e92ac56SJamie Gritton if (offset >= SVC_RPC_GSS_SEQWINDOW) { 11042e92ac56SJamie Gritton result = FALSE; 11052e92ac56SJamie Gritton goto out; 11062e92ac56SJamie Gritton } 11072e92ac56SJamie Gritton word = offset / 32; 11082e92ac56SJamie Gritton bit = offset % 32; 11092e92ac56SJamie Gritton if (client->cl_seqmask[word] & (1 << bit)) { 11102e92ac56SJamie Gritton result = FALSE; 11112e92ac56SJamie Gritton goto out; 11122e92ac56SJamie Gritton } 11132e92ac56SJamie Gritton } 11142e92ac56SJamie Gritton 11152e92ac56SJamie Gritton result = TRUE; 11162e92ac56SJamie Gritton out: 11172e92ac56SJamie Gritton sx_xunlock(&client->cl_lock); 11182e92ac56SJamie Gritton return (result); 11192e92ac56SJamie Gritton } 11202e92ac56SJamie Gritton 11212e92ac56SJamie Gritton static void 11222e92ac56SJamie Gritton svc_rpc_gss_update_seq(struct svc_rpc_gss_client *client, uint32_t seq) 11232e92ac56SJamie Gritton { 11242e92ac56SJamie Gritton int offset, i, word, bit; 11252e92ac56SJamie Gritton uint32_t carry, newcarry; 11262e92ac56SJamie Gritton 11272e92ac56SJamie Gritton sx_xlock(&client->cl_lock); 11282e92ac56SJamie Gritton if (seq > client->cl_seqlast) { 11292e92ac56SJamie Gritton /* 11302e92ac56SJamie Gritton * This request has a sequence number greater 11312e92ac56SJamie Gritton * than any we have seen so far. Advance the 11322e92ac56SJamie Gritton * seq window and set bit zero of the window 11332e92ac56SJamie Gritton * (which corresponds to the new sequence 11342e92ac56SJamie Gritton * number) 11352e92ac56SJamie Gritton */ 11362e92ac56SJamie Gritton offset = seq - client->cl_seqlast; 11372e92ac56SJamie Gritton while (offset > 32) { 11382e92ac56SJamie Gritton for (i = (SVC_RPC_GSS_SEQWINDOW / 32) - 1; 11392e92ac56SJamie Gritton i > 0; i--) { 11402e92ac56SJamie Gritton client->cl_seqmask[i] = client->cl_seqmask[i-1]; 11412e92ac56SJamie Gritton } 11422e92ac56SJamie Gritton client->cl_seqmask[0] = 0; 11432e92ac56SJamie Gritton offset -= 32; 11442e92ac56SJamie Gritton } 11452e92ac56SJamie Gritton carry = 0; 11462e92ac56SJamie Gritton for (i = 0; i < SVC_RPC_GSS_SEQWINDOW / 32; i++) { 11472e92ac56SJamie Gritton newcarry = client->cl_seqmask[i] >> (32 - offset); 11482e92ac56SJamie Gritton client->cl_seqmask[i] = 11492e92ac56SJamie Gritton (client->cl_seqmask[i] << offset) | carry; 11502e92ac56SJamie Gritton carry = newcarry; 11512e92ac56SJamie Gritton } 11522e92ac56SJamie Gritton client->cl_seqmask[0] |= 1; 11532e92ac56SJamie Gritton client->cl_seqlast = seq; 11542e92ac56SJamie Gritton } else { 11552e92ac56SJamie Gritton offset = client->cl_seqlast - seq; 11562e92ac56SJamie Gritton word = offset / 32; 11572e92ac56SJamie Gritton bit = offset % 32; 11582e92ac56SJamie Gritton client->cl_seqmask[word] |= (1 << bit); 11592e92ac56SJamie Gritton } 11602e92ac56SJamie Gritton sx_xunlock(&client->cl_lock); 11612e92ac56SJamie Gritton } 11622e92ac56SJamie Gritton 11632e92ac56SJamie Gritton enum auth_stat 11642e92ac56SJamie Gritton svc_rpc_gss(struct svc_req *rqst, struct rpc_msg *msg) 11652e92ac56SJamie Gritton 11662e92ac56SJamie Gritton { 11672e92ac56SJamie Gritton OM_uint32 min_stat; 11682e92ac56SJamie Gritton XDR xdrs; 11692e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc; 11702e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 11712e92ac56SJamie Gritton struct rpc_gss_cred gc; 11722e92ac56SJamie Gritton struct rpc_gss_init_res gr; 11732e92ac56SJamie Gritton gss_qop_t qop; 11742e92ac56SJamie Gritton int call_stat; 11752e92ac56SJamie Gritton enum auth_stat result; 11762e92ac56SJamie Gritton 11772e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss()"); 11782e92ac56SJamie Gritton 11792e92ac56SJamie Gritton /* Garbage collect old clients. */ 11802e92ac56SJamie Gritton svc_rpc_gss_timeout_clients(); 11812e92ac56SJamie Gritton 11822e92ac56SJamie Gritton /* Initialize reply. */ 11832e92ac56SJamie Gritton rqst->rq_verf = _null_auth; 11842e92ac56SJamie Gritton 11852e92ac56SJamie Gritton /* Deserialize client credentials. */ 11862e92ac56SJamie Gritton if (rqst->rq_cred.oa_length <= 0) 11872e92ac56SJamie Gritton return (AUTH_BADCRED); 11882e92ac56SJamie Gritton 11892e92ac56SJamie Gritton memset(&gc, 0, sizeof(gc)); 11902e92ac56SJamie Gritton 11912e92ac56SJamie Gritton xdrmem_create(&xdrs, rqst->rq_cred.oa_base, 11922e92ac56SJamie Gritton rqst->rq_cred.oa_length, XDR_DECODE); 11932e92ac56SJamie Gritton 11942e92ac56SJamie Gritton if (!xdr_rpc_gss_cred(&xdrs, &gc)) { 11952e92ac56SJamie Gritton XDR_DESTROY(&xdrs); 11962e92ac56SJamie Gritton return (AUTH_BADCRED); 11972e92ac56SJamie Gritton } 11982e92ac56SJamie Gritton XDR_DESTROY(&xdrs); 11992e92ac56SJamie Gritton 12002e92ac56SJamie Gritton client = NULL; 12012e92ac56SJamie Gritton 12022e92ac56SJamie Gritton /* Check version. */ 12032e92ac56SJamie Gritton if (gc.gc_version != RPCSEC_GSS_VERSION) { 12042e92ac56SJamie Gritton result = AUTH_BADCRED; 12052e92ac56SJamie Gritton goto out; 12062e92ac56SJamie Gritton } 12072e92ac56SJamie Gritton 12082e92ac56SJamie Gritton /* Check the proc and find the client (or create it) */ 12092e92ac56SJamie Gritton if (gc.gc_proc == RPCSEC_GSS_INIT) { 12102e92ac56SJamie Gritton if (gc.gc_handle.length != 0) { 12112e92ac56SJamie Gritton result = AUTH_BADCRED; 12122e92ac56SJamie Gritton goto out; 12132e92ac56SJamie Gritton } 12142e92ac56SJamie Gritton client = svc_rpc_gss_create_client(); 12152e92ac56SJamie Gritton refcount_acquire(&client->cl_refs); 12162e92ac56SJamie Gritton } else { 12172e92ac56SJamie Gritton struct svc_rpc_gss_clientid *p; 12182e92ac56SJamie Gritton if (gc.gc_handle.length != sizeof(*p)) { 12192e92ac56SJamie Gritton result = AUTH_BADCRED; 12202e92ac56SJamie Gritton goto out; 12212e92ac56SJamie Gritton } 12222e92ac56SJamie Gritton p = gc.gc_handle.value; 12232e92ac56SJamie Gritton client = svc_rpc_gss_find_client(p); 12242e92ac56SJamie Gritton if (!client) { 12252e92ac56SJamie Gritton /* 12262e92ac56SJamie Gritton * Can't find the client - we may have 12272e92ac56SJamie Gritton * destroyed it - tell the other side to 12282e92ac56SJamie Gritton * re-authenticate. 12292e92ac56SJamie Gritton */ 12302e92ac56SJamie Gritton result = RPCSEC_GSS_CREDPROBLEM; 12312e92ac56SJamie Gritton goto out; 12322e92ac56SJamie Gritton } 12332e92ac56SJamie Gritton } 12342e92ac56SJamie Gritton cc = rqst->rq_clntcred; 12352e92ac56SJamie Gritton cc->cc_client = client; 12362e92ac56SJamie Gritton cc->cc_service = gc.gc_svc; 12372e92ac56SJamie Gritton cc->cc_seq = gc.gc_seq; 12382e92ac56SJamie Gritton 12392e92ac56SJamie Gritton /* 12402e92ac56SJamie Gritton * The service and sequence number must be ignored for 12412e92ac56SJamie Gritton * RPCSEC_GSS_INIT and RPCSEC_GSS_CONTINUE_INIT. 12422e92ac56SJamie Gritton */ 12432e92ac56SJamie Gritton if (gc.gc_proc != RPCSEC_GSS_INIT 12442e92ac56SJamie Gritton && gc.gc_proc != RPCSEC_GSS_CONTINUE_INIT) { 12452e92ac56SJamie Gritton /* 12462e92ac56SJamie Gritton * Check for sequence number overflow. 12472e92ac56SJamie Gritton */ 12482e92ac56SJamie Gritton if (gc.gc_seq >= MAXSEQ) { 12492e92ac56SJamie Gritton result = RPCSEC_GSS_CTXPROBLEM; 12502e92ac56SJamie Gritton goto out; 12512e92ac56SJamie Gritton } 12522e92ac56SJamie Gritton 12532e92ac56SJamie Gritton /* 12542e92ac56SJamie Gritton * Check for valid service. 12552e92ac56SJamie Gritton */ 12562e92ac56SJamie Gritton if (gc.gc_svc != rpc_gss_svc_none && 12572e92ac56SJamie Gritton gc.gc_svc != rpc_gss_svc_integrity && 12582e92ac56SJamie Gritton gc.gc_svc != rpc_gss_svc_privacy) { 12592e92ac56SJamie Gritton result = AUTH_BADCRED; 12602e92ac56SJamie Gritton goto out; 12612e92ac56SJamie Gritton } 12622e92ac56SJamie Gritton } 12632e92ac56SJamie Gritton 12642e92ac56SJamie Gritton /* Handle RPCSEC_GSS control procedure. */ 12652e92ac56SJamie Gritton switch (gc.gc_proc) { 12662e92ac56SJamie Gritton 12672e92ac56SJamie Gritton case RPCSEC_GSS_INIT: 12682e92ac56SJamie Gritton case RPCSEC_GSS_CONTINUE_INIT: 12692e92ac56SJamie Gritton if (rqst->rq_proc != NULLPROC) { 12702e92ac56SJamie Gritton result = AUTH_REJECTEDCRED; 12712e92ac56SJamie Gritton break; 12722e92ac56SJamie Gritton } 12732e92ac56SJamie Gritton 12742e92ac56SJamie Gritton memset(&gr, 0, sizeof(gr)); 12752e92ac56SJamie Gritton if (!svc_rpc_gss_accept_sec_context(client, rqst, &gr, &gc)) { 12762e92ac56SJamie Gritton result = AUTH_REJECTEDCRED; 12772e92ac56SJamie Gritton break; 12782e92ac56SJamie Gritton } 12792e92ac56SJamie Gritton 12802e92ac56SJamie Gritton if (gr.gr_major == GSS_S_COMPLETE) { 12812e92ac56SJamie Gritton /* 12822e92ac56SJamie Gritton * We borrow the space for the call verf to 12832e92ac56SJamie Gritton * pack our reply verf. 12842e92ac56SJamie Gritton */ 12852e92ac56SJamie Gritton rqst->rq_verf = msg->rm_call.cb_verf; 12862e92ac56SJamie Gritton if (!svc_rpc_gss_nextverf(client, rqst, gr.gr_win)) { 12872e92ac56SJamie Gritton result = AUTH_REJECTEDCRED; 12882e92ac56SJamie Gritton break; 12892e92ac56SJamie Gritton } 12902e92ac56SJamie Gritton } else { 12912e92ac56SJamie Gritton rqst->rq_verf = _null_auth; 12922e92ac56SJamie Gritton } 12932e92ac56SJamie Gritton 12942e92ac56SJamie Gritton call_stat = svc_sendreply(rqst, 12952e92ac56SJamie Gritton (xdrproc_t) xdr_rpc_gss_init_res, 12962e92ac56SJamie Gritton (caddr_t) &gr); 12972e92ac56SJamie Gritton 12982e92ac56SJamie Gritton gss_release_buffer(&min_stat, &gr.gr_token); 12992e92ac56SJamie Gritton 13002e92ac56SJamie Gritton if (!call_stat) { 13012e92ac56SJamie Gritton result = AUTH_FAILED; 13022e92ac56SJamie Gritton break; 13032e92ac56SJamie Gritton } 13042e92ac56SJamie Gritton 13052e92ac56SJamie Gritton if (gr.gr_major == GSS_S_COMPLETE) 13062e92ac56SJamie Gritton client->cl_state = CLIENT_ESTABLISHED; 13072e92ac56SJamie Gritton 13082e92ac56SJamie Gritton result = RPCSEC_GSS_NODISPATCH; 13092e92ac56SJamie Gritton break; 13102e92ac56SJamie Gritton 13112e92ac56SJamie Gritton case RPCSEC_GSS_DATA: 13122e92ac56SJamie Gritton case RPCSEC_GSS_DESTROY: 13132e92ac56SJamie Gritton if (!svc_rpc_gss_check_replay(client, gc.gc_seq)) { 13142e92ac56SJamie Gritton result = RPCSEC_GSS_NODISPATCH; 13152e92ac56SJamie Gritton break; 13162e92ac56SJamie Gritton } 13172e92ac56SJamie Gritton 13182e92ac56SJamie Gritton if (!svc_rpc_gss_validate(client, msg, &qop)) { 13192e92ac56SJamie Gritton result = RPCSEC_GSS_CREDPROBLEM; 13202e92ac56SJamie Gritton break; 13212e92ac56SJamie Gritton } 13222e92ac56SJamie Gritton 13232e92ac56SJamie Gritton /* 13242e92ac56SJamie Gritton * We borrow the space for the call verf to pack our 13252e92ac56SJamie Gritton * reply verf. 13262e92ac56SJamie Gritton */ 13272e92ac56SJamie Gritton rqst->rq_verf = msg->rm_call.cb_verf; 13282e92ac56SJamie Gritton if (!svc_rpc_gss_nextverf(client, rqst, gc.gc_seq)) { 13292e92ac56SJamie Gritton result = RPCSEC_GSS_CTXPROBLEM; 13302e92ac56SJamie Gritton break; 13312e92ac56SJamie Gritton } 13322e92ac56SJamie Gritton 13332e92ac56SJamie Gritton svc_rpc_gss_update_seq(client, gc.gc_seq); 13342e92ac56SJamie Gritton 13352e92ac56SJamie Gritton /* 13362e92ac56SJamie Gritton * Change the SVCAUTH ops on the request to point at 13372e92ac56SJamie Gritton * our own code so that we can unwrap the arguments 13382e92ac56SJamie Gritton * and wrap the result. The caller will re-set this on 13392e92ac56SJamie Gritton * every request to point to a set of null wrap/unwrap 13402e92ac56SJamie Gritton * methods. Acquire an extra reference to the client 13412e92ac56SJamie Gritton * which will be released by svc_rpc_gss_release() 13422e92ac56SJamie Gritton * after the request has finished processing. 13432e92ac56SJamie Gritton */ 13442e92ac56SJamie Gritton refcount_acquire(&client->cl_refs); 13452e92ac56SJamie Gritton rqst->rq_auth.svc_ah_ops = &svc_auth_gss_ops; 13462e92ac56SJamie Gritton rqst->rq_auth.svc_ah_private = cc; 13472e92ac56SJamie Gritton 13482e92ac56SJamie Gritton if (gc.gc_proc == RPCSEC_GSS_DATA) { 13492e92ac56SJamie Gritton /* 13502e92ac56SJamie Gritton * We might be ready to do a callback to the server to 13512e92ac56SJamie Gritton * see if it wants to accept/reject the connection. 13522e92ac56SJamie Gritton */ 13532e92ac56SJamie Gritton sx_xlock(&client->cl_lock); 13542e92ac56SJamie Gritton if (!client->cl_done_callback) { 13552e92ac56SJamie Gritton client->cl_done_callback = TRUE; 13562e92ac56SJamie Gritton client->cl_qop = qop; 13572e92ac56SJamie Gritton client->cl_rawcred.qop = _rpc_gss_num_to_qop( 13582e92ac56SJamie Gritton client->cl_rawcred.mechanism, qop); 13592e92ac56SJamie Gritton if (!svc_rpc_gss_callback(client, rqst)) { 13602e92ac56SJamie Gritton result = AUTH_REJECTEDCRED; 13612e92ac56SJamie Gritton sx_xunlock(&client->cl_lock); 13622e92ac56SJamie Gritton break; 13632e92ac56SJamie Gritton } 13642e92ac56SJamie Gritton } 13652e92ac56SJamie Gritton sx_xunlock(&client->cl_lock); 13662e92ac56SJamie Gritton 13672e92ac56SJamie Gritton /* 13682e92ac56SJamie Gritton * If the server has locked this client to a 13692e92ac56SJamie Gritton * particular service+qop pair, enforce that 13702e92ac56SJamie Gritton * restriction now. 13712e92ac56SJamie Gritton */ 13722e92ac56SJamie Gritton if (client->cl_locked) { 13732e92ac56SJamie Gritton if (client->cl_rawcred.service != gc.gc_svc) { 13742e92ac56SJamie Gritton result = AUTH_FAILED; 13752e92ac56SJamie Gritton break; 13762e92ac56SJamie Gritton } else if (client->cl_qop != qop) { 13772e92ac56SJamie Gritton result = AUTH_BADVERF; 13782e92ac56SJamie Gritton break; 13792e92ac56SJamie Gritton } 13802e92ac56SJamie Gritton } 13812e92ac56SJamie Gritton 13822e92ac56SJamie Gritton /* 13832e92ac56SJamie Gritton * If the qop changed, look up the new qop 13842e92ac56SJamie Gritton * name for rawcred. 13852e92ac56SJamie Gritton */ 13862e92ac56SJamie Gritton if (client->cl_qop != qop) { 13872e92ac56SJamie Gritton client->cl_qop = qop; 13882e92ac56SJamie Gritton client->cl_rawcred.qop = _rpc_gss_num_to_qop( 13892e92ac56SJamie Gritton client->cl_rawcred.mechanism, qop); 13902e92ac56SJamie Gritton } 13912e92ac56SJamie Gritton 13922e92ac56SJamie Gritton /* 13932e92ac56SJamie Gritton * Make sure we use the right service value 13942e92ac56SJamie Gritton * for unwrap/wrap. 13952e92ac56SJamie Gritton */ 13962e92ac56SJamie Gritton if (client->cl_rawcred.service != gc.gc_svc) { 13972e92ac56SJamie Gritton client->cl_rawcred.service = gc.gc_svc; 13982e92ac56SJamie Gritton svc_rpc_gss_set_flavor(client); 13992e92ac56SJamie Gritton } 14002e92ac56SJamie Gritton 14012e92ac56SJamie Gritton result = AUTH_OK; 14022e92ac56SJamie Gritton } else { 14032e92ac56SJamie Gritton if (rqst->rq_proc != NULLPROC) { 14042e92ac56SJamie Gritton result = AUTH_REJECTEDCRED; 14052e92ac56SJamie Gritton break; 14062e92ac56SJamie Gritton } 14072e92ac56SJamie Gritton 14082e92ac56SJamie Gritton call_stat = svc_sendreply(rqst, 14092e92ac56SJamie Gritton (xdrproc_t) xdr_void, (caddr_t) NULL); 14102e92ac56SJamie Gritton 14112e92ac56SJamie Gritton if (!call_stat) { 14122e92ac56SJamie Gritton result = AUTH_FAILED; 14132e92ac56SJamie Gritton break; 14142e92ac56SJamie Gritton } 14152e92ac56SJamie Gritton 14162e92ac56SJamie Gritton svc_rpc_gss_forget_client(client); 14172e92ac56SJamie Gritton 14182e92ac56SJamie Gritton result = RPCSEC_GSS_NODISPATCH; 14192e92ac56SJamie Gritton break; 14202e92ac56SJamie Gritton } 14212e92ac56SJamie Gritton break; 14222e92ac56SJamie Gritton 14232e92ac56SJamie Gritton default: 14242e92ac56SJamie Gritton result = AUTH_BADCRED; 14252e92ac56SJamie Gritton break; 14262e92ac56SJamie Gritton } 14272e92ac56SJamie Gritton out: 14282e92ac56SJamie Gritton if (client) 14292e92ac56SJamie Gritton svc_rpc_gss_release_client(client); 14302e92ac56SJamie Gritton 14312e92ac56SJamie Gritton xdr_free((xdrproc_t) xdr_rpc_gss_cred, (char *) &gc); 14322e92ac56SJamie Gritton return (result); 14332e92ac56SJamie Gritton } 14342e92ac56SJamie Gritton 14352e92ac56SJamie Gritton static bool_t 14362e92ac56SJamie Gritton svc_rpc_gss_wrap(SVCAUTH *auth, struct mbuf **mp) 14372e92ac56SJamie Gritton { 14382e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc; 14392e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 14402e92ac56SJamie Gritton 14412e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_wrap()"); 14422e92ac56SJamie Gritton 14432e92ac56SJamie Gritton cc = (struct svc_rpc_gss_cookedcred *) auth->svc_ah_private; 14442e92ac56SJamie Gritton client = cc->cc_client; 14452e92ac56SJamie Gritton if (client->cl_state != CLIENT_ESTABLISHED 14462e92ac56SJamie Gritton || cc->cc_service == rpc_gss_svc_none || *mp == NULL) { 14472e92ac56SJamie Gritton return (TRUE); 14482e92ac56SJamie Gritton } 14492e92ac56SJamie Gritton 14502e92ac56SJamie Gritton return (xdr_rpc_gss_wrap_data(mp, 14512e92ac56SJamie Gritton client->cl_ctx, client->cl_qop, 14522e92ac56SJamie Gritton cc->cc_service, cc->cc_seq)); 14532e92ac56SJamie Gritton } 14542e92ac56SJamie Gritton 14552e92ac56SJamie Gritton static bool_t 14562e92ac56SJamie Gritton svc_rpc_gss_unwrap(SVCAUTH *auth, struct mbuf **mp) 14572e92ac56SJamie Gritton { 14582e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc; 14592e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 14602e92ac56SJamie Gritton 14612e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_unwrap()"); 14622e92ac56SJamie Gritton 14632e92ac56SJamie Gritton cc = (struct svc_rpc_gss_cookedcred *) auth->svc_ah_private; 14642e92ac56SJamie Gritton client = cc->cc_client; 14652e92ac56SJamie Gritton if (client->cl_state != CLIENT_ESTABLISHED 14662e92ac56SJamie Gritton || cc->cc_service == rpc_gss_svc_none) { 14672e92ac56SJamie Gritton return (TRUE); 14682e92ac56SJamie Gritton } 14692e92ac56SJamie Gritton 14702e92ac56SJamie Gritton return (xdr_rpc_gss_unwrap_data(mp, 14712e92ac56SJamie Gritton client->cl_ctx, client->cl_qop, 14722e92ac56SJamie Gritton cc->cc_service, cc->cc_seq)); 14732e92ac56SJamie Gritton } 14742e92ac56SJamie Gritton 14752e92ac56SJamie Gritton static void 14762e92ac56SJamie Gritton svc_rpc_gss_release(SVCAUTH *auth) 14772e92ac56SJamie Gritton { 14782e92ac56SJamie Gritton struct svc_rpc_gss_cookedcred *cc; 14792e92ac56SJamie Gritton struct svc_rpc_gss_client *client; 14802e92ac56SJamie Gritton 14812e92ac56SJamie Gritton rpc_gss_log_debug("in svc_rpc_gss_release()"); 14822e92ac56SJamie Gritton 14832e92ac56SJamie Gritton cc = (struct svc_rpc_gss_cookedcred *) auth->svc_ah_private; 14842e92ac56SJamie Gritton client = cc->cc_client; 14852e92ac56SJamie Gritton svc_rpc_gss_release_client(client); 14862e92ac56SJamie Gritton } 1487