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) 938f55a568SDoug Rabson 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) 1058f55a568SDoug Rabson 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 1438f55a568SDoug Rabson struct svc_rpc_gss_client_list svc_rpc_gss_client_hash[CLIENT_HASH_SIZE]; 1448f55a568SDoug Rabson 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 1718f55a568SDoug Rabson scb = malloc(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 2588f55a568SDoug Rabson buf.value = malloc(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); 2768f55a568SDoug Rabson free(buf.value); 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 3038f55a568SDoug Rabson result = malloc(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) 4468f55a568SDoug Rabson free(client->cl_rawcred.client_principal); 4478f55a568SDoug Rabson 4488f55a568SDoug Rabson if (client->cl_verf.value) 4498f55a568SDoug Rabson gss_release_buffer(&min_stat, &client->cl_verf); 4508f55a568SDoug Rabson 4518f55a568SDoug Rabson list = &svc_rpc_gss_client_hash[client->cl_id % CLIENT_HASH_SIZE]; 4528f55a568SDoug Rabson TAILQ_REMOVE(list, client, cl_link); 4538f55a568SDoug Rabson TAILQ_REMOVE(&svc_rpc_gss_clients, client, cl_alllink); 4548f55a568SDoug Rabson svc_rpc_gss_client_count--; 4558f55a568SDoug Rabson mem_free(client, sizeof(*client)); 4568f55a568SDoug Rabson } 4578f55a568SDoug Rabson 4588f55a568SDoug Rabson static void 4598f55a568SDoug Rabson svc_rpc_gss_timeout_clients(void) 4608f55a568SDoug Rabson { 4618f55a568SDoug Rabson struct svc_rpc_gss_client *client; 4628f55a568SDoug Rabson struct svc_rpc_gss_client *nclient; 4638f55a568SDoug Rabson time_t now = time(0); 4648f55a568SDoug Rabson 4658f55a568SDoug Rabson log_debug("in svc_rpc_gss_timeout_clients()"); 4668f55a568SDoug Rabson /* 4678f55a568SDoug Rabson * First enforce the max client limit. We keep 4688f55a568SDoug Rabson * svc_rpc_gss_clients in LRU order. 4698f55a568SDoug Rabson */ 4708f55a568SDoug Rabson while (svc_rpc_gss_client_count > CLIENT_MAX) 4718f55a568SDoug Rabson svc_rpc_gss_destroy_client(TAILQ_LAST(&svc_rpc_gss_clients, 4728f55a568SDoug Rabson svc_rpc_gss_client_list)); 4738f55a568SDoug Rabson TAILQ_FOREACH_SAFE(client, &svc_rpc_gss_clients, cl_alllink, nclient) { 4748f55a568SDoug Rabson if (client->cl_state == CLIENT_STALE 4758f55a568SDoug Rabson || now > client->cl_expiration) { 4768f55a568SDoug Rabson log_debug("expiring client %p", client); 4778f55a568SDoug Rabson svc_rpc_gss_destroy_client(client); 4788f55a568SDoug Rabson } 4798f55a568SDoug Rabson } 4808f55a568SDoug Rabson } 4818f55a568SDoug Rabson 4828f55a568SDoug Rabson #ifdef DEBUG 4838f55a568SDoug Rabson /* 4848f55a568SDoug Rabson * OID<->string routines. These are uuuuugly. 4858f55a568SDoug Rabson */ 4868f55a568SDoug Rabson static OM_uint32 4878f55a568SDoug Rabson gss_oid_to_str(OM_uint32 *minor_status, gss_OID oid, gss_buffer_t oid_str) 4888f55a568SDoug Rabson { 4898f55a568SDoug Rabson char numstr[128]; 4908f55a568SDoug Rabson unsigned long number; 4918f55a568SDoug Rabson int numshift; 4928f55a568SDoug Rabson size_t string_length; 4938f55a568SDoug Rabson size_t i; 4948f55a568SDoug Rabson unsigned char *cp; 4958f55a568SDoug Rabson char *bp; 4968f55a568SDoug Rabson 4978f55a568SDoug Rabson /* Decoded according to krb5/gssapi_krb5.c */ 4988f55a568SDoug Rabson 4998f55a568SDoug Rabson /* First determine the size of the string */ 5008f55a568SDoug Rabson string_length = 0; 5018f55a568SDoug Rabson number = 0; 5028f55a568SDoug Rabson numshift = 0; 5038f55a568SDoug Rabson cp = (unsigned char *) oid->elements; 5048f55a568SDoug Rabson number = (unsigned long) cp[0]; 5058f55a568SDoug Rabson sprintf(numstr, "%ld ", number/40); 5068f55a568SDoug Rabson string_length += strlen(numstr); 5078f55a568SDoug Rabson sprintf(numstr, "%ld ", number%40); 5088f55a568SDoug Rabson string_length += strlen(numstr); 5098f55a568SDoug Rabson for (i=1; i<oid->length; i++) { 5108f55a568SDoug Rabson if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) { 5118f55a568SDoug Rabson number = (number << 7) | (cp[i] & 0x7f); 5128f55a568SDoug Rabson numshift += 7; 5138f55a568SDoug Rabson } 5148f55a568SDoug Rabson else { 5158f55a568SDoug Rabson *minor_status = 0; 5168f55a568SDoug Rabson return(GSS_S_FAILURE); 5178f55a568SDoug Rabson } 5188f55a568SDoug Rabson if ((cp[i] & 0x80) == 0) { 5198f55a568SDoug Rabson sprintf(numstr, "%ld ", number); 5208f55a568SDoug Rabson string_length += strlen(numstr); 5218f55a568SDoug Rabson number = 0; 5228f55a568SDoug Rabson numshift = 0; 5238f55a568SDoug Rabson } 5248f55a568SDoug Rabson } 5258f55a568SDoug Rabson /* 5268f55a568SDoug Rabson * If we get here, we've calculated the length of "n n n ... n ". Add 4 5278f55a568SDoug Rabson * here for "{ " and "}\0". 5288f55a568SDoug Rabson */ 5298f55a568SDoug Rabson string_length += 4; 5308f55a568SDoug Rabson if ((bp = (char *) malloc(string_length))) { 5318f55a568SDoug Rabson strcpy(bp, "{ "); 5328f55a568SDoug Rabson number = (unsigned long) cp[0]; 5338f55a568SDoug Rabson sprintf(numstr, "%ld ", number/40); 5348f55a568SDoug Rabson strcat(bp, numstr); 5358f55a568SDoug Rabson sprintf(numstr, "%ld ", number%40); 5368f55a568SDoug Rabson strcat(bp, numstr); 5378f55a568SDoug Rabson number = 0; 5388f55a568SDoug Rabson cp = (unsigned char *) oid->elements; 5398f55a568SDoug Rabson for (i=1; i<oid->length; i++) { 5408f55a568SDoug Rabson number = (number << 7) | (cp[i] & 0x7f); 5418f55a568SDoug Rabson if ((cp[i] & 0x80) == 0) { 5428f55a568SDoug Rabson sprintf(numstr, "%ld ", number); 5438f55a568SDoug Rabson strcat(bp, numstr); 5448f55a568SDoug Rabson number = 0; 5458f55a568SDoug Rabson } 5468f55a568SDoug Rabson } 5478f55a568SDoug Rabson strcat(bp, "}"); 5488f55a568SDoug Rabson oid_str->length = strlen(bp)+1; 5498f55a568SDoug Rabson oid_str->value = (void *) bp; 5508f55a568SDoug Rabson *minor_status = 0; 5518f55a568SDoug Rabson return(GSS_S_COMPLETE); 5528f55a568SDoug Rabson } 5538f55a568SDoug Rabson *minor_status = 0; 5548f55a568SDoug Rabson return(GSS_S_FAILURE); 5558f55a568SDoug Rabson } 5568f55a568SDoug Rabson #endif 5578f55a568SDoug Rabson 5588f55a568SDoug Rabson static void 5598f55a568SDoug Rabson svc_rpc_gss_build_ucred(struct svc_rpc_gss_client *client, 5608f55a568SDoug Rabson const gss_name_t name) 5618f55a568SDoug Rabson { 5628f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 5638f55a568SDoug Rabson char buf[128]; 5648f55a568SDoug Rabson uid_t uid; 5658f55a568SDoug Rabson struct passwd pwd, *pw; 5668f55a568SDoug Rabson rpc_gss_ucred_t *uc = &client->cl_ucred; 5678f55a568SDoug Rabson 5688f55a568SDoug Rabson uc->uid = 65534; 5698f55a568SDoug Rabson uc->gid = 65534; 5708f55a568SDoug Rabson uc->gidlen = 0; 5718f55a568SDoug Rabson uc->gidlist = client->cl_gid_storage; 5728f55a568SDoug Rabson 5738f55a568SDoug Rabson maj_stat = gss_pname_to_uid(&min_stat, name, client->cl_mech, &uid); 5748f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) 5758f55a568SDoug Rabson return; 5768f55a568SDoug Rabson 5778f55a568SDoug Rabson getpwuid_r(uid, &pwd, buf, sizeof(buf), &pw); 5788f55a568SDoug Rabson if (pw) { 5798f55a568SDoug Rabson int len = NGRPS; 5808f55a568SDoug Rabson uc->uid = pw->pw_uid; 5818f55a568SDoug Rabson uc->gid = pw->pw_gid; 5828f55a568SDoug Rabson uc->gidlist = client->cl_gid_storage; 5838f55a568SDoug Rabson getgrouplist(pw->pw_name, pw->pw_gid, uc->gidlist, &len); 5848f55a568SDoug Rabson uc->gidlen = len; 5858f55a568SDoug Rabson } 5868f55a568SDoug Rabson } 5878f55a568SDoug Rabson 5888f55a568SDoug Rabson static bool_t 5898f55a568SDoug Rabson svc_rpc_gss_accept_sec_context(struct svc_rpc_gss_client *client, 5908f55a568SDoug Rabson struct svc_req *rqst, 5918f55a568SDoug Rabson struct rpc_gss_init_res *gr, 5928f55a568SDoug Rabson struct rpc_gss_cred *gc) 5938f55a568SDoug Rabson { 5948f55a568SDoug Rabson gss_buffer_desc recv_tok; 5958f55a568SDoug Rabson gss_OID mech; 5968f55a568SDoug Rabson OM_uint32 maj_stat = 0, min_stat = 0, ret_flags; 5978f55a568SDoug Rabson OM_uint32 cred_lifetime; 5988f55a568SDoug Rabson struct svc_rpc_gss_svc_name *sname; 5998f55a568SDoug Rabson 6008f55a568SDoug Rabson log_debug("in svc_rpc_gss_accept_context()"); 6018f55a568SDoug Rabson 6028f55a568SDoug Rabson /* Deserialize arguments. */ 6038f55a568SDoug Rabson memset(&recv_tok, 0, sizeof(recv_tok)); 6048f55a568SDoug Rabson 6058f55a568SDoug Rabson if (!svc_getargs(rqst->rq_xprt, 6068f55a568SDoug Rabson (xdrproc_t) xdr_gss_buffer_desc, 6078f55a568SDoug Rabson (caddr_t) &recv_tok)) { 6088f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 6098f55a568SDoug Rabson return (FALSE); 6108f55a568SDoug Rabson } 6118f55a568SDoug Rabson 6128f55a568SDoug Rabson /* 6138f55a568SDoug Rabson * First time round, try all the server names we have until 6148f55a568SDoug Rabson * one matches. Afterwards, stick with that one. 6158f55a568SDoug Rabson */ 6168f55a568SDoug Rabson if (!client->cl_sname) { 6178f55a568SDoug Rabson SLIST_FOREACH(sname, &svc_rpc_gss_svc_names, sn_link) { 6188f55a568SDoug Rabson if (sname->sn_program == rqst->rq_prog 6198f55a568SDoug Rabson && sname->sn_version == rqst->rq_vers) { 6208f55a568SDoug Rabson gr->gr_major = gss_accept_sec_context( 6218f55a568SDoug Rabson &gr->gr_minor, 6228f55a568SDoug Rabson &client->cl_ctx, 6238f55a568SDoug Rabson sname->sn_cred, 6248f55a568SDoug Rabson &recv_tok, 6258f55a568SDoug Rabson GSS_C_NO_CHANNEL_BINDINGS, 6268f55a568SDoug Rabson &client->cl_cname, 6278f55a568SDoug Rabson &mech, 6288f55a568SDoug Rabson &gr->gr_token, 6298f55a568SDoug Rabson &ret_flags, 6308f55a568SDoug Rabson &cred_lifetime, 6318f55a568SDoug Rabson &client->cl_creds); 6328f55a568SDoug Rabson if (gr->gr_major == GSS_S_COMPLETE 6338f55a568SDoug Rabson || gr->gr_major == GSS_S_CONTINUE_NEEDED) { 6348f55a568SDoug Rabson client->cl_sname = sname; 6358f55a568SDoug Rabson break; 6368f55a568SDoug Rabson } 6378f55a568SDoug Rabson } 6388f55a568SDoug Rabson } 6398f55a568SDoug Rabson } else { 6408f55a568SDoug Rabson gr->gr_major = gss_accept_sec_context( 6418f55a568SDoug Rabson &gr->gr_minor, 6428f55a568SDoug Rabson &client->cl_ctx, 6438f55a568SDoug Rabson client->cl_sname->sn_cred, 6448f55a568SDoug Rabson &recv_tok, 6458f55a568SDoug Rabson GSS_C_NO_CHANNEL_BINDINGS, 6468f55a568SDoug Rabson &client->cl_cname, 6478f55a568SDoug Rabson &mech, 6488f55a568SDoug Rabson &gr->gr_token, 6498f55a568SDoug Rabson &ret_flags, 6508f55a568SDoug Rabson &cred_lifetime, 6518f55a568SDoug Rabson NULL); 6528f55a568SDoug Rabson } 6538f55a568SDoug Rabson 6548f55a568SDoug Rabson xdr_free((xdrproc_t) xdr_gss_buffer_desc, (char *) &recv_tok); 6558f55a568SDoug Rabson 6568f55a568SDoug Rabson /* 6578f55a568SDoug Rabson * If we get an error from gss_accept_sec_context, send the 6588f55a568SDoug Rabson * reply anyway so that the client gets a chance to see what 6598f55a568SDoug Rabson * is wrong. 6608f55a568SDoug Rabson */ 6618f55a568SDoug Rabson if (gr->gr_major != GSS_S_COMPLETE && 6628f55a568SDoug Rabson gr->gr_major != GSS_S_CONTINUE_NEEDED) { 6638f55a568SDoug Rabson log_status("accept_sec_context", client->cl_mech, 6648f55a568SDoug Rabson gr->gr_major, gr->gr_minor); 6658f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 6668f55a568SDoug Rabson return (FALSE); 6678f55a568SDoug Rabson } 6688f55a568SDoug Rabson 6698f55a568SDoug Rabson gr->gr_handle.value = &client->cl_id; 6708f55a568SDoug Rabson gr->gr_handle.length = sizeof(uint32_t); 6718f55a568SDoug Rabson gr->gr_win = SVC_RPC_GSS_SEQWINDOW; 6728f55a568SDoug Rabson 6738f55a568SDoug Rabson /* Save client info. */ 6748f55a568SDoug Rabson client->cl_mech = mech; 6758f55a568SDoug Rabson client->cl_qop = GSS_C_QOP_DEFAULT; 6768f55a568SDoug Rabson client->cl_seq = gc->gc_seq; 6778f55a568SDoug Rabson client->cl_win = gr->gr_win; 6788f55a568SDoug Rabson client->cl_done_callback = FALSE; 6798f55a568SDoug Rabson 6808f55a568SDoug Rabson if (gr->gr_major == GSS_S_COMPLETE) { 6818f55a568SDoug Rabson gss_buffer_desc export_name; 6828f55a568SDoug Rabson 6838f55a568SDoug Rabson /* 6848f55a568SDoug Rabson * Change client expiration time to be near when the 6858f55a568SDoug Rabson * client creds expire (or 24 hours if we can't figure 6868f55a568SDoug Rabson * that out). 6878f55a568SDoug Rabson */ 6888f55a568SDoug Rabson if (cred_lifetime == GSS_C_INDEFINITE) 6898f55a568SDoug Rabson cred_lifetime = time(0) + 24*60*60; 6908f55a568SDoug Rabson 6918f55a568SDoug Rabson client->cl_expiration = time(0) + cred_lifetime; 6928f55a568SDoug Rabson 6938f55a568SDoug Rabson /* 6948f55a568SDoug Rabson * Fill in cred details in the rawcred structure. 6958f55a568SDoug Rabson */ 6968f55a568SDoug Rabson client->cl_rawcred.version = RPCSEC_GSS_VERSION; 6978f55a568SDoug Rabson rpc_gss_oid_to_mech(mech, &client->cl_rawcred.mechanism); 6988f55a568SDoug Rabson maj_stat = gss_export_name(&min_stat, client->cl_cname, 6998f55a568SDoug Rabson &export_name); 7008f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 7018f55a568SDoug Rabson log_status("gss_export_name", client->cl_mech, 7028f55a568SDoug Rabson maj_stat, min_stat); 7038f55a568SDoug Rabson return (FALSE); 7048f55a568SDoug Rabson } 7058f55a568SDoug Rabson client->cl_rawcred.client_principal = 7068f55a568SDoug Rabson malloc(sizeof(*client->cl_rawcred.client_principal) 7078f55a568SDoug Rabson + export_name.length); 7088f55a568SDoug Rabson client->cl_rawcred.client_principal->len = export_name.length; 7098f55a568SDoug Rabson memcpy(client->cl_rawcred.client_principal->name, 7108f55a568SDoug Rabson export_name.value, export_name.length); 7118f55a568SDoug Rabson gss_release_buffer(&min_stat, &export_name); 7128f55a568SDoug Rabson client->cl_rawcred.svc_principal = 7138f55a568SDoug Rabson client->cl_sname->sn_principal; 7148f55a568SDoug Rabson client->cl_rawcred.service = gc->gc_svc; 7158f55a568SDoug Rabson 7168f55a568SDoug Rabson /* 7178f55a568SDoug Rabson * Use gss_pname_to_uid to map to unix creds. For 7188f55a568SDoug Rabson * kerberos5, this uses krb5_aname_to_localname. 7198f55a568SDoug Rabson */ 7208f55a568SDoug Rabson svc_rpc_gss_build_ucred(client, client->cl_cname); 7218f55a568SDoug Rabson 7228f55a568SDoug Rabson #ifdef DEBUG 7238f55a568SDoug Rabson { 7248f55a568SDoug Rabson gss_buffer_desc mechname; 7258f55a568SDoug Rabson 7268f55a568SDoug Rabson gss_oid_to_str(&min_stat, mech, &mechname); 7278f55a568SDoug Rabson 7288f55a568SDoug Rabson log_debug("accepted context for %s with " 7298f55a568SDoug Rabson "<mech %.*s, qop %d, svc %d>", 7308f55a568SDoug Rabson client->cl_rawcred.client_principal->name, 7318f55a568SDoug Rabson mechname.length, (char *)mechname.value, 7328f55a568SDoug Rabson client->cl_qop, client->rawcred.service); 7338f55a568SDoug Rabson 7348f55a568SDoug Rabson gss_release_buffer(&min_stat, &mechname); 7358f55a568SDoug Rabson } 7368f55a568SDoug Rabson #endif /* DEBUG */ 7378f55a568SDoug Rabson } 7388f55a568SDoug Rabson return (TRUE); 7398f55a568SDoug Rabson } 7408f55a568SDoug Rabson 7418f55a568SDoug Rabson static bool_t 7428f55a568SDoug Rabson svc_rpc_gss_validate(struct svc_rpc_gss_client *client, struct rpc_msg *msg, 7438f55a568SDoug Rabson gss_qop_t *qop) 7448f55a568SDoug Rabson { 7458f55a568SDoug Rabson struct opaque_auth *oa; 7468f55a568SDoug Rabson gss_buffer_desc rpcbuf, checksum; 7478f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 7488f55a568SDoug Rabson gss_qop_t qop_state; 7499b118815SDoug Rabson int32_t rpchdr[128 / sizeof(int32_t)]; 7508f55a568SDoug Rabson int32_t *buf; 7518f55a568SDoug Rabson 7528f55a568SDoug Rabson log_debug("in svc_rpc_gss_validate()"); 7538f55a568SDoug Rabson 7548f55a568SDoug Rabson memset(rpchdr, 0, sizeof(rpchdr)); 7558f55a568SDoug Rabson 7568f55a568SDoug Rabson /* Reconstruct RPC header for signing (from xdr_callmsg). */ 7579b118815SDoug Rabson buf = rpchdr; 7588f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_xid); 7598f55a568SDoug Rabson IXDR_PUT_ENUM(buf, msg->rm_direction); 7608f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); 7618f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); 7628f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); 7638f55a568SDoug Rabson IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); 7648f55a568SDoug Rabson oa = &msg->rm_call.cb_cred; 7658f55a568SDoug Rabson IXDR_PUT_ENUM(buf, oa->oa_flavor); 7668f55a568SDoug Rabson IXDR_PUT_LONG(buf, oa->oa_length); 7678f55a568SDoug Rabson if (oa->oa_length) { 7688f55a568SDoug Rabson memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); 7698f55a568SDoug Rabson buf += RNDUP(oa->oa_length) / sizeof(int32_t); 7708f55a568SDoug Rabson } 7718f55a568SDoug Rabson rpcbuf.value = rpchdr; 7729b118815SDoug Rabson rpcbuf.length = (u_char *)buf - (u_char *)rpchdr; 7738f55a568SDoug Rabson 7748f55a568SDoug Rabson checksum.value = msg->rm_call.cb_verf.oa_base; 7758f55a568SDoug Rabson checksum.length = msg->rm_call.cb_verf.oa_length; 7768f55a568SDoug Rabson 7778f55a568SDoug Rabson maj_stat = gss_verify_mic(&min_stat, client->cl_ctx, &rpcbuf, &checksum, 7788f55a568SDoug Rabson &qop_state); 7798f55a568SDoug Rabson 7808f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 7818f55a568SDoug Rabson log_status("gss_verify_mic", client->cl_mech, 7828f55a568SDoug Rabson maj_stat, min_stat); 7838f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 7848f55a568SDoug Rabson return (FALSE); 7858f55a568SDoug Rabson } 7868f55a568SDoug Rabson *qop = qop_state; 7878f55a568SDoug Rabson return (TRUE); 7888f55a568SDoug Rabson } 7898f55a568SDoug Rabson 7908f55a568SDoug Rabson static bool_t 7918f55a568SDoug Rabson svc_rpc_gss_nextverf(struct svc_rpc_gss_client *client, 7928f55a568SDoug Rabson struct svc_req *rqst, u_int seq) 7938f55a568SDoug Rabson { 7948f55a568SDoug Rabson gss_buffer_desc signbuf; 7958f55a568SDoug Rabson OM_uint32 maj_stat, min_stat; 7968f55a568SDoug Rabson uint32_t nseq; 7978f55a568SDoug Rabson 7988f55a568SDoug Rabson log_debug("in svc_rpc_gss_nextverf()"); 7998f55a568SDoug Rabson 8008f55a568SDoug Rabson nseq = htonl(seq); 8018f55a568SDoug Rabson signbuf.value = &nseq; 8028f55a568SDoug Rabson signbuf.length = sizeof(nseq); 8038f55a568SDoug Rabson 8048f55a568SDoug Rabson if (client->cl_verf.value) 8058f55a568SDoug Rabson gss_release_buffer(&min_stat, &client->cl_verf); 8068f55a568SDoug Rabson 8078f55a568SDoug Rabson maj_stat = gss_get_mic(&min_stat, client->cl_ctx, client->cl_qop, 8088f55a568SDoug Rabson &signbuf, &client->cl_verf); 8098f55a568SDoug Rabson 8108f55a568SDoug Rabson if (maj_stat != GSS_S_COMPLETE) { 8118f55a568SDoug Rabson log_status("gss_get_mic", client->cl_mech, maj_stat, min_stat); 8128f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 8138f55a568SDoug Rabson return (FALSE); 8148f55a568SDoug Rabson } 8158f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; 8168f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_base = (caddr_t)client->cl_verf.value; 8178f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_length = (u_int)client->cl_verf.length; 8188f55a568SDoug Rabson 8198f55a568SDoug Rabson return (TRUE); 8208f55a568SDoug Rabson } 8218f55a568SDoug Rabson 8228f55a568SDoug Rabson static bool_t 8238f55a568SDoug Rabson svc_rpc_gss_callback(struct svc_rpc_gss_client *client, struct svc_req *rqst) 8248f55a568SDoug Rabson { 8258f55a568SDoug Rabson struct svc_rpc_gss_callback *scb; 8268f55a568SDoug Rabson rpc_gss_lock_t lock; 8278f55a568SDoug Rabson void *cookie; 8288f55a568SDoug Rabson bool_t cb_res; 8298f55a568SDoug Rabson bool_t result; 8308f55a568SDoug Rabson 8318f55a568SDoug Rabson /* 8328f55a568SDoug Rabson * See if we have a callback for this guy. 8338f55a568SDoug Rabson */ 8348f55a568SDoug Rabson result = TRUE; 8358f55a568SDoug Rabson SLIST_FOREACH(scb, &svc_rpc_gss_callbacks, cb_link) { 8368f55a568SDoug Rabson if (scb->cb_callback.program == rqst->rq_prog 8378f55a568SDoug Rabson && scb->cb_callback.version == rqst->rq_vers) { 8388f55a568SDoug Rabson /* 8398f55a568SDoug Rabson * This one matches. Call the callback and see 8408f55a568SDoug Rabson * if it wants to veto or something. 8418f55a568SDoug Rabson */ 8428f55a568SDoug Rabson lock.locked = FALSE; 8438f55a568SDoug Rabson lock.raw_cred = &client->cl_rawcred; 8448f55a568SDoug Rabson cb_res = scb->cb_callback.callback(rqst, 8458f55a568SDoug Rabson client->cl_creds, 8468f55a568SDoug Rabson client->cl_ctx, 8478f55a568SDoug Rabson &lock, 8488f55a568SDoug Rabson &cookie); 8498f55a568SDoug Rabson 8508f55a568SDoug Rabson if (!cb_res) { 8518f55a568SDoug Rabson client->cl_state = CLIENT_STALE; 8528f55a568SDoug Rabson result = FALSE; 8538f55a568SDoug Rabson break; 8548f55a568SDoug Rabson } 8558f55a568SDoug Rabson 8568f55a568SDoug Rabson /* 8578f55a568SDoug Rabson * The callback accepted the connection - it 8588f55a568SDoug Rabson * is responsible for freeing client->cl_creds 8598f55a568SDoug Rabson * now. 8608f55a568SDoug Rabson */ 8618f55a568SDoug Rabson client->cl_creds = GSS_C_NO_CREDENTIAL; 8628f55a568SDoug Rabson client->cl_locked = lock.locked; 8638f55a568SDoug Rabson client->cl_cookie = cookie; 8648f55a568SDoug Rabson return (TRUE); 8658f55a568SDoug Rabson } 8668f55a568SDoug Rabson } 8678f55a568SDoug Rabson 8688f55a568SDoug Rabson /* 8698f55a568SDoug Rabson * Either no callback exists for this program/version or one 8708f55a568SDoug Rabson * of the callbacks rejected the connection. We just need to 8718f55a568SDoug Rabson * clean up the delegated client creds, if any. 8728f55a568SDoug Rabson */ 8738f55a568SDoug Rabson if (client->cl_creds) { 8748f55a568SDoug Rabson OM_uint32 min_ver; 8758f55a568SDoug Rabson gss_release_cred(&min_ver, &client->cl_creds); 8768f55a568SDoug Rabson } 8778f55a568SDoug Rabson return (result); 8788f55a568SDoug Rabson } 8798f55a568SDoug Rabson 8808f55a568SDoug Rabson static bool_t 8818f55a568SDoug Rabson svc_rpc_gss_check_replay(struct svc_rpc_gss_client *client, uint32_t seq) 8828f55a568SDoug Rabson { 8838f55a568SDoug Rabson u_int32_t offset; 8848f55a568SDoug Rabson int word, bit; 8858f55a568SDoug Rabson 8868f55a568SDoug Rabson if (seq < client->cl_seqlast) { 8878f55a568SDoug Rabson /* 8888f55a568SDoug Rabson * The request sequence number is less than 8898f55a568SDoug Rabson * the largest we have seen so far. If it is 8908f55a568SDoug Rabson * outside the window or if we have seen a 8918f55a568SDoug Rabson * request with this sequence before, silently 8928f55a568SDoug Rabson * discard it. 8938f55a568SDoug Rabson */ 8948f55a568SDoug Rabson offset = client->cl_seqlast - seq; 8958f55a568SDoug Rabson if (offset >= client->cl_win) 8968f55a568SDoug Rabson return (FALSE); 8978f55a568SDoug Rabson word = offset / 32; 8988f55a568SDoug Rabson bit = offset % 32; 8998f55a568SDoug Rabson if (client->cl_seqmask[word] & (1 << bit)) 9008f55a568SDoug Rabson return (FALSE); 9018f55a568SDoug Rabson client->cl_seqmask[word] |= (1 << bit); 9028f55a568SDoug Rabson } 9038f55a568SDoug Rabson 9048f55a568SDoug Rabson return (TRUE); 9058f55a568SDoug Rabson } 9068f55a568SDoug Rabson 9078f55a568SDoug Rabson static void 9088f55a568SDoug Rabson svc_rpc_gss_update_seq(struct svc_rpc_gss_client *client, uint32_t seq) 9098f55a568SDoug Rabson { 9108f55a568SDoug Rabson int offset, i; 9118f55a568SDoug Rabson uint32_t carry, newcarry; 9128f55a568SDoug Rabson 9138f55a568SDoug Rabson if (seq > client->cl_seqlast) { 9148f55a568SDoug Rabson /* 9158f55a568SDoug Rabson * This request has a sequence number greater 9168f55a568SDoug Rabson * than any we have seen so far. Advance the 9178f55a568SDoug Rabson * seq window and set bit zero of the window 9188f55a568SDoug Rabson * (which corresponds to the new sequence 9198f55a568SDoug Rabson * number) 9208f55a568SDoug Rabson */ 9218f55a568SDoug Rabson offset = seq - client->cl_seqlast; 9228f55a568SDoug Rabson while (offset > 32) { 9238f55a568SDoug Rabson for (i = (SVC_RPC_GSS_SEQWINDOW / 32) - 1; 9248f55a568SDoug Rabson i > 0; i--) { 9258f55a568SDoug Rabson client->cl_seqmask[i] = client->cl_seqmask[i-1]; 9268f55a568SDoug Rabson } 9278f55a568SDoug Rabson client->cl_seqmask[0] = 0; 9288f55a568SDoug Rabson offset -= 32; 9298f55a568SDoug Rabson } 9308f55a568SDoug Rabson carry = 0; 9318f55a568SDoug Rabson for (i = 0; i < SVC_RPC_GSS_SEQWINDOW / 32; i++) { 9328f55a568SDoug Rabson newcarry = client->cl_seqmask[i] >> (32 - offset); 9338f55a568SDoug Rabson client->cl_seqmask[i] = 9348f55a568SDoug Rabson (client->cl_seqmask[i] << offset) | carry; 9358f55a568SDoug Rabson carry = newcarry; 9368f55a568SDoug Rabson } 9378f55a568SDoug Rabson client->cl_seqmask[0] |= 1; 9388f55a568SDoug Rabson client->cl_seqlast = seq; 9398f55a568SDoug Rabson } 9408f55a568SDoug Rabson } 9418f55a568SDoug Rabson 9428f55a568SDoug Rabson enum auth_stat 9438f55a568SDoug Rabson svc_rpc_gss(struct svc_req *rqst, struct rpc_msg *msg) 9448f55a568SDoug Rabson 9458f55a568SDoug Rabson { 9468f55a568SDoug Rabson OM_uint32 min_stat; 9478f55a568SDoug Rabson XDR xdrs; 9488f55a568SDoug Rabson struct svc_rpc_gss_client *client; 9498f55a568SDoug Rabson struct rpc_gss_cred gc; 9508f55a568SDoug Rabson struct rpc_gss_init_res gr; 9518f55a568SDoug Rabson gss_qop_t qop; 9528f55a568SDoug Rabson int call_stat; 9538f55a568SDoug Rabson enum auth_stat result; 9548f55a568SDoug Rabson 9558f55a568SDoug Rabson log_debug("in svc_rpc_gss()"); 9568f55a568SDoug Rabson 9578f55a568SDoug Rabson /* Garbage collect old clients. */ 9588f55a568SDoug Rabson svc_rpc_gss_timeout_clients(); 9598f55a568SDoug Rabson 9608f55a568SDoug Rabson /* Initialize reply. */ 9618f55a568SDoug Rabson rqst->rq_xprt->xp_verf = _null_auth; 9628f55a568SDoug Rabson 9638f55a568SDoug Rabson /* Deserialize client credentials. */ 9648f55a568SDoug Rabson if (rqst->rq_cred.oa_length <= 0) 9658f55a568SDoug Rabson return (AUTH_BADCRED); 9668f55a568SDoug Rabson 9678f55a568SDoug Rabson memset(&gc, 0, sizeof(gc)); 9688f55a568SDoug Rabson 9698f55a568SDoug Rabson xdrmem_create(&xdrs, rqst->rq_cred.oa_base, 9708f55a568SDoug Rabson rqst->rq_cred.oa_length, XDR_DECODE); 9718f55a568SDoug Rabson 9728f55a568SDoug Rabson if (!xdr_rpc_gss_cred(&xdrs, &gc)) { 9738f55a568SDoug Rabson XDR_DESTROY(&xdrs); 9748f55a568SDoug Rabson return (AUTH_BADCRED); 9758f55a568SDoug Rabson } 9768f55a568SDoug Rabson XDR_DESTROY(&xdrs); 9778f55a568SDoug Rabson 9788f55a568SDoug Rabson /* Check version. */ 9798f55a568SDoug Rabson if (gc.gc_version != RPCSEC_GSS_VERSION) { 9808f55a568SDoug Rabson result = AUTH_BADCRED; 9818f55a568SDoug Rabson goto out; 9828f55a568SDoug Rabson } 9838f55a568SDoug Rabson 9848f55a568SDoug Rabson /* Check the proc and find the client (or create it) */ 9858f55a568SDoug Rabson if (gc.gc_proc == RPCSEC_GSS_INIT) { 9868f55a568SDoug Rabson client = svc_rpc_gss_create_client(); 9878f55a568SDoug Rabson } else { 9888f55a568SDoug Rabson if (gc.gc_handle.length != sizeof(uint32_t)) { 9898f55a568SDoug Rabson result = AUTH_BADCRED; 9908f55a568SDoug Rabson goto out; 9918f55a568SDoug Rabson } 9928f55a568SDoug Rabson uint32_t *p = gc.gc_handle.value; 9938f55a568SDoug Rabson client = svc_rpc_gss_find_client(*p); 9948f55a568SDoug Rabson if (!client) { 9958f55a568SDoug Rabson /* 9968f55a568SDoug Rabson * Can't find the client - we may have 9978f55a568SDoug Rabson * destroyed it - tell the other side to 9988f55a568SDoug Rabson * re-authenticate. 9998f55a568SDoug Rabson */ 10008f55a568SDoug Rabson result = RPCSEC_GSS_CREDPROBLEM; 10018f55a568SDoug Rabson goto out; 10028f55a568SDoug Rabson } 10038f55a568SDoug Rabson } 10048f55a568SDoug Rabson rqst->rq_clntcred = client; 10058f55a568SDoug Rabson 10068f55a568SDoug Rabson /* 10078f55a568SDoug Rabson * The service and sequence number must be ignored for 10088f55a568SDoug Rabson * RPCSEC_GSS_INIT and RPCSEC_GSS_CONTINUE_INIT. 10098f55a568SDoug Rabson */ 10108f55a568SDoug Rabson if (gc.gc_proc != RPCSEC_GSS_INIT 10118f55a568SDoug Rabson && gc.gc_proc != RPCSEC_GSS_CONTINUE_INIT) { 10128f55a568SDoug Rabson /* 10138f55a568SDoug Rabson * Check for sequence number overflow. 10148f55a568SDoug Rabson */ 10158f55a568SDoug Rabson if (gc.gc_seq >= MAXSEQ) { 10168f55a568SDoug Rabson result = RPCSEC_GSS_CTXPROBLEM; 10178f55a568SDoug Rabson goto out; 10188f55a568SDoug Rabson } 10198f55a568SDoug Rabson client->cl_seq = gc.gc_seq; 10208f55a568SDoug Rabson 10218f55a568SDoug Rabson /* 10228f55a568SDoug Rabson * Check for valid service. 10238f55a568SDoug Rabson */ 10248f55a568SDoug Rabson if (gc.gc_svc != rpc_gss_svc_none && 10258f55a568SDoug Rabson gc.gc_svc != rpc_gss_svc_integrity && 10268f55a568SDoug Rabson gc.gc_svc != rpc_gss_svc_privacy) { 10278f55a568SDoug Rabson result = AUTH_BADCRED; 10288f55a568SDoug Rabson goto out; 10298f55a568SDoug Rabson } 10308f55a568SDoug Rabson } 10318f55a568SDoug Rabson 10328f55a568SDoug Rabson /* Handle RPCSEC_GSS control procedure. */ 10338f55a568SDoug Rabson switch (gc.gc_proc) { 10348f55a568SDoug Rabson 10358f55a568SDoug Rabson case RPCSEC_GSS_INIT: 10368f55a568SDoug Rabson case RPCSEC_GSS_CONTINUE_INIT: 10378f55a568SDoug Rabson if (rqst->rq_proc != NULLPROC) { 10388f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 10398f55a568SDoug Rabson break; 10408f55a568SDoug Rabson } 10418f55a568SDoug Rabson 10428f55a568SDoug Rabson memset(&gr, 0, sizeof(gr)); 10438f55a568SDoug Rabson if (!svc_rpc_gss_accept_sec_context(client, rqst, &gr, &gc)) { 10448f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 10458f55a568SDoug Rabson break; 10468f55a568SDoug Rabson } 10478f55a568SDoug Rabson 10488f55a568SDoug Rabson if (gr.gr_major == GSS_S_COMPLETE) { 10498f55a568SDoug Rabson if (!svc_rpc_gss_nextverf(client, rqst, gr.gr_win)) { 10508f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 10518f55a568SDoug Rabson break; 10528f55a568SDoug Rabson } 10538f55a568SDoug Rabson } else { 10548f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL; 10558f55a568SDoug Rabson rqst->rq_xprt->xp_verf.oa_length = 0; 10568f55a568SDoug Rabson } 10578f55a568SDoug Rabson 10588f55a568SDoug Rabson call_stat = svc_sendreply(rqst->rq_xprt, 10598f55a568SDoug Rabson (xdrproc_t) xdr_rpc_gss_init_res, 10608f55a568SDoug Rabson (caddr_t) &gr); 10618f55a568SDoug Rabson 10628f55a568SDoug Rabson gss_release_buffer(&min_stat, &gr.gr_token); 10638f55a568SDoug Rabson 10648f55a568SDoug Rabson if (!call_stat) { 10658f55a568SDoug Rabson result = AUTH_FAILED; 10668f55a568SDoug Rabson break; 10678f55a568SDoug Rabson } 10688f55a568SDoug Rabson 10698f55a568SDoug Rabson if (gr.gr_major == GSS_S_COMPLETE) 10708f55a568SDoug Rabson client->cl_state = CLIENT_ESTABLISHED; 10718f55a568SDoug Rabson 10728f55a568SDoug Rabson result = RPCSEC_GSS_NODISPATCH; 10738f55a568SDoug Rabson break; 10748f55a568SDoug Rabson 10758f55a568SDoug Rabson case RPCSEC_GSS_DATA: 10768f55a568SDoug Rabson case RPCSEC_GSS_DESTROY: 10778f55a568SDoug Rabson if (!svc_rpc_gss_check_replay(client, gc.gc_seq)) { 10788f55a568SDoug Rabson result = RPCSEC_GSS_NODISPATCH; 10798f55a568SDoug Rabson break; 10808f55a568SDoug Rabson } 10818f55a568SDoug Rabson 10828f55a568SDoug Rabson if (!svc_rpc_gss_validate(client, msg, &qop)) { 10838f55a568SDoug Rabson result = RPCSEC_GSS_CREDPROBLEM; 10848f55a568SDoug Rabson break; 10858f55a568SDoug Rabson } 10868f55a568SDoug Rabson 10878f55a568SDoug Rabson if (!svc_rpc_gss_nextverf(client, rqst, gc.gc_seq)) { 10888f55a568SDoug Rabson result = RPCSEC_GSS_CTXPROBLEM; 10898f55a568SDoug Rabson break; 10908f55a568SDoug Rabson } 10918f55a568SDoug Rabson 10928f55a568SDoug Rabson svc_rpc_gss_update_seq(client, gc.gc_seq); 10938f55a568SDoug Rabson 10948f55a568SDoug Rabson /* 10958f55a568SDoug Rabson * Change the SVCAUTH ops on the transport to point at 10968f55a568SDoug Rabson * our own code so that we can unwrap the arguments 10978f55a568SDoug Rabson * and wrap the result. The caller will re-set this on 10988f55a568SDoug Rabson * every request to point to a set of null wrap/unwrap 10998f55a568SDoug Rabson * methods. 11008f55a568SDoug Rabson */ 11018f55a568SDoug Rabson SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_gss_ops; 11028f55a568SDoug Rabson SVC_AUTH(rqst->rq_xprt).svc_ah_private = client; 11038f55a568SDoug Rabson 11048f55a568SDoug Rabson if (gc.gc_proc == RPCSEC_GSS_DATA) { 11058f55a568SDoug Rabson /* 11068f55a568SDoug Rabson * We might be ready to do a callback to the server to 11078f55a568SDoug Rabson * see if it wants to accept/reject the connection. 11088f55a568SDoug Rabson */ 11098f55a568SDoug Rabson if (!client->cl_done_callback) { 11108f55a568SDoug Rabson client->cl_done_callback = TRUE; 11118f55a568SDoug Rabson client->cl_qop = qop; 11128f55a568SDoug Rabson client->cl_rawcred.qop = _rpc_gss_num_to_qop( 11138f55a568SDoug Rabson client->cl_rawcred.mechanism, qop); 11148f55a568SDoug Rabson if (!svc_rpc_gss_callback(client, rqst)) { 11158f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 11168f55a568SDoug Rabson break; 11178f55a568SDoug Rabson } 11188f55a568SDoug Rabson } 11198f55a568SDoug Rabson 11208f55a568SDoug Rabson /* 11218f55a568SDoug Rabson * If the server has locked this client to a 11228f55a568SDoug Rabson * particular service+qop pair, enforce that 11238f55a568SDoug Rabson * restriction now. 11248f55a568SDoug Rabson */ 11258f55a568SDoug Rabson if (client->cl_locked) { 11268f55a568SDoug Rabson if (client->cl_rawcred.service != gc.gc_svc) { 11278f55a568SDoug Rabson result = AUTH_FAILED; 11288f55a568SDoug Rabson break; 11298f55a568SDoug Rabson } else if (client->cl_qop != qop) { 11308f55a568SDoug Rabson result = AUTH_BADVERF; 11318f55a568SDoug Rabson break; 11328f55a568SDoug Rabson } 11338f55a568SDoug Rabson } 11348f55a568SDoug Rabson 11358f55a568SDoug Rabson /* 11368f55a568SDoug Rabson * If the qop changed, look up the new qop 11378f55a568SDoug Rabson * name for rawcred. 11388f55a568SDoug Rabson */ 11398f55a568SDoug Rabson if (client->cl_qop != qop) { 11408f55a568SDoug Rabson client->cl_qop = qop; 11418f55a568SDoug Rabson client->cl_rawcred.qop = _rpc_gss_num_to_qop( 11428f55a568SDoug Rabson client->cl_rawcred.mechanism, qop); 11438f55a568SDoug Rabson } 11448f55a568SDoug Rabson 11458f55a568SDoug Rabson /* 11468f55a568SDoug Rabson * Make sure we use the right service value 11478f55a568SDoug Rabson * for unwrap/wrap. 11488f55a568SDoug Rabson */ 11498f55a568SDoug Rabson client->cl_rawcred.service = gc.gc_svc; 11508f55a568SDoug Rabson 11518f55a568SDoug Rabson result = AUTH_OK; 11528f55a568SDoug Rabson } else { 11538f55a568SDoug Rabson if (rqst->rq_proc != NULLPROC) { 11548f55a568SDoug Rabson result = AUTH_REJECTEDCRED; 11558f55a568SDoug Rabson break; 11568f55a568SDoug Rabson } 11578f55a568SDoug Rabson 11588f55a568SDoug Rabson call_stat = svc_sendreply(rqst->rq_xprt, 11598f55a568SDoug Rabson (xdrproc_t) xdr_void, (caddr_t) NULL); 11608f55a568SDoug Rabson 11618f55a568SDoug Rabson if (!call_stat) { 11628f55a568SDoug Rabson result = AUTH_FAILED; 11638f55a568SDoug Rabson break; 11648f55a568SDoug Rabson } 11658f55a568SDoug Rabson 11668f55a568SDoug Rabson svc_rpc_gss_destroy_client(client); 11678f55a568SDoug Rabson 11688f55a568SDoug Rabson result = RPCSEC_GSS_NODISPATCH; 11698f55a568SDoug Rabson break; 11708f55a568SDoug Rabson } 11718f55a568SDoug Rabson break; 11728f55a568SDoug Rabson 11738f55a568SDoug Rabson default: 11748f55a568SDoug Rabson result = AUTH_BADCRED; 11758f55a568SDoug Rabson break; 11768f55a568SDoug Rabson } 11778f55a568SDoug Rabson out: 11788f55a568SDoug Rabson xdr_free((xdrproc_t) xdr_rpc_gss_cred, (char *) &gc); 11798f55a568SDoug Rabson return (result); 11808f55a568SDoug Rabson } 11818f55a568SDoug Rabson 11828f55a568SDoug Rabson bool_t 11838f55a568SDoug Rabson svc_rpc_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) 11848f55a568SDoug Rabson { 11858f55a568SDoug Rabson struct svc_rpc_gss_client *client; 11868f55a568SDoug Rabson 11878f55a568SDoug Rabson log_debug("in svc_rpc_gss_wrap()"); 11888f55a568SDoug Rabson 11898f55a568SDoug Rabson client = (struct svc_rpc_gss_client *) auth->svc_ah_private; 11908f55a568SDoug Rabson if (client->cl_state != CLIENT_ESTABLISHED 11918f55a568SDoug Rabson || client->cl_rawcred.service == rpc_gss_svc_none) { 11928f55a568SDoug Rabson return xdr_func(xdrs, xdr_ptr); 11938f55a568SDoug Rabson } 11948f55a568SDoug Rabson return (xdr_rpc_gss_wrap_data(xdrs, xdr_func, xdr_ptr, 11958f55a568SDoug Rabson client->cl_ctx, client->cl_qop, 11968f55a568SDoug Rabson client->cl_rawcred.service, client->cl_seq)); 11978f55a568SDoug Rabson } 11988f55a568SDoug Rabson 11998f55a568SDoug Rabson bool_t 12008f55a568SDoug Rabson svc_rpc_gss_unwrap(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_unwrap()"); 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_unwrap_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 } 1215