18f55a568SDoug Rabson /*- 28f55a568SDoug Rabson * Copyright (c) 2008 Doug Rabson 38f55a568SDoug Rabson * All rights reserved. 48f55a568SDoug Rabson * 58f55a568SDoug Rabson * Redistribution and use in source and binary forms, with or without 68f55a568SDoug Rabson * modification, are permitted provided that the following conditions 78f55a568SDoug Rabson * are met: 88f55a568SDoug Rabson * 1. Redistributions of source code must retain the above copyright 98f55a568SDoug Rabson * notice, this list of conditions and the following disclaimer. 108f55a568SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 118f55a568SDoug Rabson * notice, this list of conditions and the following disclaimer in the 128f55a568SDoug Rabson * documentation and/or other materials provided with the distribution. 138f55a568SDoug Rabson * 148f55a568SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158f55a568SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168f55a568SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178f55a568SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188f55a568SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198f55a568SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208f55a568SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218f55a568SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228f55a568SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238f55a568SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248f55a568SDoug Rabson * SUCH DAMAGE. 258f55a568SDoug Rabson * 268f55a568SDoug Rabson * $FreeBSD$ 278f55a568SDoug Rabson */ 288f55a568SDoug Rabson /* 298f55a568SDoug Rabson svc_rpcsec_gss.c 308f55a568SDoug Rabson 318f55a568SDoug Rabson Copyright (c) 2000 The Regents of the University of Michigan. 328f55a568SDoug Rabson All rights reserved. 338f55a568SDoug Rabson 348f55a568SDoug Rabson Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. 358f55a568SDoug Rabson All rights reserved, all wrongs reversed. 368f55a568SDoug Rabson 378f55a568SDoug Rabson Redistribution and use in source and binary forms, with or without 388f55a568SDoug Rabson modification, are permitted provided that the following conditions 398f55a568SDoug Rabson are met: 408f55a568SDoug Rabson 418f55a568SDoug Rabson 1. Redistributions of source code must retain the above copyright 428f55a568SDoug Rabson notice, this list of conditions and the following disclaimer. 438f55a568SDoug Rabson 2. Redistributions in binary form must reproduce the above copyright 448f55a568SDoug Rabson notice, this list of conditions and the following disclaimer in the 458f55a568SDoug Rabson documentation and/or other materials provided with the distribution. 468f55a568SDoug Rabson 3. Neither the name of the University nor the names of its 478f55a568SDoug Rabson contributors may be used to endorse or promote products derived 488f55a568SDoug Rabson from this software without specific prior written permission. 498f55a568SDoug Rabson 508f55a568SDoug Rabson THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 518f55a568SDoug Rabson WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 528f55a568SDoug Rabson MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 538f55a568SDoug Rabson DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 548f55a568SDoug Rabson FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 558f55a568SDoug Rabson CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 568f55a568SDoug Rabson SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 578f55a568SDoug Rabson BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 588f55a568SDoug Rabson LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 598f55a568SDoug Rabson NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 608f55a568SDoug Rabson SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 618f55a568SDoug Rabson 628f55a568SDoug Rabson $Id: svc_auth_gss.c,v 1.27 2002/01/15 15:43:00 andros Exp $ 638f55a568SDoug Rabson */ 648f55a568SDoug Rabson 658f55a568SDoug Rabson #include <stdio.h> 668f55a568SDoug Rabson #include <stdlib.h> 678f55a568SDoug Rabson #include <string.h> 688f55a568SDoug Rabson #include <pwd.h> 698f55a568SDoug Rabson #include <grp.h> 708f55a568SDoug Rabson #include <errno.h> 718f55a568SDoug Rabson #include <unistd.h> 728f55a568SDoug Rabson #include <sys/queue.h> 738f55a568SDoug Rabson #include <rpc/rpc.h> 748f55a568SDoug Rabson #include <rpc/rpcsec_gss.h> 758f55a568SDoug Rabson #include "rpcsec_gss_int.h" 768f55a568SDoug Rabson 778f55a568SDoug Rabson static bool_t svc_rpc_gss_initialised = FALSE; 788f55a568SDoug Rabson 798f55a568SDoug Rabson static bool_t svc_rpc_gss_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t); 808f55a568SDoug Rabson static bool_t svc_rpc_gss_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t); 818f55a568SDoug Rabson static enum auth_stat svc_rpc_gss(struct svc_req *, struct rpc_msg *); 828f55a568SDoug Rabson 838f55a568SDoug Rabson static struct svc_auth_ops svc_auth_gss_ops = { 848f55a568SDoug Rabson svc_rpc_gss_wrap, 858f55a568SDoug Rabson svc_rpc_gss_unwrap, 868f55a568SDoug Rabson }; 878f55a568SDoug Rabson 888f55a568SDoug Rabson struct svc_rpc_gss_callback { 898f55a568SDoug Rabson SLIST_ENTRY(svc_rpc_gss_callback) cb_link; 908f55a568SDoug Rabson rpc_gss_callback_t cb_callback; 918f55a568SDoug Rabson }; 928f55a568SDoug Rabson static SLIST_HEAD(svc_rpc_gss_callback_list, svc_rpc_gss_callback) 9313e403fdSAntoine Brodin svc_rpc_gss_callbacks = SLIST_HEAD_INITIALIZER(svc_rpc_gss_callbacks); 948f55a568SDoug Rabson 958f55a568SDoug Rabson struct svc_rpc_gss_svc_name { 968f55a568SDoug Rabson SLIST_ENTRY(svc_rpc_gss_svc_name) sn_link; 978f55a568SDoug Rabson char *sn_principal; 988f55a568SDoug Rabson gss_OID sn_mech; 998f55a568SDoug Rabson u_int sn_req_time; 1008f55a568SDoug Rabson gss_cred_id_t sn_cred; 1018f55a568SDoug Rabson u_int sn_program; 1028f55a568SDoug Rabson u_int sn_version; 1038f55a568SDoug Rabson }; 1048f55a568SDoug Rabson static SLIST_HEAD(svc_rpc_gss_svc_name_list, svc_rpc_gss_svc_name) 10513e403fdSAntoine Brodin svc_rpc_gss_svc_names = SLIST_HEAD_INITIALIZER(svc_rpc_gss_svc_names); 1068f55a568SDoug Rabson 1078f55a568SDoug Rabson enum svc_rpc_gss_client_state { 1088f55a568SDoug Rabson CLIENT_NEW, /* still authenticating */ 1098f55a568SDoug Rabson CLIENT_ESTABLISHED, /* context established */ 1108f55a568SDoug Rabson CLIENT_STALE /* garbage to collect */ 1118f55a568SDoug Rabson }; 1128f55a568SDoug Rabson 1138f55a568SDoug Rabson #define SVC_RPC_GSS_SEQWINDOW 128 1148f55a568SDoug Rabson 1158f55a568SDoug Rabson struct svc_rpc_gss_client { 1168f55a568SDoug Rabson TAILQ_ENTRY(svc_rpc_gss_client) cl_link; 1178f55a568SDoug Rabson TAILQ_ENTRY(svc_rpc_gss_client) cl_alllink; 1188f55a568SDoug Rabson uint32_t cl_id; 1198f55a568SDoug Rabson time_t cl_expiration; /* when to gc */ 1208f55a568SDoug Rabson enum svc_rpc_gss_client_state cl_state; /* client state */ 1218f55a568SDoug Rabson bool_t cl_locked; /* fixed service+qop */ 1228f55a568SDoug Rabson gss_ctx_id_t cl_ctx; /* context id */ 1238f55a568SDoug Rabson gss_cred_id_t cl_creds; /* delegated creds */ 1248f55a568SDoug Rabson gss_name_t cl_cname; /* client name */ 1258f55a568SDoug Rabson struct svc_rpc_gss_svc_name *cl_sname; /* server name used */ 1268f55a568SDoug Rabson rpc_gss_rawcred_t cl_rawcred; /* raw credentials */ 1278f55a568SDoug Rabson rpc_gss_ucred_t cl_ucred; /* unix-style credentials */ 1288f55a568SDoug Rabson bool_t cl_done_callback; /* TRUE after call */ 1298f55a568SDoug Rabson void *cl_cookie; /* user cookie from callback */ 1308f55a568SDoug Rabson gid_t cl_gid_storage[NGRPS]; 1318f55a568SDoug Rabson gss_OID cl_mech; /* mechanism */ 1328f55a568SDoug Rabson gss_qop_t cl_qop; /* quality of protection */ 1338f55a568SDoug Rabson u_int cl_seq; /* current sequence number */ 1348f55a568SDoug Rabson u_int cl_win; /* sequence window size */ 1358f55a568SDoug Rabson u_int cl_seqlast; /* sequence window origin */ 1368f55a568SDoug Rabson uint32_t cl_seqmask[SVC_RPC_GSS_SEQWINDOW/32]; /* bitmask of seqnums */ 1378f55a568SDoug Rabson gss_buffer_desc cl_verf; /* buffer for verf checksum */ 1388f55a568SDoug Rabson }; 1398f55a568SDoug Rabson TAILQ_HEAD(svc_rpc_gss_client_list, svc_rpc_gss_client); 1408f55a568SDoug Rabson 1418f55a568SDoug Rabson #define CLIENT_HASH_SIZE 256 1428f55a568SDoug Rabson #define CLIENT_MAX 128 143ae824d80SEd Schouten static struct svc_rpc_gss_client_list svc_rpc_gss_client_hash[CLIENT_HASH_SIZE]; 144ae824d80SEd Schouten static struct svc_rpc_gss_client_list svc_rpc_gss_clients; 1458f55a568SDoug Rabson static size_t svc_rpc_gss_client_count; 1468f55a568SDoug Rabson static uint32_t svc_rpc_gss_next_clientid = 1; 1478f55a568SDoug Rabson 1488f55a568SDoug Rabson #ifdef __GNUC__ 1498f55a568SDoug Rabson static void svc_rpc_gss_init(void) __attribute__ ((constructor)); 1508f55a568SDoug Rabson #endif 1518f55a568SDoug Rabson 1528f55a568SDoug Rabson static void 1538f55a568SDoug Rabson svc_rpc_gss_init(void) 1548f55a568SDoug Rabson { 1558f55a568SDoug Rabson int i; 1568f55a568SDoug Rabson 1578f55a568SDoug Rabson if (!svc_rpc_gss_initialised) { 1588f55a568SDoug Rabson for (i = 0; i < CLIENT_HASH_SIZE; i++) 1598f55a568SDoug Rabson TAILQ_INIT(&svc_rpc_gss_client_hash[i]); 1608f55a568SDoug Rabson TAILQ_INIT(&svc_rpc_gss_clients); 1618f55a568SDoug Rabson svc_auth_reg(RPCSEC_GSS, svc_rpc_gss); 1628f55a568SDoug Rabson svc_rpc_gss_initialised = TRUE; 1638f55a568SDoug Rabson } 1648f55a568SDoug Rabson } 1658f55a568SDoug Rabson 1668f55a568SDoug Rabson bool_t 1678f55a568SDoug Rabson rpc_gss_set_callback(rpc_gss_callback_t *cb) 1688f55a568SDoug Rabson { 1698f55a568SDoug Rabson struct svc_rpc_gss_callback *scb; 1708f55a568SDoug Rabson 171a9148abdSDoug Rabson scb = mem_alloc(sizeof(struct svc_rpc_gss_callback)); 1728f55a568SDoug Rabson if (!scb) { 1738f55a568SDoug Rabson _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOMEM); 1748f55a568SDoug Rabson return (FALSE); 1758f55a568SDoug Rabson } 1768f55a568SDoug Rabson scb->cb_callback = *cb; 1778f55a568SDoug Rabson SLIST_INSERT_HEAD(&svc_rpc_gss_callbacks, scb, cb_link); 1788f55a568SDoug Rabson 1798f55a568SDoug Rabson return (TRUE); 1808f55a568SDoug Rabson } 1818f55a568SDoug Rabson 1828f55a568SDoug Rabson bool_t 1838f55a568SDoug Rabson rpc_gss_set_svc_name(const char *principal, const char *mechanism, 1848f55a568SDoug Rabson u_int req_time, u_int program, u_int version) 1858f55a568SDoug Rabson { 1868f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 1878f55a568SDoug Rabson struct svc_rpc_gss_svc_name *sname; 1888f55a568SDoug Rabson gss_buffer_desc namebuf; 1898f55a568SDoug Rabson gss_name_t name; 1908f55a568SDoug Rabson gss_OID mech_oid; 1918f55a568SDoug Rabson gss_OID_set_desc oid_set; 1928f55a568SDoug Rabson gss_cred_id_t cred; 1938f55a568SDoug Rabson 1948f55a568SDoug Rabson svc_rpc_gss_init(); 1958f55a568SDoug Rabson 1968f55a568SDoug Rabson if (!rpc_gss_mech_to_oid(mechanism, &mech_oid)) 1978f55a568SDoug Rabson return (FALSE); 1988f55a568SDoug Rabson oid_set.count = 1; 1998f55a568SDoug Rabson oid_set.elements = mech_oid; 2008f55a568SDoug Rabson 2018f55a568SDoug Rabson namebuf.value = (void *)(intptr_t) principal; 2028f55a568SDoug Rabson namebuf.length = strlen(principal); 2038f55a568SDoug Rabson 2048f55a568SDoug Rabson maj_stat = gss_import_name(&min_stat, &namebuf, 2058f55a568SDoug Rabson GSS_C_NT_HOSTBASED_SERVICE, &name); 2068f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) 2078f55a568SDoug Rabson return (FALSE); 2088f55a568SDoug Rabson 2098f55a568SDoug Rabson maj_stat = gss_acquire_cred(&min_stat, name, 2108f55a568SDoug Rabson req_time, &oid_set, GSS_C_ACCEPT, &cred, NULL, NULL); 2118f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) 2128f55a568SDoug Rabson return (FALSE); 2138f55a568SDoug Rabson 2148f55a568SDoug Rabson gss_release_name(&min_stat, &name); 2158f55a568SDoug Rabson 2168f55a568SDoug Rabson sname = malloc(sizeof(struct svc_rpc_gss_svc_name)); 2178f55a568SDoug Rabson if (!sname) 2188f55a568SDoug Rabson return (FALSE); 2198f55a568SDoug Rabson sname->sn_principal = strdup(principal); 2208f55a568SDoug Rabson sname->sn_mech = mech_oid; 2218f55a568SDoug Rabson sname->sn_req_time = req_time; 2228f55a568SDoug Rabson sname->sn_cred = cred; 2238f55a568SDoug Rabson sname->sn_program = program; 2248f55a568SDoug Rabson sname->sn_version = version; 2258f55a568SDoug Rabson SLIST_INSERT_HEAD(&svc_rpc_gss_svc_names, sname, sn_link); 2268f55a568SDoug Rabson 2278f55a568SDoug Rabson return (TRUE); 2288f55a568SDoug Rabson } 2298f55a568SDoug Rabson 2308f55a568SDoug Rabson bool_t 2318f55a568SDoug Rabson rpc_gss_get_principal_name(rpc_gss_principal_t *principal, 2328f55a568SDoug Rabson const char *mech, const char *name, const char *node, const char *domain) 2338f55a568SDoug Rabson { 2348f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 2358f55a568SDoug Rabson gss_OID mech_oid; 2368f55a568SDoug Rabson size_t namelen; 2378f55a568SDoug Rabson gss_buffer_desc buf; 2388f55a568SDoug Rabson gss_name_t gss_name, gss_mech_name; 2398f55a568SDoug Rabson rpc_gss_principal_t result; 2408f55a568SDoug Rabson 2418f55a568SDoug Rabson svc_rpc_gss_init(); 2428f55a568SDoug Rabson 2438f55a568SDoug Rabson if (!rpc_gss_mech_to_oid(mech, &mech_oid)) 2448f55a568SDoug Rabson return (FALSE); 2458f55a568SDoug Rabson 2468f55a568SDoug Rabson /* 2478f55a568SDoug Rabson * Construct a gss_buffer containing the full name formatted 2488f55a568SDoug Rabson * as "name/node@domain" where node and domain are optional. 2498f55a568SDoug Rabson */ 2508f55a568SDoug Rabson namelen = strlen(name); 2518f55a568SDoug Rabson if (node) { 2528f55a568SDoug Rabson namelen += strlen(node) + 1; 2538f55a568SDoug Rabson } 2548f55a568SDoug Rabson if (domain) { 2558f55a568SDoug Rabson namelen += strlen(domain) + 1; 2568f55a568SDoug Rabson } 2578f55a568SDoug Rabson 258a9148abdSDoug Rabson buf.value = mem_alloc(namelen); 2598f55a568SDoug Rabson buf.length = namelen; 2608f55a568SDoug Rabson strcpy((char *) buf.value, name); 2618f55a568SDoug Rabson if (node) { 2628f55a568SDoug Rabson strcat((char *) buf.value, "/"); 2638f55a568SDoug Rabson strcat((char *) buf.value, node); 2648f55a568SDoug Rabson } 2658f55a568SDoug Rabson if (domain) { 2668f55a568SDoug Rabson strcat((char *) buf.value, "@"); 2678f55a568SDoug Rabson strcat((char *) buf.value, domain); 2688f55a568SDoug Rabson } 2698f55a568SDoug Rabson 2708f55a568SDoug Rabson /* 2718f55a568SDoug Rabson * Convert that to a gss_name_t and then convert that to a 2728f55a568SDoug Rabson * mechanism name in the selected mechanism. 2738f55a568SDoug Rabson */ 2748f55a568SDoug Rabson maj_stat = gss_import_name(&min_stat, &buf, 2758f55a568SDoug Rabson GSS_C_NT_USER_NAME, &gss_name); 276a9148abdSDoug Rabson mem_free(buf.value, buf.length); 2778f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 2788f55a568SDoug Rabson log_status("gss_import_name", mech_oid, maj_stat, min_stat); 2798f55a568SDoug Rabson return (FALSE); 2808f55a568SDoug Rabson } 2818f55a568SDoug Rabson maj_stat = gss_canonicalize_name(&min_stat, gss_name, mech_oid, 2828f55a568SDoug Rabson &gss_mech_name); 2838f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 2848f55a568SDoug Rabson log_status("gss_canonicalize_name", mech_oid, maj_stat, 2858f55a568SDoug Rabson min_stat); 2868f55a568SDoug Rabson gss_release_name(&min_stat, &gss_name); 2878f55a568SDoug Rabson return (FALSE); 2888f55a568SDoug Rabson } 2898f55a568SDoug Rabson gss_release_name(&min_stat, &gss_name); 2908f55a568SDoug Rabson 2918f55a568SDoug Rabson /* 2928f55a568SDoug Rabson * Export the mechanism name and use that to construct the 2938f55a568SDoug Rabson * rpc_gss_principal_t result. 2948f55a568SDoug Rabson */ 2958f55a568SDoug Rabson maj_stat = gss_export_name(&min_stat, gss_mech_name, &buf); 2968f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 2978f55a568SDoug Rabson log_status("gss_export_name", mech_oid, maj_stat, min_stat); 2988f55a568SDoug Rabson gss_release_name(&min_stat, &gss_mech_name); 2998f55a568SDoug Rabson return (FALSE); 3008f55a568SDoug Rabson } 3018f55a568SDoug Rabson gss_release_name(&min_stat, &gss_mech_name); 3028f55a568SDoug Rabson 303a9148abdSDoug Rabson result = mem_alloc(sizeof(int) + buf.length); 3048f55a568SDoug Rabson if (!result) { 3058f55a568SDoug Rabson gss_release_buffer(&min_stat, &buf); 3068f55a568SDoug Rabson return (FALSE); 3078f55a568SDoug Rabson } 3088f55a568SDoug Rabson result->len = buf.length; 3098f55a568SDoug Rabson memcpy(result->name, buf.value, buf.length); 3108f55a568SDoug Rabson gss_release_buffer(&min_stat, &buf); 3118f55a568SDoug Rabson 3128f55a568SDoug Rabson *principal = result; 3138f55a568SDoug Rabson return (TRUE); 3148f55a568SDoug Rabson } 3158f55a568SDoug Rabson 3168f55a568SDoug Rabson bool_t 3178f55a568SDoug Rabson rpc_gss_getcred(struct svc_req *req, rpc_gss_rawcred_t **rcred, 3188f55a568SDoug Rabson rpc_gss_ucred_t **ucred, void **cookie) 3198f55a568SDoug Rabson { 3208f55a568SDoug Rabson struct svc_rpc_gss_client *client; 3218f55a568SDoug Rabson 3228f55a568SDoug Rabson if (req->rq_cred.oa_flavor != RPCSEC_GSS) 3238f55a568SDoug Rabson return (FALSE); 3248f55a568SDoug Rabson 3258f55a568SDoug Rabson client = req->rq_clntcred; 3268f55a568SDoug Rabson if (rcred) 3278f55a568SDoug Rabson *rcred = &client->cl_rawcred; 3288f55a568SDoug Rabson if (ucred) 3298f55a568SDoug Rabson *ucred = &client->cl_ucred; 3308f55a568SDoug Rabson if (cookie) 3318f55a568SDoug Rabson *cookie = client->cl_cookie; 3328f55a568SDoug Rabson return (TRUE); 3338f55a568SDoug Rabson } 3348f55a568SDoug Rabson 3358f55a568SDoug Rabson int 3368f55a568SDoug Rabson rpc_gss_svc_max_data_length(struct svc_req *req, int max_tp_unit_len) 3378f55a568SDoug Rabson { 3388f55a568SDoug Rabson struct svc_rpc_gss_client *client = req->rq_clntcred; 3398f55a568SDoug Rabson int want_conf; 3408f55a568SDoug Rabson OM_uint32 max; 3418f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 3428f55a568SDoug Rabson int result; 3438f55a568SDoug Rabson 3448f55a568SDoug Rabson switch (client->cl_rawcred.service) { 3458f55a568SDoug Rabson case rpc_gss_svc_none: 3468f55a568SDoug Rabson return (max_tp_unit_len); 3478f55a568SDoug Rabson break; 3488f55a568SDoug Rabson 3498f55a568SDoug Rabson case rpc_gss_svc_default: 3508f55a568SDoug Rabson case rpc_gss_svc_integrity: 3518f55a568SDoug Rabson want_conf = FALSE; 3528f55a568SDoug Rabson break; 3538f55a568SDoug Rabson 3548f55a568SDoug Rabson case rpc_gss_svc_privacy: 3558f55a568SDoug Rabson want_conf = TRUE; 3568f55a568SDoug Rabson break; 3578f55a568SDoug Rabson 3588f55a568SDoug Rabson default: 3598f55a568SDoug Rabson return (0); 3608f55a568SDoug Rabson } 3618f55a568SDoug Rabson 3628f55a568SDoug Rabson maj_stat = gss_wrap_size_limit(&min_stat, client->cl_ctx, want_conf, 3638f55a568SDoug Rabson client->cl_qop, max_tp_unit_len, &max); 3648f55a568SDoug Rabson 3658f55a568SDoug Rabson if (maj_stat == GSS_S_COMPLETE) { 3668f55a568SDoug Rabson result = (int) max; 3678f55a568SDoug Rabson if (result < 0) 3688f55a568SDoug Rabson result = 0; 3698f55a568SDoug Rabson return (result); 3708f55a568SDoug Rabson } else { 3718f55a568SDoug Rabson log_status("gss_wrap_size_limit", client->cl_mech, 3728f55a568SDoug Rabson maj_stat, min_stat); 3738f55a568SDoug Rabson return (0); 3748f55a568SDoug Rabson } 3758f55a568SDoug Rabson } 3768f55a568SDoug Rabson 3778f55a568SDoug Rabson static struct svc_rpc_gss_client * 3788f55a568SDoug Rabson svc_rpc_gss_find_client(uint32_t clientid) 3798f55a568SDoug Rabson { 3808f55a568SDoug Rabson struct svc_rpc_gss_client *client; 3818f55a568SDoug Rabson struct svc_rpc_gss_client_list *list; 3828f55a568SDoug Rabson 3838f55a568SDoug Rabson 3848f55a568SDoug Rabson log_debug("in svc_rpc_gss_find_client(%d)", clientid); 3858f55a568SDoug Rabson 3868f55a568SDoug Rabson list = &svc_rpc_gss_client_hash[clientid % CLIENT_HASH_SIZE]; 3878f55a568SDoug Rabson TAILQ_FOREACH(client, list, cl_link) { 3888f55a568SDoug Rabson if (client->cl_id == clientid) { 3898f55a568SDoug Rabson /* 3908f55a568SDoug Rabson * Move this client to the front of the LRU 3918f55a568SDoug Rabson * list. 3928f55a568SDoug Rabson */ 3938f55a568SDoug Rabson TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); 3948f55a568SDoug Rabson TAILQ_INSERT_HEAD(&svc_rpc_gss_clients, client, 3958f55a568SDoug Rabson cl_alllink); 3968f55a568SDoug Rabson return client; 3978f55a568SDoug Rabson } 3988f55a568SDoug Rabson } 3998f55a568SDoug Rabson 4008f55a568SDoug Rabson return (NULL); 4018f55a568SDoug Rabson } 4028f55a568SDoug Rabson 4038f55a568SDoug Rabson static struct svc_rpc_gss_client * 4048f55a568SDoug Rabson svc_rpc_gss_create_client(void) 4058f55a568SDoug Rabson { 4068f55a568SDoug Rabson struct svc_rpc_gss_client *client; 4078f55a568SDoug Rabson struct svc_rpc_gss_client_list *list; 4088f55a568SDoug Rabson 4098f55a568SDoug Rabson log_debug("in svc_rpc_gss_create_client()"); 4108f55a568SDoug Rabson 4118f55a568SDoug Rabson client = mem_alloc(sizeof(struct svc_rpc_gss_client)); 4128f55a568SDoug Rabson memset(client, 0, sizeof(struct svc_rpc_gss_client)); 4138f55a568SDoug Rabson client->cl_id = svc_rpc_gss_next_clientid++; 4148f55a568SDoug Rabson list = &svc_rpc_gss_client_hash[client->cl_id % CLIENT_HASH_SIZE]; 4158f55a568SDoug Rabson TAILQ_INSERT_HEAD(list, client, cl_link); 4168f55a568SDoug Rabson TAILQ_INSERT_HEAD(&svc_rpc_gss_clients, client, cl_alllink); 4178f55a568SDoug Rabson 4188f55a568SDoug Rabson /* 4198f55a568SDoug Rabson * Start the client off with a short expiration time. We will 4208f55a568SDoug Rabson * try to get a saner value from the client creds later. 4218f55a568SDoug Rabson */ 4228f55a568SDoug Rabson client->cl_state = CLIENT_NEW; 4238f55a568SDoug Rabson client->cl_locked = FALSE; 4248f55a568SDoug Rabson client->cl_expiration = time(0) + 5*60; 4258f55a568SDoug Rabson svc_rpc_gss_client_count++; 4268f55a568SDoug Rabson 4278f55a568SDoug Rabson return (client); 4288f55a568SDoug Rabson } 4298f55a568SDoug Rabson 4308f55a568SDoug Rabson static void 4318f55a568SDoug Rabson svc_rpc_gss_destroy_client(struct svc_rpc_gss_client *client) 4328f55a568SDoug Rabson { 4338f55a568SDoug Rabson struct svc_rpc_gss_client_list *list; 4348f55a568SDoug Rabson OM_uint32 min_stat; 4358f55a568SDoug Rabson 4368f55a568SDoug Rabson log_debug("in svc_rpc_gss_destroy_client()"); 4378f55a568SDoug Rabson 4388f55a568SDoug Rabson if (client->cl_ctx) 4398f55a568SDoug Rabson gss_delete_sec_context(&min_stat, 4408f55a568SDoug Rabson &client->cl_ctx, GSS_C_NO_BUFFER); 4418f55a568SDoug Rabson 4428f55a568SDoug Rabson if (client->cl_cname) 4438f55a568SDoug Rabson gss_release_name(&min_stat, &client->cl_cname); 4448f55a568SDoug Rabson 4458f55a568SDoug Rabson if (client->cl_rawcred.client_principal) 446a9148abdSDoug Rabson mem_free(client->cl_rawcred.client_principal, 447a9148abdSDoug Rabson sizeof(*client->cl_rawcred.client_principal) 448a9148abdSDoug Rabson + client->cl_rawcred.client_principal->len); 4498f55a568SDoug Rabson 4508f55a568SDoug Rabson if (client->cl_verf.value) 4518f55a568SDoug Rabson gss_release_buffer(&min_stat, &client->cl_verf); 4528f55a568SDoug Rabson 4538f55a568SDoug Rabson list = &svc_rpc_gss_client_hash[client->cl_id % CLIENT_HASH_SIZE]; 4548f55a568SDoug Rabson TAILQ_REMOVE(list, client, cl_link); 4558f55a568SDoug Rabson TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); 4568f55a568SDoug Rabson svc_rpc_gss_client_count--; 4578f55a568SDoug Rabson mem_free(client, sizeof(*client)); 4588f55a568SDoug Rabson } 4598f55a568SDoug Rabson 4608f55a568SDoug Rabson static void 4618f55a568SDoug Rabson svc_rpc_gss_timeout_clients(void) 4628f55a568SDoug Rabson { 4638f55a568SDoug Rabson struct svc_rpc_gss_client *client; 4648f55a568SDoug Rabson struct svc_rpc_gss_client *nclient; 4658f55a568SDoug Rabson time_t now = time(0); 4668f55a568SDoug Rabson 4678f55a568SDoug Rabson log_debug("in svc_rpc_gss_timeout_clients()"); 4688f55a568SDoug Rabson /* 4698f55a568SDoug Rabson * First enforce the max client limit. We keep 4708f55a568SDoug Rabson * svc_rpc_gss_clients in LRU order. 4718f55a568SDoug Rabson */ 4728f55a568SDoug Rabson while (svc_rpc_gss_client_count > CLIENT_MAX) 4738f55a568SDoug Rabson svc_rpc_gss_destroy_client(TAILQ_LAST(&svc_rpc_gss_clients, 4748f55a568SDoug Rabson svc_rpc_gss_client_list)); 4758f55a568SDoug Rabson TAILQ_FOREACH_SAFE(client, &svc_rpc_gss_clients, cl_alllink, nclient) { 4768f55a568SDoug Rabson if (client->cl_state == CLIENT_STALE 4778f55a568SDoug Rabson || now > client->cl_expiration) { 4788f55a568SDoug Rabson log_debug("expiring client %p", client); 4798f55a568SDoug Rabson svc_rpc_gss_destroy_client(client); 4808f55a568SDoug Rabson } 4818f55a568SDoug Rabson } 4828f55a568SDoug Rabson } 4838f55a568SDoug Rabson 4848f55a568SDoug Rabson #ifdef DEBUG 4858f55a568SDoug Rabson /* 4868f55a568SDoug Rabson * OID<->string routines. These are uuuuugly. 4878f55a568SDoug Rabson */ 4888f55a568SDoug Rabson static OM_uint32 4898f55a568SDoug Rabson gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) 4908f55a568SDoug Rabson { 4918f55a568SDoug Rabson char numstr[128]; 4928f55a568SDoug Rabson unsigned long number; 4938f55a568SDoug Rabson int numshift; 4948f55a568SDoug Rabson size_t string_length; 4958f55a568SDoug Rabson size_t i; 4968f55a568SDoug Rabson unsigned char *cp; 4978f55a568SDoug Rabson char *bp; 4988f55a568SDoug Rabson 4998f55a568SDoug Rabson /* Decoded according to krb5/gssapi_krb5.c */ 5008f55a568SDoug Rabson 5018f55a568SDoug Rabson /* First determine the size of the string */ 5028f55a568SDoug Rabson string_length = 0; 5038f55a568SDoug Rabson number = 0; 5048f55a568SDoug Rabson numshift = 0; 5058f55a568SDoug Rabson cp = (unsigned char *) oid->elements; 5068f55a568SDoug Rabson number = (unsigned long) cp[0]; 5078f55a568SDoug Rabson sprintf(numstr, "%ld ", number/40); 5088f55a568SDoug Rabson string_length += strlen(numstr); 5098f55a568SDoug Rabson sprintf(numstr, "%ld ", number%40); 5108f55a568SDoug Rabson string_length += strlen(numstr); 5118f55a568SDoug Rabson for (i=1; i<oid->length; i++) { 5128f55a568SDoug Rabson if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) { 5138f55a568SDoug Rabson number = (number << 7) | (cp[i] & 0x7f); 5148f55a568SDoug Rabson numshift += 7; 5158f55a568SDoug Rabson } 5168f55a568SDoug Rabson else { 5178f55a568SDoug Rabson *minor_status = 0; 5188f55a568SDoug Rabson return(GSS_S_FAILURE); 5198f55a568SDoug Rabson } 5208f55a568SDoug Rabson if ((cp[i] & 0x80) == 0) { 5218f55a568SDoug Rabson sprintf(numstr, "%ld ", number); 5228f55a568SDoug Rabson string_length += strlen(numstr); 5238f55a568SDoug Rabson number = 0; 5248f55a568SDoug Rabson numshift = 0; 5258f55a568SDoug Rabson } 5268f55a568SDoug Rabson } 5278f55a568SDoug Rabson /* 5288f55a568SDoug Rabson * If we get here, we've calculated the length of "n n n ... n ". Add 4 5298f55a568SDoug Rabson * here for "{ " and "}\0". 5308f55a568SDoug Rabson */ 5318f55a568SDoug Rabson string_length += 4; 532a9148abdSDoug Rabson if ((bp = (char *) mem_alloc(string_length))) { 5338f55a568SDoug Rabson strcpy(bp, "{ "); 5348f55a568SDoug Rabson number = (unsigned long) cp[0]; 5358f55a568SDoug Rabson sprintf(numstr, "%ld ", number/40); 5368f55a568SDoug Rabson strcat(bp, numstr); 5378f55a568SDoug Rabson sprintf(numstr, "%ld ", number%40); 5388f55a568SDoug Rabson strcat(bp, numstr); 5398f55a568SDoug Rabson number = 0; 5408f55a568SDoug Rabson cp = (unsigned char *) oid->elements; 5418f55a568SDoug Rabson for (i=1; i<oid->length; i++) { 5428f55a568SDoug Rabson number = (number << 7) | (cp[i] & 0x7f); 5438f55a568SDoug Rabson if ((cp[i] & 0x80) == 0) { 5448f55a568SDoug Rabson sprintf(numstr, "%ld ", number); 5458f55a568SDoug Rabson strcat(bp, numstr); 5468f55a568SDoug Rabson number = 0; 5478f55a568SDoug Rabson } 5488f55a568SDoug Rabson } 5498f55a568SDoug Rabson strcat(bp, "}"); 5508f55a568SDoug Rabson oid_str->length = strlen(bp)+1; 5518f55a568SDoug Rabson oid_str->value = (void *) bp; 5528f55a568SDoug Rabson *minor_status = 0; 5538f55a568SDoug Rabson return(GSS_S_COMPLETE); 5548f55a568SDoug Rabson } 5558f55a568SDoug Rabson *minor_status = 0; 5568f55a568SDoug Rabson return(GSS_S_FAILURE); 5578f55a568SDoug Rabson } 5588f55a568SDoug Rabson #endif 5598f55a568SDoug Rabson 5608f55a568SDoug Rabson static void 5618f55a568SDoug Rabson svc_rpc_gss_build_ucred(struct svc_rpc_gss_client *client, 5628f55a568SDoug Rabson const gss_name_t name) 5638f55a568SDoug Rabson { 5648f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 5658f55a568SDoug Rabson char buf[128]; 5668f55a568SDoug Rabson uid_t uid; 5678f55a568SDoug Rabson struct passwd pwd, *pw; 5688f55a568SDoug Rabson rpc_gss_ucred_t *uc = &client->cl_ucred; 5698f55a568SDoug Rabson 5708f55a568SDoug Rabson uc->uid = 65534; 5718f55a568SDoug Rabson uc->gid = 65534; 5728f55a568SDoug Rabson uc->gidlen = 0; 5738f55a568SDoug Rabson uc->gidlist = client->cl_gid_storage; 5748f55a568SDoug Rabson 5758f55a568SDoug Rabson maj_stat = gss_pname_to_uid(&min_stat, name, client->cl_mech, &uid); 5768f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) 5778f55a568SDoug Rabson return; 5788f55a568SDoug Rabson 5798f55a568SDoug Rabson getpwuid_r(uid, &pwd, buf, sizeof(buf), &pw); 5808f55a568SDoug Rabson if (pw) { 5818f55a568SDoug Rabson int len = NGRPS; 5828f55a568SDoug Rabson uc->uid = pw->pw_uid; 5838f55a568SDoug Rabson uc->gid = pw->pw_gid; 5848f55a568SDoug Rabson uc->gidlist = client->cl_gid_storage; 5858f55a568SDoug Rabson getgrouplist(pw->pw_name, pw->pw_gid, uc->gidlist, &len); 5868f55a568SDoug Rabson uc->gidlen = len; 5878f55a568SDoug Rabson } 5888f55a568SDoug Rabson } 5898f55a568SDoug Rabson 5908f55a568SDoug Rabson static bool_t 5918f55a568SDoug Rabson svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client, 5928f55a568SDoug Rabson struct svc_req *rqst, 5938f55a568SDoug Rabson struct rpc_gss_init_res *gr, 5948f55a568SDoug Rabson struct rpc_gss_cred *gc) 5958f55a568SDoug Rabson { 5968f55a568SDoug Rabson gss_buffer_desc recv_tok; 5978f55a568SDoug Rabson gss_OID mech; 5988f55a568SDoug Rabson OM_uint32 maj_stat = 0, min_stat = 0, ret_flags; 5998f55a568SDoug Rabson OM_uint32 cred_lifetime; 6008f55a568SDoug Rabson struct svc_rpc_gss_svc_name *sname; 6018f55a568SDoug Rabson 6028f55a568SDoug Rabson log_debug("in svc_rpc_gss_accept_context()"); 6038f55a568SDoug Rabson 6048f55a568SDoug Rabson /* Deserialize arguments. */ 6058f55a568SDoug Rabson memset(&recv_tok, 0, sizeof(recv_tok)); 6068f55a568SDoug Rabson 6078f55a568SDoug Rabson if (!svc_getargs(rqst->rq_xprt, 6088f55a568SDoug Rabson (xdrproc_t) xdr_gss_buffer_desc, 6098f55a568SDoug Rabson (caddr_t) &recv_tok)) { 6108f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 6118f55a568SDoug Rabson return (FALSE); 6128f55a568SDoug Rabson } 6138f55a568SDoug Rabson 6148f55a568SDoug Rabson /* 6158f55a568SDoug Rabson * First time round, try all the server names we have until 6168f55a568SDoug Rabson * one matches. Afterwards, stick with that one. 6178f55a568SDoug Rabson */ 6188f55a568SDoug Rabson if (!client->cl_sname) { 6198f55a568SDoug Rabson SLIST_FOREACH(sname, &svc_rpc_gss_svc_names, sn_link) { 6208f55a568SDoug Rabson if (sname->sn_program == rqst->rq_prog 6218f55a568SDoug Rabson && sname->sn_version == rqst->rq_vers) { 6228f55a568SDoug Rabson gr->gr_major = gss_accept_sec_context( 6238f55a568SDoug Rabson &gr->gr_minor, 6248f55a568SDoug Rabson &client->cl_ctx, 6258f55a568SDoug Rabson sname->sn_cred, 6268f55a568SDoug Rabson &recv_tok, 6278f55a568SDoug Rabson GSS_C_NO_CHANNEL_BINDINGS, 6288f55a568SDoug Rabson &client->cl_cname, 6298f55a568SDoug Rabson &mech, 6308f55a568SDoug Rabson &gr->gr_token, 6318f55a568SDoug Rabson &ret_flags, 6328f55a568SDoug Rabson &cred_lifetime, 6338f55a568SDoug Rabson &client->cl_creds); 634a9148abdSDoug Rabson client->cl_sname = sname; 635a9148abdSDoug Rabson break; 6368f55a568SDoug Rabson } 6378f55a568SDoug Rabson } 638a9148abdSDoug Rabson if (!sname) { 639a9148abdSDoug Rabson xdr_free((xdrproc_t) xdr_gss_buffer_desc, 640a9148abdSDoug Rabson (char *) &recv_tok); 641a9148abdSDoug Rabson return (FALSE); 642a9148abdSDoug Rabson } 6438f55a568SDoug Rabson } else { 6448f55a568SDoug Rabson gr->gr_major = gss_accept_sec_context( 6458f55a568SDoug Rabson &gr->gr_minor, 6468f55a568SDoug Rabson &client->cl_ctx, 6478f55a568SDoug Rabson client->cl_sname->sn_cred, 6488f55a568SDoug Rabson &recv_tok, 6498f55a568SDoug Rabson GSS_C_NO_CHANNEL_BINDINGS, 6508f55a568SDoug Rabson &client->cl_cname, 6518f55a568SDoug Rabson &mech, 6528f55a568SDoug Rabson &gr->gr_token, 6538f55a568SDoug Rabson &ret_flags, 6548f55a568SDoug Rabson &cred_lifetime, 6558f55a568SDoug Rabson NULL); 6568f55a568SDoug Rabson } 6578f55a568SDoug Rabson 6588f55a568SDoug Rabson xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &recv_tok); 6598f55a568SDoug Rabson 6608f55a568SDoug Rabson /* 6618f55a568SDoug Rabson * If we get an error from gss_accept_sec_context, send the 6628f55a568SDoug Rabson * reply anyway so that the client gets a chance to see what 6638f55a568SDoug Rabson * is wrong. 6648f55a568SDoug Rabson */ 6658f55a568SDoug Rabson if (gr->gr_major != GSS_S_COMPLETE && 6668f55a568SDoug Rabson gr->gr_major != GSS_S_CONTINUE_NEEDED) { 6678f55a568SDoug Rabson log_status("accept_sec_context", client->cl_mech, 6688f55a568SDoug Rabson gr->gr_major, gr->gr_minor); 6698f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 670a9148abdSDoug Rabson return (TRUE); 6718f55a568SDoug Rabson } 6728f55a568SDoug Rabson 6738f55a568SDoug Rabson gr->gr_handle.value = &client->cl_id; 674a9148abdSDoug Rabson gr->gr_handle.length = sizeof(client->cl_id); 6758f55a568SDoug Rabson gr->gr_win = SVC_RPC_GSS_SEQWINDOW; 6768f55a568SDoug Rabson 6778f55a568SDoug Rabson /* Save client info. */ 6788f55a568SDoug Rabson client->cl_mech = mech; 6798f55a568SDoug Rabson client->cl_qop = GSS_C_QOP_DEFAULT; 6808f55a568SDoug Rabson client->cl_seq = gc->gc_seq; 6818f55a568SDoug Rabson client->cl_win = gr->gr_win; 6828f55a568SDoug Rabson client->cl_done_callback = FALSE; 6838f55a568SDoug Rabson 6848f55a568SDoug Rabson if (gr->gr_major == GSS_S_COMPLETE) { 6858f55a568SDoug Rabson gss_buffer_desc export_name; 6868f55a568SDoug Rabson 6878f55a568SDoug Rabson /* 6888f55a568SDoug Rabson * Change client expiration time to be near when the 6898f55a568SDoug Rabson * client creds expire (or 24 hours if we can't figure 6908f55a568SDoug Rabson * that out). 6918f55a568SDoug Rabson */ 6928f55a568SDoug Rabson if (cred_lifetime == GSS_C_INDEFINITE) 6938f55a568SDoug Rabson cred_lifetime = time(0) + 24*60*60; 6948f55a568SDoug Rabson 6958f55a568SDoug Rabson client->cl_expiration = time(0) + cred_lifetime; 6968f55a568SDoug Rabson 6978f55a568SDoug Rabson /* 6988f55a568SDoug Rabson * Fill in cred details in the rawcred structure. 6998f55a568SDoug Rabson */ 7008f55a568SDoug Rabson client->cl_rawcred.version = RPCSEC_GSS_VERSION; 7018f55a568SDoug Rabson rpc_gss_oid_to_mech(mech, &client->cl_rawcred.mechanism); 7028f55a568SDoug Rabson maj_stat = gss_export_name(&min_stat, client->cl_cname, 7038f55a568SDoug Rabson &export_name); 7048f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 7058f55a568SDoug Rabson log_status("gss_export_name", client->cl_mech, 7068f55a568SDoug Rabson maj_stat, min_stat); 7078f55a568SDoug Rabson return (FALSE); 7088f55a568SDoug Rabson } 7098f55a568SDoug Rabson client->cl_rawcred.client_principal = 710a9148abdSDoug Rabson mem_alloc(sizeof(*client->cl_rawcred.client_principal) 7118f55a568SDoug Rabson + export_name.length); 7128f55a568SDoug Rabson client->cl_rawcred.client_principal->len = export_name.length; 7138f55a568SDoug Rabson memcpy(client->cl_rawcred.client_principal->name, 7148f55a568SDoug Rabson export_name.value, export_name.length); 7158f55a568SDoug Rabson gss_release_buffer(&min_stat, &export_name); 7168f55a568SDoug Rabson client->cl_rawcred.svc_principal = 7178f55a568SDoug Rabson client->cl_sname->sn_principal; 7188f55a568SDoug Rabson client->cl_rawcred.service = gc->gc_svc; 7198f55a568SDoug Rabson 7208f55a568SDoug Rabson /* 7218f55a568SDoug Rabson * Use gss_pname_to_uid to map to unix creds. For 7228f55a568SDoug Rabson * kerberos5, this uses krb5_aname_to_localname. 7238f55a568SDoug Rabson */ 7248f55a568SDoug Rabson svc_rpc_gss_build_ucred(client, client->cl_cname); 725a9148abdSDoug Rabson gss_release_name(&min_stat, &client->cl_cname); 7268f55a568SDoug Rabson 7278f55a568SDoug Rabson #ifdef DEBUG 7288f55a568SDoug Rabson { 7298f55a568SDoug Rabson gss_buffer_desc mechname; 7308f55a568SDoug Rabson 7318f55a568SDoug Rabson gss_oid_to_str(&min_stat, mech, &mechname); 7328f55a568SDoug Rabson 7338f55a568SDoug Rabson log_debug("accepted context for %s with " 7348f55a568SDoug Rabson "<mech %.*s, qop %d, svc %d>", 7358f55a568SDoug Rabson client->cl_rawcred.client_principal->name, 7368f55a568SDoug Rabson mechname.length, (char *)mechname.value, 7378f55a568SDoug Rabson client->cl_qop, client->rawcred.service); 7388f55a568SDoug Rabson 7398f55a568SDoug Rabson gss_release_buffer(&min_stat, &mechname); 7408f55a568SDoug Rabson } 7418f55a568SDoug Rabson #endif /* DEBUG */ 7428f55a568SDoug Rabson } 7438f55a568SDoug Rabson return (TRUE); 7448f55a568SDoug Rabson } 7458f55a568SDoug Rabson 7468f55a568SDoug Rabson static bool_t 7478f55a568SDoug Rabson svc_rpc_gss_validate(struct svc_rpc_gss_client *client, struct rpc_msg *msg, 7488f55a568SDoug Rabson gss_qop_t *qop) 7498f55a568SDoug Rabson { 7508f55a568SDoug Rabson struct opaque_auth *oa; 7518f55a568SDoug Rabson gss_buffer_desc rpcbuf, checksum; 7528f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 7538f55a568SDoug Rabson gss_qop_t qop_state; 7549b118815SDoug Rabson int32_t rpchdr[128 / sizeof(int32_t)]; 7558f55a568SDoug Rabson int32_t *buf; 7568f55a568SDoug Rabson 7578f55a568SDoug Rabson log_debug("in svc_rpc_gss_validate()"); 7588f55a568SDoug Rabson 7598f55a568SDoug Rabson memset(rpchdr, 0, sizeof(rpchdr)); 7608f55a568SDoug Rabson 7618f55a568SDoug Rabson /* Reconstruct RPC header for signing (from xdr_callmsg). */ 7629b118815SDoug Rabson buf = rpchdr; 7638f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_xid); 7648f55a568SDoug Rabson IXDR_PUT_ENUM(buf, msg->rm_direction); 7658f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); 7668f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); 7678f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); 7688f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); 7698f55a568SDoug Rabson oa = &msg->rm_call.cb_cred; 7708f55a568SDoug Rabson IXDR_PUT_ENUM(buf, oa->oa_flavor); 7718f55a568SDoug Rabson IXDR_PUT_LONG(buf, oa->oa_length); 7728f55a568SDoug Rabson if (oa->oa_length) { 7738f55a568SDoug Rabson memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); 7748f55a568SDoug Rabson buf += RNDUP(oa->oa_length) / sizeof(int32_t); 7758f55a568SDoug Rabson } 7768f55a568SDoug Rabson rpcbuf.value = rpchdr; 7779b118815SDoug Rabson rpcbuf.length = (u_char *)buf - (u_char *)rpchdr; 7788f55a568SDoug Rabson 7798f55a568SDoug Rabson checksum.value = msg->rm_call.cb_verf.oa_base; 7808f55a568SDoug Rabson checksum.length = msg->rm_call.cb_verf.oa_length; 7818f55a568SDoug Rabson 7828f55a568SDoug Rabson maj_stat = gss_verify_mic(&min_stat, client->cl_ctx, &rpcbuf, &checksum, 7838f55a568SDoug Rabson &qop_state); 7848f55a568SDoug Rabson 7858f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 7868f55a568SDoug Rabson log_status("gss_verify_mic", client->cl_mech, 7878f55a568SDoug Rabson maj_stat, min_stat); 7888f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 7898f55a568SDoug Rabson return (FALSE); 7908f55a568SDoug Rabson } 7918f55a568SDoug Rabson *qop = qop_state; 7928f55a568SDoug Rabson return (TRUE); 7938f55a568SDoug Rabson } 7948f55a568SDoug Rabson 7958f55a568SDoug Rabson static bool_t 7968f55a568SDoug Rabson svc_rpc_gss_nextverf(struct svc_rpc_gss_client *client, 7978f55a568SDoug Rabson struct svc_req *rqst, u_int seq) 7988f55a568SDoug Rabson { 7998f55a568SDoug Rabson gss_buffer_desc signbuf; 8008f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 8018f55a568SDoug Rabson uint32_t nseq; 8028f55a568SDoug Rabson 8038f55a568SDoug Rabson log_debug("in svc_rpc_gss_nextverf()"); 8048f55a568SDoug Rabson 8058f55a568SDoug Rabson nseq = htonl(seq); 8068f55a568SDoug Rabson signbuf.value = &nseq; 8078f55a568SDoug Rabson signbuf.length = sizeof(nseq); 8088f55a568SDoug Rabson 8098f55a568SDoug Rabson if (client->cl_verf.value) 8108f55a568SDoug Rabson gss_release_buffer(&min_stat, &client->cl_verf); 8118f55a568SDoug Rabson 8128f55a568SDoug Rabson maj_stat = gss_get_mic(&min_stat, client->cl_ctx, client->cl_qop, 8138f55a568SDoug Rabson &signbuf, &client->cl_verf); 8148f55a568SDoug Rabson 8158f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 8168f55a568SDoug Rabson log_status("gss_get_mic", client->cl_mech, maj_stat, min_stat); 8178f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 8188f55a568SDoug Rabson return (FALSE); 8198f55a568SDoug Rabson } 8208f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 8218f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_base = (caddr_t)client->cl_verf.value; 8228f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_length = (u_int)client->cl_verf.length; 8238f55a568SDoug Rabson 8248f55a568SDoug Rabson return (TRUE); 8258f55a568SDoug Rabson } 8268f55a568SDoug Rabson 8278f55a568SDoug Rabson static bool_t 8288f55a568SDoug Rabson svc_rpc_gss_callback(struct svc_rpc_gss_client *client, struct svc_req *rqst) 8298f55a568SDoug Rabson { 8308f55a568SDoug Rabson struct svc_rpc_gss_callback *scb; 8318f55a568SDoug Rabson rpc_gss_lock_t lock; 8328f55a568SDoug Rabson void *cookie; 8338f55a568SDoug Rabson bool_t cb_res; 8348f55a568SDoug Rabson bool_t result; 8358f55a568SDoug Rabson 8368f55a568SDoug Rabson /* 8378f55a568SDoug Rabson * See if we have a callback for this guy. 8388f55a568SDoug Rabson */ 8398f55a568SDoug Rabson result = TRUE; 8408f55a568SDoug Rabson SLIST_FOREACH(scb, &svc_rpc_gss_callbacks, cb_link) { 8418f55a568SDoug Rabson if (scb->cb_callback.program == rqst->rq_prog 8428f55a568SDoug Rabson && scb->cb_callback.version == rqst->rq_vers) { 8438f55a568SDoug Rabson /* 8448f55a568SDoug Rabson * This one matches. Call the callback and see 8458f55a568SDoug Rabson * if it wants to veto or something. 8468f55a568SDoug Rabson */ 8478f55a568SDoug Rabson lock.locked = FALSE; 8488f55a568SDoug Rabson lock.raw_cred = &client->cl_rawcred; 8498f55a568SDoug Rabson cb_res = scb->cb_callback.callback(rqst, 8508f55a568SDoug Rabson client->cl_creds, 8518f55a568SDoug Rabson client->cl_ctx, 8528f55a568SDoug Rabson &lock, 8538f55a568SDoug Rabson &cookie); 8548f55a568SDoug Rabson 8558f55a568SDoug Rabson if (!cb_res) { 8568f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 8578f55a568SDoug Rabson result = FALSE; 8588f55a568SDoug Rabson break; 8598f55a568SDoug Rabson } 8608f55a568SDoug Rabson 8618f55a568SDoug Rabson /* 8628f55a568SDoug Rabson * The callback accepted the connection - it 8638f55a568SDoug Rabson * is responsible for freeing client->cl_creds 8648f55a568SDoug Rabson * now. 8658f55a568SDoug Rabson */ 8668f55a568SDoug Rabson client->cl_creds = GSS_C_NO_CREDENTIAL; 8678f55a568SDoug Rabson client->cl_locked = lock.locked; 8688f55a568SDoug Rabson client->cl_cookie = cookie; 8698f55a568SDoug Rabson return (TRUE); 8708f55a568SDoug Rabson } 8718f55a568SDoug Rabson } 8728f55a568SDoug Rabson 8738f55a568SDoug Rabson /* 8748f55a568SDoug Rabson * Either no callback exists for this program/version or one 8758f55a568SDoug Rabson * of the callbacks rejected the connection. We just need to 8768f55a568SDoug Rabson * clean up the delegated client creds, if any. 8778f55a568SDoug Rabson */ 8788f55a568SDoug Rabson if (client->cl_creds) { 8798f55a568SDoug Rabson OM_uint32 min_ver; 8808f55a568SDoug Rabson gss_release_cred(&min_ver, &client->cl_creds); 8818f55a568SDoug Rabson } 8828f55a568SDoug Rabson return (result); 8838f55a568SDoug Rabson } 8848f55a568SDoug Rabson 8858f55a568SDoug Rabson static bool_t 8868f55a568SDoug Rabson svc_rpc_gss_check_replay(struct svc_rpc_gss_client *client, uint32_t seq) 8878f55a568SDoug Rabson { 8888f55a568SDoug Rabson u_int32_t offset; 8898f55a568SDoug Rabson int word, bit; 8908f55a568SDoug Rabson 8915f7399dcSDoug Rabson if (seq <= client->cl_seqlast) { 8928f55a568SDoug Rabson /* 8938f55a568SDoug Rabson * The request sequence number is less than 8948f55a568SDoug Rabson * the largest we have seen so far. If it is 8958f55a568SDoug Rabson * outside the window or if we have seen a 8968f55a568SDoug Rabson * request with this sequence before, silently 8978f55a568SDoug Rabson * discard it. 8988f55a568SDoug Rabson */ 8998f55a568SDoug Rabson offset = client->cl_seqlast - seq; 900a9148abdSDoug Rabson if (offset >= SVC_RPC_GSS_SEQWINDOW) 9018f55a568SDoug Rabson return (FALSE); 9028f55a568SDoug Rabson word = offset / 32; 9038f55a568SDoug Rabson bit = offset % 32; 9048f55a568SDoug Rabson if (client->cl_seqmask[word] & (1 << bit)) 9058f55a568SDoug Rabson return (FALSE); 9068f55a568SDoug Rabson } 9078f55a568SDoug Rabson 9088f55a568SDoug Rabson return (TRUE); 9098f55a568SDoug Rabson } 9108f55a568SDoug Rabson 9118f55a568SDoug Rabson static void 9128f55a568SDoug Rabson svc_rpc_gss_update_seq(struct svc_rpc_gss_client *client, uint32_t seq) 9138f55a568SDoug Rabson { 914a9148abdSDoug Rabson int offset, i, word, bit; 9158f55a568SDoug Rabson uint32_t carry, newcarry; 916*11bc2c1cSDoug Rabson uint32_t* maskp; 9178f55a568SDoug Rabson 918*11bc2c1cSDoug Rabson maskp = client->cl_seqmask; 9198f55a568SDoug Rabson if (seq > client->cl_seqlast) { 9208f55a568SDoug Rabson /* 9218f55a568SDoug Rabson * This request has a sequence number greater 9228f55a568SDoug Rabson * than any we have seen so far. Advance the 9238f55a568SDoug Rabson * seq window and set bit zero of the window 9248f55a568SDoug Rabson * (which corresponds to the new sequence 9258f55a568SDoug Rabson * number) 9268f55a568SDoug Rabson */ 9278f55a568SDoug Rabson offset = seq - client->cl_seqlast; 928*11bc2c1cSDoug Rabson while (offset >= 32) { 9298f55a568SDoug Rabson for (i = (SVC_RPC_GSS_SEQWINDOW / 32) - 1; 9308f55a568SDoug Rabson i > 0; i--) { 931*11bc2c1cSDoug Rabson maskp[i] = maskp[i-1]; 9328f55a568SDoug Rabson } 933*11bc2c1cSDoug Rabson maskp[0] = 0; 9348f55a568SDoug Rabson offset -= 32; 9358f55a568SDoug Rabson } 936*11bc2c1cSDoug Rabson if (offset > 0) { 9378f55a568SDoug Rabson carry = 0; 9388f55a568SDoug Rabson for (i = 0; i < SVC_RPC_GSS_SEQWINDOW / 32; i++) { 939*11bc2c1cSDoug Rabson newcarry = maskp[i] >> (32 - offset); 940*11bc2c1cSDoug Rabson maskp[i] = (maskp[i] << offset) | carry; 9418f55a568SDoug Rabson carry = newcarry; 9428f55a568SDoug Rabson } 943*11bc2c1cSDoug Rabson } 944*11bc2c1cSDoug Rabson maskp[0] |= 1; 9458f55a568SDoug Rabson client->cl_seqlast = seq; 946a9148abdSDoug Rabson } else { 947a9148abdSDoug Rabson offset = client->cl_seqlast - seq; 948a9148abdSDoug Rabson word = offset / 32; 949a9148abdSDoug Rabson bit = offset % 32; 950*11bc2c1cSDoug Rabson maskp[word] |= (1 << bit); 9518f55a568SDoug Rabson } 952a9148abdSDoug Rabson 9538f55a568SDoug Rabson } 9548f55a568SDoug Rabson 9558f55a568SDoug Rabson enum auth_stat 9568f55a568SDoug Rabson svc_rpc_gss(struct svc_req *rqst, struct rpc_msg *msg) 9578f55a568SDoug Rabson 9588f55a568SDoug Rabson { 9598f55a568SDoug Rabson OM_uint32 min_stat; 9608f55a568SDoug Rabson XDR xdrs; 9618f55a568SDoug Rabson struct svc_rpc_gss_client *client; 9628f55a568SDoug Rabson struct rpc_gss_cred gc; 9638f55a568SDoug Rabson struct rpc_gss_init_res gr; 9648f55a568SDoug Rabson gss_qop_t qop; 9658f55a568SDoug Rabson int call_stat; 9668f55a568SDoug Rabson enum auth_stat result; 9678f55a568SDoug Rabson 9688f55a568SDoug Rabson log_debug("in svc_rpc_gss()"); 9698f55a568SDoug Rabson 9708f55a568SDoug Rabson /* Garbage collect old clients. */ 9718f55a568SDoug Rabson svc_rpc_gss_timeout_clients(); 9728f55a568SDoug Rabson 9738f55a568SDoug Rabson /* Initialize reply. */ 9748f55a568SDoug Rabson rqst->rq_xprt->xp_verf = _null_auth; 9758f55a568SDoug Rabson 9768f55a568SDoug Rabson /* Deserialize client credentials. */ 9778f55a568SDoug Rabson if (rqst->rq_cred.oa_length <= 0) 9788f55a568SDoug Rabson return (AUTH_BADCRED); 9798f55a568SDoug Rabson 9808f55a568SDoug Rabson memset(&gc, 0, sizeof(gc)); 9818f55a568SDoug Rabson 9828f55a568SDoug Rabson xdrmem_create(&xdrs, rqst->rq_cred.oa_base, 9838f55a568SDoug Rabson rqst->rq_cred.oa_length, XDR_DECODE); 9848f55a568SDoug Rabson 9858f55a568SDoug Rabson if (!xdr_rpc_gss_cred(&xdrs, &gc)) { 9868f55a568SDoug Rabson XDR_DESTROY(&xdrs); 9878f55a568SDoug Rabson return (AUTH_BADCRED); 9888f55a568SDoug Rabson } 9898f55a568SDoug Rabson XDR_DESTROY(&xdrs); 9908f55a568SDoug Rabson 9918f55a568SDoug Rabson /* Check version. */ 9928f55a568SDoug Rabson if (gc.gc_version != RPCSEC_GSS_VERSION) { 9938f55a568SDoug Rabson result = AUTH_BADCRED; 9948f55a568SDoug Rabson goto out; 9958f55a568SDoug Rabson } 9968f55a568SDoug Rabson 9978f55a568SDoug Rabson /* Check the proc and find the client (or create it) */ 9988f55a568SDoug Rabson if (gc.gc_proc == RPCSEC_GSS_INIT) { 999a9148abdSDoug Rabson if (gc.gc_handle.length != 0) { 1000a9148abdSDoug Rabson result = AUTH_BADCRED; 1001a9148abdSDoug Rabson goto out; 1002a9148abdSDoug Rabson } 10038f55a568SDoug Rabson client = svc_rpc_gss_create_client(); 10048f55a568SDoug Rabson } else { 10058f55a568SDoug Rabson if (gc.gc_handle.length != sizeof(uint32_t)) { 10068f55a568SDoug Rabson result = AUTH_BADCRED; 10078f55a568SDoug Rabson goto out; 10088f55a568SDoug Rabson } 10098f55a568SDoug Rabson uint32_t *p = gc.gc_handle.value; 10108f55a568SDoug Rabson client = svc_rpc_gss_find_client(*p); 10118f55a568SDoug Rabson if (!client) { 10128f55a568SDoug Rabson /* 10138f55a568SDoug Rabson * Can't find the client - we may have 10148f55a568SDoug Rabson * destroyed it - tell the other side to 10158f55a568SDoug Rabson * re-authenticate. 10168f55a568SDoug Rabson */ 10178f55a568SDoug Rabson result = RPCSEC_GSS_CREDPROBLEM; 10188f55a568SDoug Rabson goto out; 10198f55a568SDoug Rabson } 10208f55a568SDoug Rabson } 10218f55a568SDoug Rabson rqst->rq_clntcred = client; 10228f55a568SDoug Rabson 10238f55a568SDoug Rabson /* 10248f55a568SDoug Rabson * The service and sequence number must be ignored for 10258f55a568SDoug Rabson * RPCSEC_GSS_INIT and RPCSEC_GSS_CONTINUE_INIT. 10268f55a568SDoug Rabson */ 10278f55a568SDoug Rabson if (gc.gc_proc != RPCSEC_GSS_INIT 10288f55a568SDoug Rabson && gc.gc_proc != RPCSEC_GSS_CONTINUE_INIT) { 10298f55a568SDoug Rabson /* 10308f55a568SDoug Rabson * Check for sequence number overflow. 10318f55a568SDoug Rabson */ 10328f55a568SDoug Rabson if (gc.gc_seq >= MAXSEQ) { 10338f55a568SDoug Rabson result = RPCSEC_GSS_CTXPROBLEM; 10348f55a568SDoug Rabson goto out; 10358f55a568SDoug Rabson } 10368f55a568SDoug Rabson client->cl_seq = gc.gc_seq; 10378f55a568SDoug Rabson 10388f55a568SDoug Rabson /* 10398f55a568SDoug Rabson * Check for valid service. 10408f55a568SDoug Rabson */ 10418f55a568SDoug Rabson if (gc.gc_svc != rpc_gss_svc_none && 10428f55a568SDoug Rabson gc.gc_svc != rpc_gss_svc_integrity && 10438f55a568SDoug Rabson gc.gc_svc != rpc_gss_svc_privacy) { 10448f55a568SDoug Rabson result = AUTH_BADCRED; 10458f55a568SDoug Rabson goto out; 10468f55a568SDoug Rabson } 10478f55a568SDoug Rabson } 10488f55a568SDoug Rabson 10498f55a568SDoug Rabson /* Handle RPCSEC_GSS control procedure. */ 10508f55a568SDoug Rabson switch (gc.gc_proc) { 10518f55a568SDoug Rabson 10528f55a568SDoug Rabson case RPCSEC_GSS_INIT: 10538f55a568SDoug Rabson case RPCSEC_GSS_CONTINUE_INIT: 10548f55a568SDoug Rabson if (rqst->rq_proc != NULLPROC) { 10558f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 10568f55a568SDoug Rabson break; 10578f55a568SDoug Rabson } 10588f55a568SDoug Rabson 10598f55a568SDoug Rabson memset(&gr, 0, sizeof(gr)); 10608f55a568SDoug Rabson if (!svc_rpc_gss_accept_sec_context(client, rqst, &gr, &gc)) { 10618f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 10628f55a568SDoug Rabson break; 10638f55a568SDoug Rabson } 10648f55a568SDoug Rabson 10658f55a568SDoug Rabson if (gr.gr_major == GSS_S_COMPLETE) { 10668f55a568SDoug Rabson if (!svc_rpc_gss_nextverf(client, rqst, gr.gr_win)) { 10678f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 10688f55a568SDoug Rabson break; 10698f55a568SDoug Rabson } 10708f55a568SDoug Rabson } else { 10718f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; 10728f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_length = 0; 10738f55a568SDoug Rabson } 10748f55a568SDoug Rabson 10758f55a568SDoug Rabson call_stat = svc_sendreply(rqst->rq_xprt, 10768f55a568SDoug Rabson (xdrproc_t) xdr_rpc_gss_init_res, 10778f55a568SDoug Rabson (caddr_t) &gr); 10788f55a568SDoug Rabson 10798f55a568SDoug Rabson gss_release_buffer(&min_stat, &gr.gr_token); 10808f55a568SDoug Rabson 10818f55a568SDoug Rabson if (!call_stat) { 10828f55a568SDoug Rabson result = AUTH_FAILED; 10838f55a568SDoug Rabson break; 10848f55a568SDoug Rabson } 10858f55a568SDoug Rabson 10868f55a568SDoug Rabson if (gr.gr_major == GSS_S_COMPLETE) 10878f55a568SDoug Rabson client->cl_state = CLIENT_ESTABLISHED; 10888f55a568SDoug Rabson 10898f55a568SDoug Rabson result = RPCSEC_GSS_NODISPATCH; 10908f55a568SDoug Rabson break; 10918f55a568SDoug Rabson 10928f55a568SDoug Rabson case RPCSEC_GSS_DATA: 10938f55a568SDoug Rabson case RPCSEC_GSS_DESTROY: 10948f55a568SDoug Rabson if (!svc_rpc_gss_check_replay(client, gc.gc_seq)) { 10958f55a568SDoug Rabson result = RPCSEC_GSS_NODISPATCH; 10968f55a568SDoug Rabson break; 10978f55a568SDoug Rabson } 10988f55a568SDoug Rabson 10998f55a568SDoug Rabson if (!svc_rpc_gss_validate(client, msg, &qop)) { 11008f55a568SDoug Rabson result = RPCSEC_GSS_CREDPROBLEM; 11018f55a568SDoug Rabson break; 11028f55a568SDoug Rabson } 11038f55a568SDoug Rabson 11048f55a568SDoug Rabson if (!svc_rpc_gss_nextverf(client, rqst, gc.gc_seq)) { 11058f55a568SDoug Rabson result = RPCSEC_GSS_CTXPROBLEM; 11068f55a568SDoug Rabson break; 11078f55a568SDoug Rabson } 11088f55a568SDoug Rabson 11098f55a568SDoug Rabson svc_rpc_gss_update_seq(client, gc.gc_seq); 11108f55a568SDoug Rabson 11118f55a568SDoug Rabson /* 11128f55a568SDoug Rabson * Change the SVCAUTH ops on the transport to point at 11138f55a568SDoug Rabson * our own code so that we can unwrap the arguments 11148f55a568SDoug Rabson * and wrap the result. The caller will re-set this on 11158f55a568SDoug Rabson * every request to point to a set of null wrap/unwrap 11168f55a568SDoug Rabson * methods. 11178f55a568SDoug Rabson */ 11188f55a568SDoug Rabson SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_gss_ops; 11198f55a568SDoug Rabson SVC_AUTH(rqst->rq_xprt).svc_ah_private = client; 11208f55a568SDoug Rabson 11218f55a568SDoug Rabson if (gc.gc_proc == RPCSEC_GSS_DATA) { 11228f55a568SDoug Rabson /* 11238f55a568SDoug Rabson * We might be ready to do a callback to the server to 11248f55a568SDoug Rabson * see if it wants to accept/reject the connection. 11258f55a568SDoug Rabson */ 11268f55a568SDoug Rabson if (!client->cl_done_callback) { 11278f55a568SDoug Rabson client->cl_done_callback = TRUE; 11288f55a568SDoug Rabson client->cl_qop = qop; 11298f55a568SDoug Rabson client->cl_rawcred.qop = _rpc_gss_num_to_qop( 11308f55a568SDoug Rabson client->cl_rawcred.mechanism, qop); 11318f55a568SDoug Rabson if (!svc_rpc_gss_callback(client, rqst)) { 11328f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 11338f55a568SDoug Rabson break; 11348f55a568SDoug Rabson } 11358f55a568SDoug Rabson } 11368f55a568SDoug Rabson 11378f55a568SDoug Rabson /* 11388f55a568SDoug Rabson * If the server has locked this client to a 11398f55a568SDoug Rabson * particular service+qop pair, enforce that 11408f55a568SDoug Rabson * restriction now. 11418f55a568SDoug Rabson */ 11428f55a568SDoug Rabson if (client->cl_locked) { 11438f55a568SDoug Rabson if (client->cl_rawcred.service != gc.gc_svc) { 11448f55a568SDoug Rabson result = AUTH_FAILED; 11458f55a568SDoug Rabson break; 11468f55a568SDoug Rabson } else if (client->cl_qop != qop) { 11478f55a568SDoug Rabson result = AUTH_BADVERF; 11488f55a568SDoug Rabson break; 11498f55a568SDoug Rabson } 11508f55a568SDoug Rabson } 11518f55a568SDoug Rabson 11528f55a568SDoug Rabson /* 11538f55a568SDoug Rabson * If the qop changed, look up the new qop 11548f55a568SDoug Rabson * name for rawcred. 11558f55a568SDoug Rabson */ 11568f55a568SDoug Rabson if (client->cl_qop != qop) { 11578f55a568SDoug Rabson client->cl_qop = qop; 11588f55a568SDoug Rabson client->cl_rawcred.qop = _rpc_gss_num_to_qop( 11598f55a568SDoug Rabson client->cl_rawcred.mechanism, qop); 11608f55a568SDoug Rabson } 11618f55a568SDoug Rabson 11628f55a568SDoug Rabson /* 11638f55a568SDoug Rabson * Make sure we use the right service value 11648f55a568SDoug Rabson * for unwrap/wrap. 11658f55a568SDoug Rabson */ 11668f55a568SDoug Rabson client->cl_rawcred.service = gc.gc_svc; 11678f55a568SDoug Rabson 11688f55a568SDoug Rabson result = AUTH_OK; 11698f55a568SDoug Rabson } else { 11708f55a568SDoug Rabson if (rqst->rq_proc != NULLPROC) { 11718f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 11728f55a568SDoug Rabson break; 11738f55a568SDoug Rabson } 11748f55a568SDoug Rabson 11758f55a568SDoug Rabson call_stat = svc_sendreply(rqst->rq_xprt, 11768f55a568SDoug Rabson (xdrproc_t) xdr_void, (caddr_t) NULL); 11778f55a568SDoug Rabson 11788f55a568SDoug Rabson if (!call_stat) { 11798f55a568SDoug Rabson result = AUTH_FAILED; 11808f55a568SDoug Rabson break; 11818f55a568SDoug Rabson } 11828f55a568SDoug Rabson 11838f55a568SDoug Rabson svc_rpc_gss_destroy_client(client); 11848f55a568SDoug Rabson 11858f55a568SDoug Rabson result = RPCSEC_GSS_NODISPATCH; 11868f55a568SDoug Rabson break; 11878f55a568SDoug Rabson } 11888f55a568SDoug Rabson break; 11898f55a568SDoug Rabson 11908f55a568SDoug Rabson default: 11918f55a568SDoug Rabson result = AUTH_BADCRED; 11928f55a568SDoug Rabson break; 11938f55a568SDoug Rabson } 11948f55a568SDoug Rabson out: 11958f55a568SDoug Rabson xdr_free((xdrproc_t) xdr_rpc_gss_cred, (char *) &gc); 11968f55a568SDoug Rabson return (result); 11978f55a568SDoug Rabson } 11988f55a568SDoug Rabson 11998f55a568SDoug Rabson bool_t 12008f55a568SDoug Rabson svc_rpc_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) 12018f55a568SDoug Rabson { 12028f55a568SDoug Rabson struct svc_rpc_gss_client *client; 12038f55a568SDoug Rabson 12048f55a568SDoug Rabson log_debug("in svc_rpc_gss_wrap()"); 12058f55a568SDoug Rabson 12068f55a568SDoug Rabson client = (struct svc_rpc_gss_client *) auth->svc_ah_private; 12078f55a568SDoug Rabson if (client->cl_state != CLIENT_ESTABLISHED 12088f55a568SDoug Rabson || client->cl_rawcred.service == rpc_gss_svc_none) { 12098f55a568SDoug Rabson return xdr_func(xdrs, xdr_ptr); 12108f55a568SDoug Rabson } 12118f55a568SDoug Rabson return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr, 12128f55a568SDoug Rabson client->cl_ctx, client->cl_qop, 12138f55a568SDoug Rabson client->cl_rawcred.service, client->cl_seq)); 12148f55a568SDoug Rabson } 12158f55a568SDoug Rabson 12168f55a568SDoug Rabson bool_t 12178f55a568SDoug Rabson svc_rpc_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) 12188f55a568SDoug Rabson { 12198f55a568SDoug Rabson struct svc_rpc_gss_client *client; 12208f55a568SDoug Rabson 12218f55a568SDoug Rabson log_debug("in svc_rpc_gss_unwrap()"); 12228f55a568SDoug Rabson 12238f55a568SDoug Rabson client = (struct svc_rpc_gss_client *) auth->svc_ah_private; 12248f55a568SDoug Rabson if (client->cl_state != CLIENT_ESTABLISHED 12258f55a568SDoug Rabson || client->cl_rawcred.service == rpc_gss_svc_none) { 12268f55a568SDoug Rabson return xdr_func(xdrs, xdr_ptr); 12278f55a568SDoug Rabson } 12288f55a568SDoug Rabson return (xdr_rpc_gss_unwrap_data(xdrs, xdr_func, xdr_ptr, 12298f55a568SDoug Rabson client->cl_ctx, client->cl_qop, 12308f55a568SDoug Rabson client->cl_rawcred.service, client->cl_seq)); 12318f55a568SDoug Rabson } 1232