1/* 2 * Copyright (c) 2007-2010 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28 29/************* 30 * These functions implement RPCSEC_GSS security for the NFS client and server. 31 * The code is specific to the use of Kerberos v5 and the use of DES MAC MD5 32 * protection as described in Internet RFC 2203 and 2623. 33 * 34 * In contrast to the original AUTH_SYS authentication, RPCSEC_GSS is stateful. 35 * It requires the client and server negotiate a secure connection as part of a 36 * security context. The context state is maintained in client and server structures. 37 * On the client side, each user of an NFS mount is assigned their own context, 38 * identified by UID, on their first use of the mount, and it persists until the 39 * unmount or until the context is renewed. Each user context has a corresponding 40 * server context which the server maintains until the client destroys it, or 41 * until the context expires. 42 * 43 * The client and server contexts are set up dynamically. When a user attempts 44 * to send an NFS request, if there is no context for the user, then one is 45 * set up via an exchange of NFS null procedure calls as described in RFC 2203. 46 * During this exchange, the client and server pass a security token that is 47 * forwarded via Mach upcall to the gssd, which invokes the GSS-API to authenticate 48 * the user to the server (and vice-versa). The client and server also receive 49 * a unique session key that can be used to digitally sign the credentials and 50 * verifier or optionally to provide data integrity and/or privacy. 51 * 52 * Once the context is complete, the client and server enter a normal data 53 * exchange phase - beginning with the NFS request that prompted the context 54 * creation. During this phase, the client's RPC header contains an RPCSEC_GSS 55 * credential and verifier, and the server returns a verifier as well. 56 * For simple authentication, the verifier contains a signed checksum of the 57 * RPC header, including the credential. The server's verifier has a signed 58 * checksum of the current sequence number. 59 * 60 * Each client call contains a sequence number that nominally increases by one 61 * on each request. The sequence number is intended to prevent replay attacks. 62 * Since the protocol can be used over UDP, there is some allowance for 63 * out-of-sequence requests, so the server checks whether the sequence numbers 64 * are within a sequence "window". If a sequence number is outside the lower 65 * bound of the window, the server silently drops the request. This has some 66 * implications for retransmission. If a request needs to be retransmitted, the 67 * client must bump the sequence number even if the request XID is unchanged. 68 * 69 * When the NFS mount is unmounted, the client sends a "destroy" credential 70 * to delete the server's context for each user of the mount. Since it's 71 * possible for the client to crash or disconnect without sending the destroy 72 * message, the server has a thread that reaps contexts that have been idle 73 * too long. 74 */ 75 76#include <stdint.h> 77#include <sys/param.h> 78#include <sys/systm.h> 79#include <sys/proc.h> 80#include <sys/kauth.h> 81#include <sys/kernel.h> 82#include <sys/mount_internal.h> 83#include <sys/vnode.h> 84#include <sys/ubc.h> 85#include <sys/malloc.h> 86#include <sys/kpi_mbuf.h> 87 88#include <kern/host.h> 89#include <libkern/libkern.h> 90 91#include <mach/task.h> 92#include <mach/host_special_ports.h> 93#include <mach/host_priv.h> 94#include <mach/thread_act.h> 95#include <mach/mig_errors.h> 96#include <mach/vm_map.h> 97#include <vm/vm_map.h> 98#include <vm/vm_kern.h> 99#include <gssd/gssd_mach.h> 100 101#include <nfs/rpcv2.h> 102#include <nfs/nfsproto.h> 103#include <nfs/nfs.h> 104#include <nfs/nfsnode.h> 105#include <nfs/nfs_gss.h> 106#include <nfs/nfsmount.h> 107#include <nfs/xdr_subs.h> 108#include <nfs/nfsm_subs.h> 109#include <nfs/nfs_gss.h> 110 111#include "nfs_gss_crypto.h" 112 113#define NFS_GSS_MACH_MAX_RETRIES 3 114 115typedef struct { 116 int type; 117 union { 118 MD5_DESCBC_CTX m_ctx; 119 HMAC_SHA1_DES3KD_CTX h_ctx; 120 }; 121} GSS_DIGEST_CTX; 122 123#define MAX_DIGEST SHA_DIGEST_LENGTH 124#ifdef NFS_KERNEL_DEBUG 125#define HASHLEN(ki) (((ki)->hash_len > MAX_DIGEST) ? \ 126 (panic("nfs_gss.c:%d ki->hash_len is invalid = %d\n", __LINE__, (ki)->hash_len), MAX_DIGEST) : (ki)->hash_len) 127#else 128#define HASHLEN(ki) (((ki)->hash_len > MAX_DIGEST) ? \ 129 (printf("nfs_gss.c:%d ki->hash_len is invalid = %d\n", __LINE__, (ki)->hash_len), MAX_DIGEST) : (ki)->hash_len) 130#endif 131 132#if NFSSERVER 133u_long nfs_gss_svc_ctx_hash; 134struct nfs_gss_svc_ctx_hashhead *nfs_gss_svc_ctx_hashtbl; 135lck_mtx_t *nfs_gss_svc_ctx_mutex; 136lck_grp_t *nfs_gss_svc_grp; 137uint32_t nfsrv_gss_context_ttl = GSS_CTX_EXPIRE; 138#define GSS_SVC_CTX_TTL ((uint64_t)max(2*GSS_CTX_PEND, nfsrv_gss_context_ttl) * NSEC_PER_SEC) 139#endif /* NFSSERVER */ 140 141#if NFSCLIENT 142lck_grp_t *nfs_gss_clnt_grp; 143int nfs_single_des; 144#endif /* NFSCLIENT */ 145 146/* 147 * These octet strings are used to encode/decode ASN.1 tokens 148 * in the RPCSEC_GSS verifiers. 149 */ 150static u_char krb5_tokhead[] __attribute__((unused)) = { 0x60, 0x23 }; 151 u_char krb5_mech[11] = { 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 }; 152static u_char krb5_mic[] = { 0x01, 0x01, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff }; 153static u_char krb5_mic3[] = { 0x01, 0x01, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff }; 154static u_char krb5_wrap[] = { 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff }; 155static u_char krb5_wrap3[] = { 0x02, 0x01, 0x04, 0x00, 0x02, 0x00, 0xff, 0xff }; 156static u_char iv0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; // DES MAC Initialization Vector 157 158#define ALG_MIC(ki) (((ki)->type == NFS_GSS_1DES) ? krb5_mic : krb5_mic3) 159#define ALG_WRAP(ki) (((ki)->type == NFS_GSS_1DES) ? krb5_wrap : krb5_wrap3) 160 161/* 162 * The size of the Kerberos v5 ASN.1 token 163 * in the verifier. 164 * 165 * Note that the second octet of the krb5_tokhead (0x23) is a 166 * DER-encoded size field that has variable length. If the size 167 * is 128 bytes or greater, then it uses two bytes, three bytes 168 * if 65536 or greater, and so on. Since the MIC tokens are 169 * separate from the data, the size is always the same: 35 bytes (0x23). 170 * However, the wrap token is different. Its size field includes the 171 * size of the token + the encrypted data that follows. So the size 172 * field may be two, three or four bytes. 173 */ 174#define KRB5_SZ_TOKHEAD sizeof(krb5_tokhead) 175#define KRB5_SZ_MECH sizeof(krb5_mech) 176#define KRB5_SZ_ALG sizeof(krb5_mic) // 8 - same as krb5_wrap 177#define KRB5_SZ_SEQ 8 178#define KRB5_SZ_EXTRA 3 // a wrap token may be longer by up to this many octets 179#define KRB5_SZ_TOKEN_NOSUM (KRB5_SZ_TOKHEAD + KRB5_SZ_MECH + KRB5_SZ_ALG + KRB5_SZ_SEQ) 180#define KRB5_SZ_TOKEN(cksumlen) ((cksumlen) + KRB5_SZ_TOKEN_NOSUM) 181#define KRB5_SZ_TOKMAX(cksumlen) (KRB5_SZ_TOKEN(cksumlen) + KRB5_SZ_EXTRA) 182 183#if NFSCLIENT 184static int nfs_gss_clnt_ctx_find(struct nfsreq *); 185static int nfs_gss_clnt_ctx_failover(struct nfsreq *); 186static int nfs_gss_clnt_ctx_init(struct nfsreq *, struct nfs_gss_clnt_ctx *); 187static int nfs_gss_clnt_ctx_init_retry(struct nfsreq *, struct nfs_gss_clnt_ctx *); 188static int nfs_gss_clnt_ctx_callserver(struct nfsreq *, struct nfs_gss_clnt_ctx *); 189static char *nfs_gss_clnt_svcname(struct nfsmount *); 190static int nfs_gss_clnt_gssd_upcall(struct nfsreq *, struct nfs_gss_clnt_ctx *); 191static void nfs_gss_clnt_ctx_remove(struct nfsmount *, struct nfs_gss_clnt_ctx *); 192#endif /* NFSCLIENT */ 193 194#if NFSSERVER 195static struct nfs_gss_svc_ctx *nfs_gss_svc_ctx_find(uint32_t); 196static void nfs_gss_svc_ctx_insert(struct nfs_gss_svc_ctx *); 197static void nfs_gss_svc_ctx_timer(void *, void *); 198static int nfs_gss_svc_gssd_upcall(struct nfs_gss_svc_ctx *); 199static int nfs_gss_svc_seqnum_valid(struct nfs_gss_svc_ctx *, uint32_t); 200#endif /* NFSSERVER */ 201 202static void host_release_special_port(mach_port_t); 203static mach_port_t host_copy_special_port(mach_port_t); 204static void nfs_gss_mach_alloc_buffer(u_char *, uint32_t, vm_map_copy_t *); 205static int nfs_gss_mach_vmcopyout(vm_map_copy_t, uint32_t, u_char *); 206static int nfs_gss_token_get(gss_key_info *ki, u_char *, u_char *, int, uint32_t *, u_char *); 207static int nfs_gss_token_put(gss_key_info *ki, u_char *, u_char *, int, int, u_char *); 208static int nfs_gss_der_length_size(int); 209static void nfs_gss_der_length_put(u_char **, int); 210static int nfs_gss_der_length_get(u_char **); 211static int nfs_gss_mchain_length(mbuf_t); 212static int nfs_gss_append_chain(struct nfsm_chain *, mbuf_t); 213static void nfs_gss_nfsm_chain(struct nfsm_chain *, mbuf_t); 214static void nfs_gss_cksum_mchain(gss_key_info *, mbuf_t, u_char *, int, int, u_char *); 215static void nfs_gss_cksum_chain(gss_key_info *, struct nfsm_chain *, u_char *, int, int, u_char *); 216static void nfs_gss_cksum_rep(gss_key_info *, uint32_t, u_char *); 217static void nfs_gss_encrypt_mchain(gss_key_info *, mbuf_t, int, int, int); 218static void nfs_gss_encrypt_chain(gss_key_info *, struct nfsm_chain *, int, int, int); 219 220static void gss_digest_Init(GSS_DIGEST_CTX *, gss_key_info *); 221static void gss_digest_Update(GSS_DIGEST_CTX *, void *, size_t); 222static void gss_digest_Final(GSS_DIGEST_CTX *, void *); 223static void gss_des_crypt(gss_key_info *, des_cblock *, des_cblock *, 224 int32_t, des_cblock *, des_cblock *, int, int); 225static int gss_key_init(gss_key_info *, uint32_t); 226 227#if NFSSERVER 228thread_call_t nfs_gss_svc_ctx_timer_call; 229int nfs_gss_timer_on = 0; 230uint32_t nfs_gss_ctx_count = 0; 231const uint32_t nfs_gss_ctx_max = GSS_SVC_MAXCONTEXTS; 232#endif /* NFSSERVER */ 233 234/* 235 * Initialization when NFS starts 236 */ 237void 238nfs_gss_init(void) 239{ 240#if NFSCLIENT 241 nfs_gss_clnt_grp = lck_grp_alloc_init("rpcsec_gss_clnt", LCK_GRP_ATTR_NULL); 242#endif /* NFSCLIENT */ 243 244#if NFSSERVER 245 nfs_gss_svc_grp = lck_grp_alloc_init("rpcsec_gss_svc", LCK_GRP_ATTR_NULL); 246 247 nfs_gss_svc_ctx_hashtbl = hashinit(SVC_CTX_HASHSZ, M_TEMP, &nfs_gss_svc_ctx_hash); 248 nfs_gss_svc_ctx_mutex = lck_mtx_alloc_init(nfs_gss_svc_grp, LCK_ATTR_NULL); 249 250 nfs_gss_svc_ctx_timer_call = thread_call_allocate(nfs_gss_svc_ctx_timer, NULL); 251#endif /* NFSSERVER */ 252} 253 254#if NFSCLIENT 255 256/* 257 * Is it OK to fall back to using AUTH_SYS? 258 */ 259static int 260nfs_gss_sysok(struct nfsreq *req) 261{ 262 struct nfsmount *nmp = req->r_nmp; 263 int i; 264 265 if (req->r_wrongsec) /* Not OK if we're trying to handle a wrongsec error */ 266 return (0); 267 if (!nmp->nm_sec.count) /* assume it's OK if we don't have a set of flavors */ 268 return (1); 269 for (i=0; i < nmp->nm_sec.count; i++) 270 if (nmp->nm_sec.flavors[i] == RPCAUTH_SYS) 271 return (1); 272 return (0); 273} 274 275/* 276 * Find the context for a particular user. 277 * 278 * If the context doesn't already exist 279 * then create a new context for this user. 280 * 281 * Note that the code allows superuser (uid == 0) 282 * to adopt the context of another user. 283 */ 284static int 285nfs_gss_clnt_ctx_find(struct nfsreq *req) 286{ 287 struct nfsmount *nmp = req->r_nmp; 288 struct nfs_gss_clnt_ctx *cp; 289 uid_t uid = kauth_cred_getuid(req->r_cred); 290 int error = 0; 291 292 lck_mtx_lock(&nmp->nm_lock); 293 TAILQ_FOREACH(cp, &nmp->nm_gsscl, gss_clnt_entries) { 294 if (cp->gss_clnt_uid == uid) { 295 if (cp->gss_clnt_flags & GSS_CTX_INVAL) 296 continue; 297 nfs_gss_clnt_ctx_ref(req, cp); 298 lck_mtx_unlock(&nmp->nm_lock); 299 return (0); 300 } 301 } 302 303 if (uid == 0) { 304 /* 305 * If superuser is trying to get access, then co-opt 306 * the first valid context in the list. 307 * XXX Ultimately, we need to allow superuser to 308 * go ahead and attempt to set up its own context 309 * in case one is set up for it. 310 */ 311 TAILQ_FOREACH(cp, &nmp->nm_gsscl, gss_clnt_entries) { 312 if (!(cp->gss_clnt_flags & GSS_CTX_INVAL)) { 313 nfs_gss_clnt_ctx_ref(req, cp); 314 lck_mtx_unlock(&nmp->nm_lock); 315 return (0); 316 } 317 } 318 } 319 320 /* 321 * Not found - create a new context 322 */ 323 324 /* 325 * If the thread is async, then it cannot get 326 * kerberos creds and set up a proper context. 327 * If no sec= mount option is given, attempt 328 * to failover to sec=sys. 329 */ 330 if (req->r_thread == NULL) { 331 if (nfs_gss_sysok(req)) { 332 error = nfs_gss_clnt_ctx_failover(req); 333 } else { 334 printf("nfs_gss_clnt_ctx_find: no context for async\n"); 335 error = NFSERR_EAUTH; 336 } 337 338 lck_mtx_unlock(&nmp->nm_lock); 339 return (error); 340 } 341 342 MALLOC(cp, struct nfs_gss_clnt_ctx *, sizeof(*cp), M_TEMP, M_WAITOK|M_ZERO); 343 if (cp == NULL) { 344 lck_mtx_unlock(&nmp->nm_lock); 345 return (ENOMEM); 346 } 347 348 cp->gss_clnt_uid = uid; 349 cp->gss_clnt_mtx = lck_mtx_alloc_init(nfs_gss_clnt_grp, LCK_ATTR_NULL); 350 cp->gss_clnt_thread = current_thread(); 351 nfs_gss_clnt_ctx_ref(req, cp); 352 TAILQ_INSERT_TAIL(&nmp->nm_gsscl, cp, gss_clnt_entries); 353 lck_mtx_unlock(&nmp->nm_lock); 354 355 error = nfs_gss_clnt_ctx_init_retry(req, cp); // Initialize new context 356 if (error) 357 nfs_gss_clnt_ctx_unref(req); 358 359 /* 360 * If we failed to set up a Kerberos context for this 361 * user and no sec= mount option was given, but the 362 * server indicated that it could support AUTH_SYS, then set 363 * up a dummy context that allows this user to attempt 364 * sec=sys calls. 365 */ 366 if (error && nfs_gss_sysok(req) && 367 (error != ENXIO) && (error != ETIMEDOUT)) { 368 lck_mtx_lock(&nmp->nm_lock); 369 error = nfs_gss_clnt_ctx_failover(req); 370 lck_mtx_unlock(&nmp->nm_lock); 371 } 372 373 return (error); 374} 375 376/* 377 * Set up a dummy context to allow the use of sec=sys 378 * for this user, if the server allows sec=sys. 379 * The context is valid for GSS_CLNT_SYS_VALID seconds, 380 * so that the user will periodically attempt to fail back 381 * and get a real credential. 382 * 383 * Assumes context list (nm_lock) is locked 384 */ 385static int 386nfs_gss_clnt_ctx_failover(struct nfsreq *req) 387{ 388 struct nfsmount *nmp = req->r_nmp; 389 struct nfs_gss_clnt_ctx *cp; 390 uid_t uid = kauth_cred_getuid(req->r_cred); 391 struct timeval now; 392 393 MALLOC(cp, struct nfs_gss_clnt_ctx *, sizeof(*cp), M_TEMP, M_WAITOK|M_ZERO); 394 if (cp == NULL) 395 return (ENOMEM); 396 397 cp->gss_clnt_service = RPCSEC_GSS_SVC_SYS; 398 cp->gss_clnt_uid = uid; 399 cp->gss_clnt_mtx = lck_mtx_alloc_init(nfs_gss_clnt_grp, LCK_ATTR_NULL); 400 microuptime(&now); 401 cp->gss_clnt_ctime = now.tv_sec; // time stamp 402 nfs_gss_clnt_ctx_ref(req, cp); 403 TAILQ_INSERT_TAIL(&nmp->nm_gsscl, cp, gss_clnt_entries); 404 405 return (0); 406} 407 408/* 409 * Inserts an RPCSEC_GSS credential into an RPC header. 410 * After the credential is inserted, the code continues 411 * to build the verifier which contains a signed checksum 412 * of the RPC header. 413 */ 414int 415nfs_gss_clnt_cred_put(struct nfsreq *req, struct nfsm_chain *nmc, mbuf_t args) 416{ 417 struct nfs_gss_clnt_ctx *cp; 418 uint32_t seqnum = 0; 419 int error = 0; 420 int slpflag, recordmark = 0; 421 int start, len, offset = 0; 422 int pad, toklen; 423 struct nfsm_chain nmc_tmp; 424 struct gss_seq *gsp; 425 u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)]; 426 u_char cksum[MAX_DIGEST]; 427 struct timeval now; 428 gss_key_info *ki; 429 430 slpflag = (PZERO-1); 431 if (req->r_nmp) { 432 slpflag |= (NMFLAG(req->r_nmp, INTR) && req->r_thread && !(req->r_flags & R_NOINTR)) ? PCATCH : 0; 433 recordmark = (req->r_nmp->nm_sotype == SOCK_STREAM); 434 } 435retry: 436 if (req->r_gss_ctx == NULL) { 437 /* 438 * Find the context for this user. 439 * If no context is found, one will 440 * be created. 441 */ 442 error = nfs_gss_clnt_ctx_find(req); 443 if (error) 444 return (error); 445 } 446 cp = req->r_gss_ctx; 447 448 /* 449 * If it's a dummy context for a user that's using 450 * a fallback to sec=sys, then just return an error 451 * so rpchead can encode an RPCAUTH_UNIX cred. 452 */ 453 if (cp->gss_clnt_service == RPCSEC_GSS_SVC_SYS) { 454 /* 455 * The dummy context is valid for just 456 * GSS_CLNT_SYS_VALID seconds. If the context 457 * is older than this, mark it invalid and try 458 * again to get a real one. 459 */ 460 lck_mtx_lock(cp->gss_clnt_mtx); 461 microuptime(&now); 462 if (now.tv_sec > cp->gss_clnt_ctime + GSS_CLNT_SYS_VALID) { 463 cp->gss_clnt_flags |= GSS_CTX_INVAL; 464 lck_mtx_unlock(cp->gss_clnt_mtx); 465 nfs_gss_clnt_ctx_unref(req); 466 goto retry; 467 } 468 lck_mtx_unlock(cp->gss_clnt_mtx); 469 return (ENEEDAUTH); 470 } 471 472 /* 473 * If the context thread isn't null, then the context isn't 474 * yet complete and is for the exclusive use of the thread 475 * doing the context setup. Wait until the context thread 476 * is null. 477 */ 478 lck_mtx_lock(cp->gss_clnt_mtx); 479 if (cp->gss_clnt_thread && cp->gss_clnt_thread != current_thread()) { 480 cp->gss_clnt_flags |= GSS_NEEDCTX; 481 msleep(cp, cp->gss_clnt_mtx, slpflag | PDROP, "ctxwait", NULL); 482 slpflag &= ~PCATCH; 483 if ((error = nfs_sigintr(req->r_nmp, req, req->r_thread, 0))) 484 return (error); 485 nfs_gss_clnt_ctx_unref(req); 486 goto retry; 487 } 488 lck_mtx_unlock(cp->gss_clnt_mtx); 489 490 ki = &cp->gss_clnt_kinfo; 491 if (cp->gss_clnt_flags & GSS_CTX_COMPLETE) { 492 /* 493 * Get a sequence number for this request. 494 * Check whether the oldest request in the window is complete. 495 * If it's still pending, then wait until it's done before 496 * we allocate a new sequence number and allow this request 497 * to proceed. 498 */ 499 lck_mtx_lock(cp->gss_clnt_mtx); 500 while (win_getbit(cp->gss_clnt_seqbits, 501 ((cp->gss_clnt_seqnum - cp->gss_clnt_seqwin) + 1) % cp->gss_clnt_seqwin)) { 502 cp->gss_clnt_flags |= GSS_NEEDSEQ; 503 msleep(cp, cp->gss_clnt_mtx, slpflag | PDROP, "seqwin", NULL); 504 slpflag &= ~PCATCH; 505 if ((error = nfs_sigintr(req->r_nmp, req, req->r_thread, 0))) { 506 return (error); 507 } 508 lck_mtx_lock(cp->gss_clnt_mtx); 509 if (cp->gss_clnt_flags & GSS_CTX_INVAL) { 510 /* Renewed while while we were waiting */ 511 lck_mtx_unlock(cp->gss_clnt_mtx); 512 nfs_gss_clnt_ctx_unref(req); 513 goto retry; 514 } 515 } 516 seqnum = ++cp->gss_clnt_seqnum; 517 win_setbit(cp->gss_clnt_seqbits, seqnum % cp->gss_clnt_seqwin); 518 lck_mtx_unlock(cp->gss_clnt_mtx); 519 520 MALLOC(gsp, struct gss_seq *, sizeof(*gsp), M_TEMP, M_WAITOK|M_ZERO); 521 if (gsp == NULL) 522 return (ENOMEM); 523 gsp->gss_seqnum = seqnum; 524 SLIST_INSERT_HEAD(&req->r_gss_seqlist, gsp, gss_seqnext); 525 } 526 527 /* Insert the credential */ 528 nfsm_chain_add_32(error, nmc, RPCSEC_GSS); 529 nfsm_chain_add_32(error, nmc, 5 * NFSX_UNSIGNED + cp->gss_clnt_handle_len); 530 nfsm_chain_add_32(error, nmc, RPCSEC_GSS_VERS_1); 531 nfsm_chain_add_32(error, nmc, cp->gss_clnt_proc); 532 nfsm_chain_add_32(error, nmc, seqnum); 533 nfsm_chain_add_32(error, nmc, cp->gss_clnt_service); 534 nfsm_chain_add_32(error, nmc, cp->gss_clnt_handle_len); 535 if (cp->gss_clnt_handle_len > 0) { 536 if (cp->gss_clnt_handle == NULL) 537 return (EBADRPC); 538 nfsm_chain_add_opaque(error, nmc, cp->gss_clnt_handle, cp->gss_clnt_handle_len); 539 } 540 if (error) 541 return(error); 542 /* 543 * Now add the verifier 544 */ 545 if (cp->gss_clnt_proc == RPCSEC_GSS_INIT || 546 cp->gss_clnt_proc == RPCSEC_GSS_CONTINUE_INIT) { 547 /* 548 * If the context is still being created 549 * then use a null verifier. 550 */ 551 nfsm_chain_add_32(error, nmc, RPCAUTH_NULL); // flavor 552 nfsm_chain_add_32(error, nmc, 0); // length 553 nfsm_chain_build_done(error, nmc); 554 if (!error) 555 nfs_gss_append_chain(nmc, args); 556 return (error); 557 } 558 559 offset = recordmark ? NFSX_UNSIGNED : 0; // record mark 560 nfsm_chain_build_done(error, nmc); 561 nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), offset, 0, cksum); 562 563 toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 1, 0, cksum); 564 nfsm_chain_add_32(error, nmc, RPCSEC_GSS); // flavor 565 nfsm_chain_add_32(error, nmc, toklen); // length 566 nfsm_chain_add_opaque(error, nmc, tokbuf, toklen); 567 nfsm_chain_build_done(error, nmc); 568 if (error) 569 return (error); 570 571 /* 572 * Now we may have to compute integrity or encrypt the call args 573 * per RFC 2203 Section 5.3.2 574 */ 575 switch (cp->gss_clnt_service) { 576 case RPCSEC_GSS_SVC_NONE: 577 nfs_gss_append_chain(nmc, args); 578 break; 579 case RPCSEC_GSS_SVC_INTEGRITY: 580 len = nfs_gss_mchain_length(args); // Find args length 581 req->r_gss_arglen = len; // Stash the args len 582 len += NFSX_UNSIGNED; // Add seqnum length 583 nfsm_chain_add_32(error, nmc, len); // and insert it 584 start = nfsm_chain_offset(nmc); 585 nfsm_chain_add_32(error, nmc, seqnum); // Insert seqnum 586 req->r_gss_argoff = nfsm_chain_offset(nmc); // Offset to args 587 nfsm_chain_build_done(error, nmc); 588 if (error) 589 return (error); 590 nfs_gss_append_chain(nmc, args); // Append the args mbufs 591 592 /* Now compute a checksum over the seqnum + args */ 593 nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), start, len, cksum); 594 595 /* Insert it into a token and append to the request */ 596 toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 1, 0, cksum); 597 nfsm_chain_finish_mbuf(error, nmc); // force checksum into new mbuf 598 nfsm_chain_add_32(error, nmc, toklen); 599 nfsm_chain_add_opaque(error, nmc, tokbuf, toklen); 600 nfsm_chain_build_done(error, nmc); 601 break; 602 case RPCSEC_GSS_SVC_PRIVACY: 603 /* Prepend a new mbuf with the confounder & sequence number */ 604 nfsm_chain_build_alloc_init(error, &nmc_tmp, 3 * NFSX_UNSIGNED); 605 nfsm_chain_add_32(error, &nmc_tmp, random()); // confounder bytes 1-4 606 nfsm_chain_add_32(error, &nmc_tmp, random()); // confounder bytes 4-8 607 nfsm_chain_add_32(error, &nmc_tmp, seqnum); 608 nfsm_chain_build_done(error, &nmc_tmp); 609 if (error) 610 return (error); 611 nfs_gss_append_chain(&nmc_tmp, args); // Append the args mbufs 612 613 len = nfs_gss_mchain_length(args); // Find args length 614 len += 3 * NFSX_UNSIGNED; // add confounder & seqnum 615 req->r_gss_arglen = len; // Stash length 616 617 /* 618 * Append a pad trailer - per RFC 1964 section 1.2.2.3 619 * Since XDR data is always 32-bit aligned, it 620 * needs to be padded either by 4 bytes or 8 bytes. 621 */ 622 nfsm_chain_finish_mbuf(error, &nmc_tmp); // force padding into new mbuf 623 if (len % 8 > 0) { 624 nfsm_chain_add_32(error, &nmc_tmp, 0x04040404); 625 len += NFSX_UNSIGNED; 626 } else { 627 nfsm_chain_add_32(error, &nmc_tmp, 0x08080808); 628 nfsm_chain_add_32(error, &nmc_tmp, 0x08080808); 629 len += 2 * NFSX_UNSIGNED; 630 } 631 nfsm_chain_build_done(error, &nmc_tmp); 632 633 /* Now compute a checksum over the confounder + seqnum + args */ 634 nfs_gss_cksum_chain(ki, &nmc_tmp, ALG_WRAP(ki), 0, len, cksum); 635 636 /* Insert it into a token */ 637 toklen = nfs_gss_token_put(ki, ALG_WRAP(ki), tokbuf, 1, len, cksum); 638 nfsm_chain_add_32(error, nmc, toklen + len); // token + args length 639 nfsm_chain_add_opaque_nopad(error, nmc, tokbuf, toklen); 640 req->r_gss_argoff = nfsm_chain_offset(nmc); // Stash offset 641 nfsm_chain_build_done(error, nmc); 642 if (error) 643 return (error); 644 nfs_gss_append_chain(nmc, nmc_tmp.nmc_mhead); // Append the args mbufs 645 646 /* Finally, encrypt the args */ 647 nfs_gss_encrypt_chain(ki, &nmc_tmp, 0, len, DES_ENCRYPT); 648 649 /* Add null XDR pad if the ASN.1 token misaligned the data */ 650 pad = nfsm_pad(toklen + len); 651 if (pad > 0) { 652 nfsm_chain_add_opaque_nopad(error, nmc, iv0, pad); 653 nfsm_chain_build_done(error, nmc); 654 } 655 break; 656 } 657 658 return (error); 659} 660 661/* 662 * When receiving a reply, the client checks the verifier 663 * returned by the server. Check that the verifier is the 664 * correct type, then extract the sequence number checksum 665 * from the token in the credential and compare it with a 666 * computed checksum of the sequence number in the request 667 * that was sent. 668 */ 669int 670nfs_gss_clnt_verf_get( 671 struct nfsreq *req, 672 struct nfsm_chain *nmc, 673 uint32_t verftype, 674 uint32_t verflen, 675 uint32_t *accepted_statusp) 676{ 677 u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)]; 678 u_char cksum1[MAX_DIGEST], cksum2[MAX_DIGEST]; 679 uint32_t seqnum = 0; 680 struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx; 681 struct nfsm_chain nmc_tmp; 682 struct gss_seq *gsp; 683 uint32_t reslen, start, cksumlen, toklen; 684 int error = 0; 685 gss_key_info *ki = &cp->gss_clnt_kinfo; 686 687 reslen = cksumlen = 0; 688 *accepted_statusp = 0; 689 690 if (cp == NULL) 691 return (NFSERR_EAUTH); 692 /* 693 * If it's not an RPCSEC_GSS verifier, then it has to 694 * be a null verifier that resulted from either 695 * a CONTINUE_NEEDED reply during context setup or 696 * from the reply to an AUTH_UNIX call from a dummy 697 * context that resulted from a fallback to sec=sys. 698 */ 699 if (verftype != RPCSEC_GSS) { 700 if (verftype != RPCAUTH_NULL) 701 return (NFSERR_EAUTH); 702 if (cp->gss_clnt_flags & GSS_CTX_COMPLETE && 703 cp->gss_clnt_service != RPCSEC_GSS_SVC_SYS) 704 return (NFSERR_EAUTH); 705 if (verflen > 0) 706 nfsm_chain_adv(error, nmc, nfsm_rndup(verflen)); 707 nfsm_chain_get_32(error, nmc, *accepted_statusp); 708 return (error); 709 } 710 711 /* 712 * If we received an RPCSEC_GSS verifier but the 713 * context isn't yet complete, then it must be 714 * the context complete message from the server. 715 * The verifier will contain an encrypted checksum 716 * of the window but we don't have the session key 717 * yet so we can't decrypt it. Stash the verifier 718 * and check it later in nfs_gss_clnt_ctx_init() when 719 * the context is complete. 720 */ 721 if (!(cp->gss_clnt_flags & GSS_CTX_COMPLETE)) { 722 MALLOC(cp->gss_clnt_verf, u_char *, verflen, M_TEMP, M_WAITOK|M_ZERO); 723 if (cp->gss_clnt_verf == NULL) 724 return (ENOMEM); 725 nfsm_chain_get_opaque(error, nmc, verflen, cp->gss_clnt_verf); 726 nfsm_chain_get_32(error, nmc, *accepted_statusp); 727 return (error); 728 } 729 730 if (verflen != KRB5_SZ_TOKEN(ki->hash_len)) 731 return (NFSERR_EAUTH); 732 733 /* 734 * Get the 8 octet sequence number 735 * checksum out of the verifier token. 736 */ 737 nfsm_chain_get_opaque(error, nmc, verflen, tokbuf); 738 if (error) 739 goto nfsmout; 740 error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 0, NULL, cksum1); 741 if (error) 742 goto nfsmout; 743 744 /* 745 * Search the request sequence numbers for this reply, starting 746 * with the most recent, looking for a checksum that matches 747 * the one in the verifier returned by the server. 748 */ 749 SLIST_FOREACH(gsp, &req->r_gss_seqlist, gss_seqnext) { 750 nfs_gss_cksum_rep(ki, gsp->gss_seqnum, cksum2); 751 if (bcmp(cksum1, cksum2, HASHLEN(ki)) == 0) 752 break; 753 } 754 if (gsp == NULL) 755 return (NFSERR_EAUTH); 756 757 /* 758 * Get the RPC accepted status 759 */ 760 nfsm_chain_get_32(error, nmc, *accepted_statusp); 761 if (*accepted_statusp != RPC_SUCCESS) 762 return (0); 763 764 /* 765 * Now we may have to check integrity or decrypt the results 766 * per RFC 2203 Section 5.3.2 767 */ 768 switch (cp->gss_clnt_service) { 769 case RPCSEC_GSS_SVC_NONE: 770 /* nothing to do */ 771 break; 772 case RPCSEC_GSS_SVC_INTEGRITY: 773 /* 774 * Here's what we expect in the integrity results: 775 * 776 * - length of seq num + results (4 bytes) 777 * - sequence number (4 bytes) 778 * - results (variable bytes) 779 * - length of checksum token (37) 780 * - checksum of seqnum + results (37 bytes) 781 */ 782 nfsm_chain_get_32(error, nmc, reslen); // length of results 783 if (reslen > NFS_MAXPACKET) { 784 error = EBADRPC; 785 goto nfsmout; 786 } 787 788 /* Compute a checksum over the sequence number + results */ 789 start = nfsm_chain_offset(nmc); 790 nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), start, reslen, cksum1); 791 792 /* 793 * Get the sequence number prepended to the results 794 * and compare it against the list in the request. 795 */ 796 nfsm_chain_get_32(error, nmc, seqnum); 797 SLIST_FOREACH(gsp, &req->r_gss_seqlist, gss_seqnext) { 798 if (seqnum == gsp->gss_seqnum) 799 break; 800 } 801 if (gsp == NULL) { 802 error = EBADRPC; 803 goto nfsmout; 804 } 805 806 /* 807 * Advance to the end of the results and 808 * fetch the checksum computed by the server. 809 */ 810 nmc_tmp = *nmc; 811 reslen -= NFSX_UNSIGNED; // already skipped seqnum 812 nfsm_chain_adv(error, &nmc_tmp, reslen); // skip over the results 813 nfsm_chain_get_32(error, &nmc_tmp, cksumlen); // length of checksum 814 if (cksumlen != KRB5_SZ_TOKEN(ki->hash_len)) { 815 error = EBADRPC; 816 goto nfsmout; 817 } 818 nfsm_chain_get_opaque(error, &nmc_tmp, cksumlen, tokbuf); 819 if (error) 820 goto nfsmout; 821 error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 0, NULL, cksum2); 822 if (error) 823 goto nfsmout; 824 825 /* Verify that the checksums are the same */ 826 if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) { 827 error = EBADRPC; 828 goto nfsmout; 829 } 830 break; 831 case RPCSEC_GSS_SVC_PRIVACY: 832 /* 833 * Here's what we expect in the privacy results: 834 * 835 * - length of confounder + seq num + token + results 836 * - wrap token (37-40 bytes) 837 * - confounder (8 bytes) 838 * - sequence number (4 bytes) 839 * - results (encrypted) 840 */ 841 nfsm_chain_get_32(error, nmc, reslen); // length of results 842 if (reslen > NFS_MAXPACKET) { 843 error = EBADRPC; 844 goto nfsmout; 845 } 846 847 /* Get the token that prepends the encrypted results */ 848 nfsm_chain_get_opaque(error, nmc, KRB5_SZ_TOKMAX(ki->hash_len), tokbuf); 849 if (error) 850 goto nfsmout; 851 error = nfs_gss_token_get(ki, ALG_WRAP(ki), tokbuf, 0, 852 &toklen, cksum1); 853 if (error) 854 goto nfsmout; 855 nfsm_chain_reverse(nmc, nfsm_pad(toklen)); 856 reslen -= toklen; // size of confounder + seqnum + results 857 858 /* decrypt the confounder + sequence number + results */ 859 start = nfsm_chain_offset(nmc); 860 nfs_gss_encrypt_chain(ki, nmc, start, reslen, DES_DECRYPT); 861 862 /* Compute a checksum over the confounder + sequence number + results */ 863 nfs_gss_cksum_chain(ki, nmc, ALG_WRAP(ki), start, reslen, cksum2); 864 865 /* Verify that the checksums are the same */ 866 if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) { 867 error = EBADRPC; 868 goto nfsmout; 869 } 870 871 nfsm_chain_adv(error, nmc, 8); // skip over the confounder 872 873 /* 874 * Get the sequence number prepended to the results 875 * and compare it against the list in the request. 876 */ 877 nfsm_chain_get_32(error, nmc, seqnum); 878 SLIST_FOREACH(gsp, &req->r_gss_seqlist, gss_seqnext) { 879 if (seqnum == gsp->gss_seqnum) 880 break; 881 } 882 if (gsp == NULL) { 883 error = EBADRPC; 884 goto nfsmout; 885 } 886 887 break; 888 } 889nfsmout: 890 return (error); 891} 892 893/* 894 * An RPCSEC_GSS request with no integrity or privacy consists 895 * of just the header mbufs followed by the arg mbufs. 896 * 897 * However, integrity or privacy both trailer mbufs to the args, 898 * which means we have to do some work to restore the arg mbuf 899 * chain to its previous state in case we need to retransmit. 900 * 901 * The location and length of the args is marked by two fields 902 * in the request structure: r_gss_argoff and r_gss_arglen, 903 * which are stashed when the NFS request is built. 904 */ 905int 906nfs_gss_clnt_args_restore(struct nfsreq *req) 907{ 908 struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx; 909 struct nfsm_chain mchain, *nmc = &mchain; 910 int len, error = 0; 911 912 if (cp == NULL) 913 return (NFSERR_EAUTH); 914 915 if ((cp->gss_clnt_flags & GSS_CTX_COMPLETE) == 0) 916 return (ENEEDAUTH); 917 918 nfsm_chain_dissect_init(error, nmc, req->r_mhead); // start at RPC header 919 nfsm_chain_adv(error, nmc, req->r_gss_argoff); // advance to args 920 if (error) 921 return (error); 922 923 switch (cp->gss_clnt_service) { 924 case RPCSEC_GSS_SVC_NONE: 925 /* nothing to do */ 926 break; 927 case RPCSEC_GSS_SVC_INTEGRITY: 928 /* 929 * All we have to do here is remove the appended checksum mbufs. 930 * We know that the checksum starts in a new mbuf beyond the end 931 * of the args. 932 */ 933 nfsm_chain_adv(error, nmc, req->r_gss_arglen); // adv to last args mbuf 934 if (error) 935 return (error); 936 937 mbuf_freem(mbuf_next(nmc->nmc_mcur)); // free the cksum mbuf 938 error = mbuf_setnext(nmc->nmc_mcur, NULL); 939 break; 940 case RPCSEC_GSS_SVC_PRIVACY: 941 /* 942 * The args are encrypted along with prepended confounders and seqnum. 943 * First we decrypt, the confounder, seqnum and args then skip to the 944 * final mbuf of the args. 945 * The arglen includes 8 bytes of confounder and 4 bytes of seqnum. 946 * Finally, we remove between 4 and 8 bytes of encryption padding 947 * as well as any alignment padding in the trailing mbuf. 948 */ 949 len = req->r_gss_arglen; 950 len += len % 8 > 0 ? 4 : 8; // add DES padding length 951 nfs_gss_encrypt_chain(&cp->gss_clnt_kinfo, nmc, 952 req->r_gss_argoff, len, DES_DECRYPT); 953 nfsm_chain_adv(error, nmc, req->r_gss_arglen); 954 if (error) 955 return (error); 956 mbuf_freem(mbuf_next(nmc->nmc_mcur)); // free the pad mbuf 957 error = mbuf_setnext(nmc->nmc_mcur, NULL); 958 break; 959 } 960 961 return (error); 962} 963 964/* 965 * This function sets up a new context on the client. 966 * Context setup alternates upcalls to the gssd with NFS nullproc calls 967 * to the server. Each of these calls exchanges an opaque token, obtained 968 * via the gssd's calls into the GSS-API on either the client or the server. 969 * This cycle of calls ends when the client's upcall to the gssd and the 970 * server's response both return GSS_S_COMPLETE. At this point, the client 971 * should have its session key and a handle that it can use to refer to its 972 * new context on the server. 973 */ 974static int 975nfs_gss_clnt_ctx_init(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp) 976{ 977 struct nfsmount *nmp = req->r_nmp; 978 int client_complete = 0; 979 int server_complete = 0; 980 u_char cksum1[MAX_DIGEST], cksum2[MAX_DIGEST]; 981 int error = 0; 982 struct timeval now; 983 gss_key_info *ki = &cp->gss_clnt_kinfo; 984 985 /* Initialize a new client context */ 986 987 cp->gss_clnt_svcname = nfs_gss_clnt_svcname(nmp); 988 if (cp->gss_clnt_svcname == NULL) { 989 error = NFSERR_EAUTH; 990 goto nfsmout; 991 } 992 993 cp->gss_clnt_proc = RPCSEC_GSS_INIT; 994 995 cp->gss_clnt_service = 996 req->r_auth == RPCAUTH_KRB5 ? RPCSEC_GSS_SVC_NONE : 997 req->r_auth == RPCAUTH_KRB5I ? RPCSEC_GSS_SVC_INTEGRITY : 998 req->r_auth == RPCAUTH_KRB5P ? RPCSEC_GSS_SVC_PRIVACY : 0; 999 1000 cp->gss_clnt_gssd_flags = (nfs_single_des ? GSSD_NFS_1DES : 0); 1001 /* 1002 * Now loop around alternating gss_init_sec_context and 1003 * gss_accept_sec_context upcalls to the gssd on the client 1004 * and server side until the context is complete - or fails. 1005 */ 1006 for (;;) { 1007 1008retry: 1009 /* Upcall to the gss_init_sec_context in the gssd */ 1010 error = nfs_gss_clnt_gssd_upcall(req, cp); 1011 if (error) 1012 goto nfsmout; 1013 1014 if (cp->gss_clnt_major == GSS_S_COMPLETE) { 1015 client_complete = 1; 1016 if (server_complete) 1017 break; 1018 } else if (cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) { 1019 error = NFSERR_EAUTH; 1020 goto nfsmout; 1021 } 1022 1023 /* 1024 * Pass the token to the server. 1025 */ 1026 error = nfs_gss_clnt_ctx_callserver(req, cp); 1027 if (error) { 1028 if (cp->gss_clnt_proc == RPCSEC_GSS_INIT && 1029 (cp->gss_clnt_gssd_flags & (GSSD_RESTART | GSSD_NFS_1DES)) == 0) { 1030 cp->gss_clnt_gssd_flags = (GSSD_RESTART | GSSD_NFS_1DES); 1031 if (cp->gss_clnt_token) 1032 FREE(cp->gss_clnt_token, M_TEMP); 1033 cp->gss_clnt_token = NULL; 1034 cp->gss_clnt_tokenlen = 0; 1035 goto retry; 1036 } 1037 // Reset flags, if error = ENEEDAUTH we will try 3des again 1038 cp->gss_clnt_gssd_flags = 0; 1039 goto nfsmout; 1040 } 1041 if (cp->gss_clnt_major == GSS_S_COMPLETE) { 1042 server_complete = 1; 1043 if (client_complete) 1044 break; 1045 } else if (cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) { 1046 error = NFSERR_EAUTH; 1047 goto nfsmout; 1048 } 1049 1050 cp->gss_clnt_proc = RPCSEC_GSS_CONTINUE_INIT; 1051 } 1052 1053 /* 1054 * The context is apparently established successfully 1055 */ 1056 lck_mtx_lock(cp->gss_clnt_mtx); 1057 cp->gss_clnt_flags |= GSS_CTX_COMPLETE; 1058 lck_mtx_unlock(cp->gss_clnt_mtx); 1059 cp->gss_clnt_proc = RPCSEC_GSS_DATA; 1060 microuptime(&now); 1061 cp->gss_clnt_ctime = now.tv_sec; // time stamp 1062 1063 1064 /* 1065 * Compute checksum of the server's window 1066 */ 1067 nfs_gss_cksum_rep(ki, cp->gss_clnt_seqwin, cksum1); 1068 1069 /* 1070 * and see if it matches the one in the 1071 * verifier the server returned. 1072 */ 1073 error = nfs_gss_token_get(ki, ALG_MIC(ki), cp->gss_clnt_verf, 0, 1074 NULL, cksum2); 1075 FREE(cp->gss_clnt_verf, M_TEMP); 1076 cp->gss_clnt_verf = NULL; 1077 1078 if (error || bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) { 1079 error = NFSERR_EAUTH; 1080 goto nfsmout; 1081 } 1082 1083 /* 1084 * Set an initial sequence number somewhat randomized. 1085 * Start small so we don't overflow GSS_MAXSEQ too quickly. 1086 * Add the size of the sequence window so seqbits arithmetic 1087 * doesn't go negative. 1088 */ 1089 cp->gss_clnt_seqnum = (random() & 0xffff) + cp->gss_clnt_seqwin; 1090 1091 /* 1092 * Allocate a bitmap to keep track of which requests 1093 * are pending within the sequence number window. 1094 */ 1095 MALLOC(cp->gss_clnt_seqbits, uint32_t *, 1096 nfsm_rndup((cp->gss_clnt_seqwin + 7) / 8), M_TEMP, M_WAITOK|M_ZERO); 1097 if (cp->gss_clnt_seqbits == NULL) 1098 error = NFSERR_EAUTH; 1099nfsmout: 1100 /* 1101 * If the error is ENEEDAUTH we're not done, so no need 1102 * to wake up other threads again. This thread will retry in 1103 * the find or renew routines. 1104 */ 1105 if (error == ENEEDAUTH) 1106 return (error); 1107 1108 /* 1109 * If there's an error, just mark it as invalid. 1110 * It will be removed when the reference count 1111 * drops to zero. 1112 */ 1113 lck_mtx_lock(cp->gss_clnt_mtx); 1114 if (error) 1115 cp->gss_clnt_flags |= GSS_CTX_INVAL; 1116 1117 /* 1118 * Wake any threads waiting to use the context 1119 */ 1120 cp->gss_clnt_thread = NULL; 1121 if (cp->gss_clnt_flags & GSS_NEEDCTX) { 1122 cp->gss_clnt_flags &= ~GSS_NEEDCTX; 1123 wakeup(cp); 1124 } 1125 lck_mtx_unlock(cp->gss_clnt_mtx); 1126 1127 return (error); 1128} 1129 1130/* 1131 * This function calls nfs_gss_clnt_ctx_init() to set up a new context. 1132 * But if there's a failure in trying to establish the context it keeps 1133 * retrying at progressively longer intervals in case the failure is 1134 * due to some transient condition. For instance, the server might be 1135 * failing the context setup because directory services is not coming 1136 * up in a timely fashion. 1137 */ 1138static int 1139nfs_gss_clnt_ctx_init_retry(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp) 1140{ 1141 struct nfsmount *nmp = req->r_nmp; 1142 struct timeval now; 1143 time_t waituntil; 1144 int error, slpflag; 1145 int retries = 0; 1146 int timeo = NFS_TRYLATERDEL; 1147 1148 if (nmp == NULL) { 1149 error = ENXIO; 1150 goto bad; 1151 } 1152 1153 /* For an "intr" mount allow a signal to interrupt the retries */ 1154 slpflag = (NMFLAG(nmp, INTR) && !(req->r_flags & R_NOINTR)) ? PCATCH : 0; 1155 1156 while ((error = nfs_gss_clnt_ctx_init(req, cp)) == ENEEDAUTH) { 1157 microuptime(&now); 1158 waituntil = now.tv_sec + timeo; 1159 while (now.tv_sec < waituntil) { 1160 tsleep(&lbolt, PSOCK | slpflag, "nfs_gss_clnt_ctx_init_retry", 0); 1161 slpflag = 0; 1162 error = nfs_sigintr(req->r_nmp, req, current_thread(), 0); 1163 if (error) 1164 goto bad; 1165 microuptime(&now); 1166 } 1167 1168 retries++; 1169 /* If it's a soft mount just give up after a while */ 1170 if (NMFLAG(nmp, SOFT) && (retries > nmp->nm_retry)) { 1171 error = ETIMEDOUT; 1172 goto bad; 1173 } 1174 timeo *= 2; 1175 if (timeo > 60) 1176 timeo = 60; 1177 } 1178 1179 if (error == 0) 1180 return 0; // success 1181bad: 1182 /* 1183 * Give up on this context 1184 */ 1185 lck_mtx_lock(cp->gss_clnt_mtx); 1186 cp->gss_clnt_flags |= GSS_CTX_INVAL; 1187 1188 /* 1189 * Wake any threads waiting to use the context 1190 */ 1191 cp->gss_clnt_thread = NULL; 1192 if (cp->gss_clnt_flags & GSS_NEEDCTX) { 1193 cp->gss_clnt_flags &= ~GSS_NEEDCTX; 1194 wakeup(cp); 1195 } 1196 lck_mtx_unlock(cp->gss_clnt_mtx); 1197 1198 return error; 1199} 1200 1201/* 1202 * Call the NFS server using a null procedure for context setup. 1203 * Even though it's a null procedure and nominally has no arguments 1204 * RFC 2203 requires that the GSS-API token be passed as an argument 1205 * and received as a reply. 1206 */ 1207static int 1208nfs_gss_clnt_ctx_callserver(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp) 1209{ 1210 struct nfsm_chain nmreq, nmrep; 1211 int error = 0, status; 1212 int sz; 1213 1214 if (!req->r_nmp) 1215 return (ENXIO); 1216 nfsm_chain_null(&nmreq); 1217 nfsm_chain_null(&nmrep); 1218 sz = NFSX_UNSIGNED + nfsm_rndup(cp->gss_clnt_tokenlen); 1219 nfsm_chain_build_alloc_init(error, &nmreq, sz); 1220 nfsm_chain_add_32(error, &nmreq, cp->gss_clnt_tokenlen); 1221 if (cp->gss_clnt_tokenlen > 0) 1222 nfsm_chain_add_opaque(error, &nmreq, cp->gss_clnt_token, cp->gss_clnt_tokenlen); 1223 nfsm_chain_build_done(error, &nmreq); 1224 if (error) 1225 goto nfsmout; 1226 1227 /* Call the server */ 1228 error = nfs_request_gss(req->r_nmp->nm_mountp, &nmreq, req->r_thread, req->r_cred, 1229 (req->r_flags & R_OPTMASK), cp, &nmrep, &status); 1230 if (cp->gss_clnt_token != NULL) { 1231 FREE(cp->gss_clnt_token, M_TEMP); 1232 cp->gss_clnt_token = NULL; 1233 } 1234 if (!error) 1235 error = status; 1236 if (error) 1237 goto nfsmout; 1238 1239 /* Get the server's reply */ 1240 1241 nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_handle_len); 1242 if (cp->gss_clnt_handle != NULL) { 1243 FREE(cp->gss_clnt_handle, M_TEMP); 1244 cp->gss_clnt_handle = NULL; 1245 } 1246 if (cp->gss_clnt_handle_len > 0) { 1247 MALLOC(cp->gss_clnt_handle, u_char *, cp->gss_clnt_handle_len, M_TEMP, M_WAITOK); 1248 if (cp->gss_clnt_handle == NULL) { 1249 error = ENOMEM; 1250 goto nfsmout; 1251 } 1252 nfsm_chain_get_opaque(error, &nmrep, cp->gss_clnt_handle_len, cp->gss_clnt_handle); 1253 } 1254 nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_major); 1255 nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_minor); 1256 nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_seqwin); 1257 nfsm_chain_get_32(error, &nmrep, cp->gss_clnt_tokenlen); 1258 if (error) 1259 goto nfsmout; 1260 if (cp->gss_clnt_tokenlen > 0) { 1261 MALLOC(cp->gss_clnt_token, u_char *, cp->gss_clnt_tokenlen, M_TEMP, M_WAITOK); 1262 if (cp->gss_clnt_token == NULL) { 1263 error = ENOMEM; 1264 goto nfsmout; 1265 } 1266 nfsm_chain_get_opaque(error, &nmrep, cp->gss_clnt_tokenlen, cp->gss_clnt_token); 1267 } 1268 1269 /* 1270 * Make sure any unusual errors are expanded and logged by gssd 1271 */ 1272 if (cp->gss_clnt_major != GSS_S_COMPLETE && 1273 cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) { 1274 char who[] = "server"; 1275 char unknown[] = "<unknown>"; 1276 1277 (void) mach_gss_log_error( 1278 cp->gss_clnt_mport, 1279 !req->r_nmp ? unknown : 1280 vfs_statfs(req->r_nmp->nm_mountp)->f_mntfromname, 1281 cp->gss_clnt_uid, 1282 who, 1283 cp->gss_clnt_major, 1284 cp->gss_clnt_minor); 1285 } 1286 1287nfsmout: 1288 nfsm_chain_cleanup(&nmreq); 1289 nfsm_chain_cleanup(&nmrep); 1290 1291 return (error); 1292} 1293 1294/* 1295 * Ugly hack to get the service principal from the f_mntfromname field in 1296 * the statfs struct. We assume a format of server:path. We don't currently 1297 * support url's or other bizarre formats like path@server. A better solution 1298 * here might be to allow passing the service principal down in the mount args. 1299 * For kerberos we just use the default realm. 1300 */ 1301static char * 1302nfs_gss_clnt_svcname(struct nfsmount *nmp) 1303{ 1304 char *svcname, *d, *mntfromhere; 1305 int len; 1306 1307 if (!nmp) 1308 return (NULL); 1309 mntfromhere = &vfs_statfs(nmp->nm_mountp)->f_mntfromname[0]; 1310 len = strlen(mntfromhere) + 5; /* "nfs/" plus null */ 1311 MALLOC(svcname, char *, len, M_TEMP, M_NOWAIT); 1312 if (svcname == NULL) 1313 return (NULL); 1314 strlcpy(svcname, "nfs/", len); 1315 strlcat(svcname, mntfromhere, len); 1316 d = strchr(svcname, ':'); 1317 if (d) 1318 *d = '\0'; 1319 1320 return (svcname); 1321} 1322 1323/* 1324 * Get a mach port to talk to gssd. 1325 * gssd lives in the root bootstrap, so we call gssd's lookup routine 1326 * to get a send right to talk to a new gssd instance that launchd has launched 1327 * based on the cred's uid and audit session id. 1328 */ 1329#define kauth_cred_getasid(cred) ((cred)->cr_audit.as_aia_p->ai_asid) 1330#define kauth_cred_getauid(cred) ((cred)->cr_audit.as_aia_p->ai_auid) 1331 1332static mach_port_t 1333nfs_gss_clnt_get_upcall_port(kauth_cred_t credp) 1334{ 1335 mach_port_t gssd_host_port, uc_port = IPC_PORT_NULL; 1336 kern_return_t kr; 1337 au_asid_t asid; 1338 uid_t uid; 1339 1340 kr = host_get_gssd_port(host_priv_self(), &gssd_host_port); 1341 if (kr != KERN_SUCCESS) { 1342 printf("nfs_gss_get_upcall_port: can't get gssd port, status %x (%d)\n", kr, kr); 1343 return (IPC_PORT_NULL); 1344 } 1345 if (!IPC_PORT_VALID(gssd_host_port)) { 1346 printf("nfs_gss_get_upcall_port: gssd port not valid\n"); 1347 return (IPC_PORT_NULL); 1348 } 1349 1350 asid = kauth_cred_getasid(credp); 1351 uid = kauth_cred_getauid(credp); 1352 if (uid == AU_DEFAUDITID) 1353 uid = kauth_cred_getuid(credp); 1354 kr = mach_gss_lookup(gssd_host_port, uid, asid, &uc_port); 1355 if (kr != KERN_SUCCESS) 1356 printf("nfs_gss_clnt_get_upcall_port: mach_gssd_lookup failed: status %x (%d)\n", kr, kr); 1357 1358 return (uc_port); 1359} 1360 1361/* 1362 * Make an upcall to the gssd using Mach RPC 1363 * The upcall is made using a host special port. 1364 * This allows launchd to fire up the gssd in the 1365 * user's session. This is important, since gssd 1366 * must have access to the user's credential cache. 1367 */ 1368static int 1369nfs_gss_clnt_gssd_upcall(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp) 1370{ 1371 kern_return_t kr; 1372 gssd_byte_buffer okey = NULL; 1373 uint32_t skeylen = 0; 1374 int retry_cnt = 0; 1375 vm_map_copy_t itoken = NULL; 1376 gssd_byte_buffer otoken = NULL; 1377 mach_msg_type_number_t otokenlen; 1378 int error = 0; 1379 char uprinc[1]; 1380 uint32_t ret_flags; 1381 1382 /* 1383 * NFS currently only supports default principals or 1384 * principals based on the uid of the caller. 1385 * 1386 * N.B. Note we define a one character array for the principal 1387 * so that we can hold an empty string required by mach, since 1388 * the kernel is being compiled with -Wwrite-strings. 1389 */ 1390 uprinc[0] = '\0'; 1391 if (!IPC_PORT_VALID(cp->gss_clnt_mport)) { 1392 cp->gss_clnt_mport = nfs_gss_clnt_get_upcall_port(req->r_cred); 1393 if (cp->gss_clnt_mport == IPC_PORT_NULL) 1394 goto out; 1395 } 1396 1397 if (cp->gss_clnt_tokenlen > 0) 1398 nfs_gss_mach_alloc_buffer(cp->gss_clnt_token, cp->gss_clnt_tokenlen, &itoken); 1399 1400retry: 1401 kr = mach_gss_init_sec_context( 1402 cp->gss_clnt_mport, 1403 GSSD_KRB5_MECH, 1404 (gssd_byte_buffer) itoken, (mach_msg_type_number_t) cp->gss_clnt_tokenlen, 1405 cp->gss_clnt_uid, 1406 uprinc, 1407 cp->gss_clnt_svcname, 1408 GSSD_MUTUAL_FLAG, 1409 cp->gss_clnt_gssd_flags, 1410 &cp->gss_clnt_context, 1411 &cp->gss_clnt_cred_handle, 1412 &ret_flags, 1413 &okey, (mach_msg_type_number_t *) &skeylen, 1414 &otoken, &otokenlen, 1415 &cp->gss_clnt_major, 1416 &cp->gss_clnt_minor); 1417 1418 cp->gss_clnt_gssd_flags &= ~GSSD_RESTART; 1419 1420 if (kr != KERN_SUCCESS) { 1421 printf("nfs_gss_clnt_gssd_upcall: mach_gss_init_sec_context failed: %x (%d)\n", kr, kr); 1422 if (kr == MIG_SERVER_DIED && cp->gss_clnt_cred_handle == 0 && 1423 retry_cnt++ < NFS_GSS_MACH_MAX_RETRIES) { 1424 if (cp->gss_clnt_tokenlen > 0) 1425 nfs_gss_mach_alloc_buffer(cp->gss_clnt_token, cp->gss_clnt_tokenlen, &itoken); 1426 goto retry; 1427 } 1428 1429 host_release_special_port(cp->gss_clnt_mport); 1430 cp->gss_clnt_mport = IPC_PORT_NULL; 1431 goto out; 1432 } 1433 1434 /* 1435 * Make sure any unusual errors are expanded and logged by gssd 1436 */ 1437 if (cp->gss_clnt_major != GSS_S_COMPLETE && 1438 cp->gss_clnt_major != GSS_S_CONTINUE_NEEDED) { 1439 char who[] = "client"; 1440 char unknown[] = "<unknown>"; 1441 1442 (void) mach_gss_log_error( 1443 cp->gss_clnt_mport, 1444 !req->r_nmp ? unknown : 1445 vfs_statfs(req->r_nmp->nm_mountp)->f_mntfromname, 1446 cp->gss_clnt_uid, 1447 who, 1448 cp->gss_clnt_major, 1449 cp->gss_clnt_minor); 1450 } 1451 1452 if (skeylen > 0) { 1453 if (skeylen != SKEYLEN && skeylen != SKEYLEN3) { 1454 printf("nfs_gss_clnt_gssd_upcall: bad key length (%d)\n", skeylen); 1455 vm_map_copy_discard((vm_map_copy_t) okey); 1456 vm_map_copy_discard((vm_map_copy_t) otoken); 1457 goto out; 1458 } 1459 error = nfs_gss_mach_vmcopyout((vm_map_copy_t) okey, skeylen, 1460 cp->gss_clnt_kinfo.skey); 1461 if (error) { 1462 vm_map_copy_discard((vm_map_copy_t) otoken); 1463 goto out; 1464 } 1465 1466 error = gss_key_init(&cp->gss_clnt_kinfo, skeylen); 1467 if (error) 1468 goto out; 1469 } 1470 1471 /* Free context token used as input */ 1472 if (cp->gss_clnt_token) 1473 FREE(cp->gss_clnt_token, M_TEMP); 1474 cp->gss_clnt_token = NULL; 1475 cp->gss_clnt_tokenlen = 0; 1476 1477 if (otokenlen > 0) { 1478 /* Set context token to gss output token */ 1479 MALLOC(cp->gss_clnt_token, u_char *, otokenlen, M_TEMP, M_WAITOK); 1480 if (cp->gss_clnt_token == NULL) { 1481 printf("nfs_gss_clnt_gssd_upcall: could not allocate %d bytes\n", otokenlen); 1482 vm_map_copy_discard((vm_map_copy_t) otoken); 1483 return (ENOMEM); 1484 } 1485 error = nfs_gss_mach_vmcopyout((vm_map_copy_t) otoken, otokenlen, cp->gss_clnt_token); 1486 if (error) { 1487 FREE(cp->gss_clnt_token, M_TEMP); 1488 cp->gss_clnt_token = NULL; 1489 return (NFSERR_EAUTH); 1490 } 1491 cp->gss_clnt_tokenlen = otokenlen; 1492 } 1493 1494 return (0); 1495 1496out: 1497 if (cp->gss_clnt_token) 1498 FREE(cp->gss_clnt_token, M_TEMP); 1499 cp->gss_clnt_token = NULL; 1500 cp->gss_clnt_tokenlen = 0; 1501 1502 return (NFSERR_EAUTH); 1503} 1504 1505/* 1506 * Invoked at the completion of an RPC call that uses an RPCSEC_GSS 1507 * credential. The sequence number window that the server returns 1508 * at context setup indicates the maximum number of client calls that 1509 * can be outstanding on a context. The client maintains a bitmap that 1510 * represents the server's window. Each pending request has a bit set 1511 * in the window bitmap. When a reply comes in or times out, we reset 1512 * the bit in the bitmap and if there are any other threads waiting for 1513 * a context slot we notify the waiting thread(s). 1514 * 1515 * Note that if a request is retransmitted, it will have a single XID 1516 * but it may be associated with multiple sequence numbers. So we 1517 * may have to reset multiple sequence number bits in the window bitmap. 1518 */ 1519void 1520nfs_gss_clnt_rpcdone(struct nfsreq *req) 1521{ 1522 struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx; 1523 struct gss_seq *gsp, *ngsp; 1524 int i = 0; 1525 1526 if (cp == NULL || !(cp->gss_clnt_flags & GSS_CTX_COMPLETE)) 1527 return; // no context - don't bother 1528 /* 1529 * Reset the bit for this request in the 1530 * sequence number window to indicate it's done. 1531 * We do this even if the request timed out. 1532 */ 1533 lck_mtx_lock(cp->gss_clnt_mtx); 1534 gsp = SLIST_FIRST(&req->r_gss_seqlist); 1535 if (gsp && gsp->gss_seqnum > (cp->gss_clnt_seqnum - cp->gss_clnt_seqwin)) 1536 win_resetbit(cp->gss_clnt_seqbits, 1537 gsp->gss_seqnum % cp->gss_clnt_seqwin); 1538 1539 /* 1540 * Limit the seqnum list to GSS_CLNT_SEQLISTMAX entries 1541 */ 1542 SLIST_FOREACH_SAFE(gsp, &req->r_gss_seqlist, gss_seqnext, ngsp) { 1543 if (++i > GSS_CLNT_SEQLISTMAX) { 1544 SLIST_REMOVE(&req->r_gss_seqlist, gsp, gss_seq, gss_seqnext); 1545 FREE(gsp, M_TEMP); 1546 } 1547 } 1548 1549 /* 1550 * If there's a thread waiting for 1551 * the window to advance, wake it up. 1552 */ 1553 if (cp->gss_clnt_flags & GSS_NEEDSEQ) { 1554 cp->gss_clnt_flags &= ~GSS_NEEDSEQ; 1555 wakeup(cp); 1556 } 1557 lck_mtx_unlock(cp->gss_clnt_mtx); 1558} 1559 1560/* 1561 * Create a reference to a context from a request 1562 * and bump the reference count 1563 */ 1564void 1565nfs_gss_clnt_ctx_ref(struct nfsreq *req, struct nfs_gss_clnt_ctx *cp) 1566{ 1567 req->r_gss_ctx = cp; 1568 1569 lck_mtx_lock(cp->gss_clnt_mtx); 1570 cp->gss_clnt_refcnt++; 1571 lck_mtx_unlock(cp->gss_clnt_mtx); 1572} 1573 1574/* 1575 * Remove a context reference from a request 1576 * If the reference count drops to zero, and the 1577 * context is invalid, destroy the context 1578 */ 1579void 1580nfs_gss_clnt_ctx_unref(struct nfsreq *req) 1581{ 1582 struct nfsmount *nmp = req->r_nmp; 1583 struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx; 1584 1585 if (cp == NULL) 1586 return; 1587 1588 req->r_gss_ctx = NULL; 1589 1590 lck_mtx_lock(cp->gss_clnt_mtx); 1591 if (--cp->gss_clnt_refcnt == 0 1592 && cp->gss_clnt_flags & GSS_CTX_INVAL) { 1593 lck_mtx_unlock(cp->gss_clnt_mtx); 1594 1595 if (nmp) 1596 lck_mtx_lock(&nmp->nm_lock); 1597 nfs_gss_clnt_ctx_remove(nmp, cp); 1598 if (nmp) 1599 lck_mtx_unlock(&nmp->nm_lock); 1600 1601 return; 1602 } 1603 lck_mtx_unlock(cp->gss_clnt_mtx); 1604} 1605 1606/* 1607 * Remove a context 1608 */ 1609static void 1610nfs_gss_clnt_ctx_remove(struct nfsmount *nmp, struct nfs_gss_clnt_ctx *cp) 1611{ 1612 /* 1613 * If dequeueing, assume nmp->nm_lock is held 1614 */ 1615 if (nmp != NULL) 1616 TAILQ_REMOVE(&nmp->nm_gsscl, cp, gss_clnt_entries); 1617 1618 host_release_special_port(cp->gss_clnt_mport); 1619 1620 if (cp->gss_clnt_mtx) 1621 lck_mtx_destroy(cp->gss_clnt_mtx, nfs_gss_clnt_grp); 1622 if (cp->gss_clnt_handle) 1623 FREE(cp->gss_clnt_handle, M_TEMP); 1624 if (cp->gss_clnt_seqbits) 1625 FREE(cp->gss_clnt_seqbits, M_TEMP); 1626 if (cp->gss_clnt_token) 1627 FREE(cp->gss_clnt_token, M_TEMP); 1628 if (cp->gss_clnt_svcname) 1629 FREE(cp->gss_clnt_svcname, M_TEMP); 1630 FREE(cp, M_TEMP); 1631} 1632 1633/* 1634 * The context for a user is invalid. 1635 * Mark the context as invalid, then 1636 * create a new context. 1637 */ 1638int 1639nfs_gss_clnt_ctx_renew(struct nfsreq *req) 1640{ 1641 struct nfs_gss_clnt_ctx *cp = req->r_gss_ctx; 1642 struct nfsmount *nmp = req->r_nmp; 1643 struct nfs_gss_clnt_ctx *ncp; 1644 int error = 0; 1645 uid_t saved_uid; 1646 mach_port_t saved_mport; 1647 1648 if (cp == NULL) 1649 return (0); 1650 1651 lck_mtx_lock(cp->gss_clnt_mtx); 1652 if (cp->gss_clnt_flags & GSS_CTX_INVAL) { 1653 lck_mtx_unlock(cp->gss_clnt_mtx); 1654 nfs_gss_clnt_ctx_unref(req); 1655 return (0); // already being renewed 1656 } 1657 saved_uid = cp->gss_clnt_uid; 1658 saved_mport = host_copy_special_port(cp->gss_clnt_mport); 1659 1660 /* Remove the old context */ 1661 cp->gss_clnt_flags |= GSS_CTX_INVAL; 1662 1663 /* 1664 * If there's a thread waiting 1665 * in the old context, wake it up. 1666 */ 1667 if (cp->gss_clnt_flags & (GSS_NEEDCTX | GSS_NEEDSEQ)) { 1668 cp->gss_clnt_flags &= ~GSS_NEEDSEQ; 1669 wakeup(cp); 1670 } 1671 lck_mtx_unlock(cp->gss_clnt_mtx); 1672 1673 /* 1674 * Create a new context 1675 */ 1676 MALLOC(ncp, struct nfs_gss_clnt_ctx *, sizeof(*ncp), 1677 M_TEMP, M_WAITOK|M_ZERO); 1678 if (ncp == NULL) { 1679 error = ENOMEM; 1680 goto out; 1681 } 1682 1683 ncp->gss_clnt_uid = saved_uid; 1684 ncp->gss_clnt_mport = host_copy_special_port(saved_mport); // re-use the gssd port 1685 ncp->gss_clnt_mtx = lck_mtx_alloc_init(nfs_gss_clnt_grp, LCK_ATTR_NULL); 1686 ncp->gss_clnt_thread = current_thread(); 1687 lck_mtx_lock(&nmp->nm_lock); 1688 TAILQ_INSERT_TAIL(&nmp->nm_gsscl, ncp, gss_clnt_entries); 1689 lck_mtx_unlock(&nmp->nm_lock); 1690 1691 /* Adjust reference counts to new and old context */ 1692 nfs_gss_clnt_ctx_unref(req); 1693 nfs_gss_clnt_ctx_ref(req, ncp); 1694 1695 error = nfs_gss_clnt_ctx_init_retry(req, ncp); // Initialize new context 1696out: 1697 host_release_special_port(saved_mport); 1698 if (error) 1699 nfs_gss_clnt_ctx_unref(req); 1700 1701 return (error); 1702} 1703 1704/* 1705 * Destroy all the contexts associated with a mount. 1706 * The contexts are also destroyed by the server. 1707 */ 1708void 1709nfs_gss_clnt_ctx_unmount(struct nfsmount *nmp) 1710{ 1711 struct nfs_gss_clnt_ctx *cp; 1712 struct nfsm_chain nmreq, nmrep; 1713 int error, status; 1714 struct nfsreq req; 1715 1716 req.r_nmp = nmp; 1717 1718 for (;;) { 1719 lck_mtx_lock(&nmp->nm_lock); 1720 cp = TAILQ_FIRST(&nmp->nm_gsscl); 1721 lck_mtx_unlock(&nmp->nm_lock); 1722 if (cp == NULL) 1723 break; 1724 1725 nfs_gss_clnt_ctx_ref(&req, cp); 1726 1727 /* 1728 * Tell the server to destroy its context. 1729 * But don't bother if it's a forced unmount 1730 * or if it's a dummy sec=sys context. 1731 */ 1732 if (!(nmp->nm_state & NFSSTA_FORCE) && (cp->gss_clnt_service != RPCSEC_GSS_SVC_SYS)) { 1733 kauth_cred_t cred; 1734 struct posix_cred temp_pcred; 1735 1736 bzero((caddr_t) &temp_pcred, sizeof(temp_pcred)); 1737 temp_pcred.cr_ngroups = 1; 1738 temp_pcred.cr_uid = cp->gss_clnt_uid; 1739 cred = posix_cred_create(&temp_pcred); 1740 cp->gss_clnt_proc = RPCSEC_GSS_DESTROY; 1741 1742 error = 0; 1743 nfsm_chain_null(&nmreq); 1744 nfsm_chain_null(&nmrep); 1745 nfsm_chain_build_alloc_init(error, &nmreq, 0); 1746 nfsm_chain_build_done(error, &nmreq); 1747 if (!error) 1748 nfs_request_gss(nmp->nm_mountp, &nmreq, 1749 current_thread(), cred, 0, cp, &nmrep, &status); 1750 nfsm_chain_cleanup(&nmreq); 1751 nfsm_chain_cleanup(&nmrep); 1752 kauth_cred_unref(&cred); 1753 } 1754 1755 /* 1756 * Mark the context invalid then drop 1757 * the reference to remove it if its 1758 * refcount is zero. 1759 */ 1760 lck_mtx_lock(cp->gss_clnt_mtx); 1761 cp->gss_clnt_flags |= GSS_CTX_INVAL; 1762 lck_mtx_unlock(cp->gss_clnt_mtx); 1763 nfs_gss_clnt_ctx_unref(&req); 1764 } 1765} 1766 1767#endif /* NFSCLIENT */ 1768 1769/************* 1770 * 1771 * Server functions 1772 */ 1773 1774#if NFSSERVER 1775 1776/* 1777 * Find a server context based on a handle value received 1778 * in an RPCSEC_GSS credential. 1779 */ 1780static struct nfs_gss_svc_ctx * 1781nfs_gss_svc_ctx_find(uint32_t handle) 1782{ 1783 struct nfs_gss_svc_ctx_hashhead *head; 1784 struct nfs_gss_svc_ctx *cp; 1785 uint64_t timenow; 1786 1787 if (handle == 0) 1788 return (NULL); 1789 1790 head = &nfs_gss_svc_ctx_hashtbl[SVC_CTX_HASH(handle)]; 1791 /* 1792 * Don't return a context that is going to expire in GSS_CTX_PEND seconds 1793 */ 1794 clock_interval_to_deadline(GSS_CTX_PEND, NSEC_PER_SEC, &timenow); 1795 1796 lck_mtx_lock(nfs_gss_svc_ctx_mutex); 1797 1798 LIST_FOREACH(cp, head, gss_svc_entries) { 1799 if (cp->gss_svc_handle == handle) { 1800 if (timenow > cp->gss_svc_incarnation + GSS_SVC_CTX_TTL) { 1801 /* 1802 * Context has or is about to expire. Don't use. 1803 * We'll return null and the client will have to create 1804 * a new context. 1805 */ 1806 cp->gss_svc_handle = 0; 1807 /* 1808 * Make sure though that we stay around for GSS_CTX_PEND seconds 1809 * for other threads that might be using the context. 1810 */ 1811 cp->gss_svc_incarnation = timenow; 1812 1813 cp = NULL; 1814 break; 1815 } 1816 lck_mtx_lock(cp->gss_svc_mtx); 1817 cp->gss_svc_refcnt++; 1818 lck_mtx_unlock(cp->gss_svc_mtx); 1819 break; 1820 } 1821 } 1822 1823 lck_mtx_unlock(nfs_gss_svc_ctx_mutex); 1824 1825 return (cp); 1826} 1827 1828/* 1829 * Insert a new server context into the hash table 1830 * and start the context reap thread if necessary. 1831 */ 1832static void 1833nfs_gss_svc_ctx_insert(struct nfs_gss_svc_ctx *cp) 1834{ 1835 struct nfs_gss_svc_ctx_hashhead *head; 1836 struct nfs_gss_svc_ctx *p; 1837 1838 lck_mtx_lock(nfs_gss_svc_ctx_mutex); 1839 1840 /* 1841 * Give the client a random handle so that if we reboot 1842 * it's unlikely the client will get a bad context match. 1843 * Make sure it's not zero or already assigned. 1844 */ 1845retry: 1846 cp->gss_svc_handle = random(); 1847 if (cp->gss_svc_handle == 0) 1848 goto retry; 1849 head = &nfs_gss_svc_ctx_hashtbl[SVC_CTX_HASH(cp->gss_svc_handle)]; 1850 LIST_FOREACH(p, head, gss_svc_entries) 1851 if (p->gss_svc_handle == cp->gss_svc_handle) 1852 goto retry; 1853 1854 clock_interval_to_deadline(GSS_CTX_PEND, NSEC_PER_SEC, 1855 &cp->gss_svc_incarnation); 1856 LIST_INSERT_HEAD(head, cp, gss_svc_entries); 1857 nfs_gss_ctx_count++; 1858 1859 if (!nfs_gss_timer_on) { 1860 nfs_gss_timer_on = 1; 1861 1862 nfs_interval_timer_start(nfs_gss_svc_ctx_timer_call, 1863 min(GSS_TIMER_PERIOD, max(GSS_CTX_TTL_MIN, nfsrv_gss_context_ttl)) * MSECS_PER_SEC); 1864 } 1865 1866 lck_mtx_unlock(nfs_gss_svc_ctx_mutex); 1867} 1868 1869/* 1870 * This function is called via the kernel's callout 1871 * mechanism. It runs only when there are 1872 * cached RPCSEC_GSS contexts. 1873 */ 1874void 1875nfs_gss_svc_ctx_timer(__unused void *param1, __unused void *param2) 1876{ 1877 struct nfs_gss_svc_ctx *cp, *next; 1878 uint64_t timenow; 1879 int contexts = 0; 1880 int i; 1881 1882 lck_mtx_lock(nfs_gss_svc_ctx_mutex); 1883 clock_get_uptime(&timenow); 1884 1885 /* 1886 * Scan all the hash chains 1887 */ 1888 for (i = 0; i < SVC_CTX_HASHSZ; i++) { 1889 /* 1890 * For each hash chain, look for entries 1891 * that haven't been used in a while. 1892 */ 1893 LIST_FOREACH_SAFE(cp, &nfs_gss_svc_ctx_hashtbl[i], gss_svc_entries, next) { 1894 contexts++; 1895 if (timenow > cp->gss_svc_incarnation + 1896 (cp->gss_svc_handle ? GSS_SVC_CTX_TTL : 0) 1897 && cp->gss_svc_refcnt == 0) { 1898 /* 1899 * A stale context - remove it 1900 */ 1901 LIST_REMOVE(cp, gss_svc_entries); 1902 if (cp->gss_svc_seqbits) 1903 FREE(cp->gss_svc_seqbits, M_TEMP); 1904 lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp); 1905 FREE(cp, M_TEMP); 1906 contexts--; 1907 } 1908 } 1909 } 1910 1911 nfs_gss_ctx_count = contexts; 1912 1913 /* 1914 * If there are still some cached contexts left, 1915 * set up another callout to check on them later. 1916 */ 1917 nfs_gss_timer_on = nfs_gss_ctx_count > 0; 1918 if (nfs_gss_timer_on) 1919 nfs_interval_timer_start(nfs_gss_svc_ctx_timer_call, 1920 min(GSS_TIMER_PERIOD, max(GSS_CTX_TTL_MIN, nfsrv_gss_context_ttl)) * MSECS_PER_SEC); 1921 1922 lck_mtx_unlock(nfs_gss_svc_ctx_mutex); 1923} 1924 1925/* 1926 * Here the server receives an RPCSEC_GSS credential in an 1927 * RPC call header. First there's some checking to make sure 1928 * the credential is appropriate - whether the context is still 1929 * being set up, or is complete. Then we use the handle to find 1930 * the server's context and validate the verifier, which contains 1931 * a signed checksum of the RPC header. If the verifier checks 1932 * out, we extract the user's UID and groups from the context 1933 * and use it to set up a UNIX credential for the user's request. 1934 */ 1935int 1936nfs_gss_svc_cred_get(struct nfsrv_descript *nd, struct nfsm_chain *nmc) 1937{ 1938 uint32_t vers, proc, seqnum, service; 1939 uint32_t handle, handle_len; 1940 struct nfs_gss_svc_ctx *cp = NULL; 1941 uint32_t flavor = 0, verflen = 0; 1942 int error = 0; 1943 uint32_t arglen, start, toklen, cksumlen; 1944 u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)]; 1945 u_char cksum1[MAX_DIGEST], cksum2[MAX_DIGEST]; 1946 struct nfsm_chain nmc_tmp; 1947 gss_key_info *ki; 1948 1949 vers = proc = seqnum = service = handle_len = 0; 1950 arglen = cksumlen = 0; 1951 1952 nfsm_chain_get_32(error, nmc, vers); 1953 if (vers != RPCSEC_GSS_VERS_1) { 1954 error = NFSERR_AUTHERR | AUTH_REJECTCRED; 1955 goto nfsmout; 1956 } 1957 1958 nfsm_chain_get_32(error, nmc, proc); 1959 nfsm_chain_get_32(error, nmc, seqnum); 1960 nfsm_chain_get_32(error, nmc, service); 1961 nfsm_chain_get_32(error, nmc, handle_len); 1962 if (error) 1963 goto nfsmout; 1964 1965 /* 1966 * Make sure context setup/destroy is being done with a nullproc 1967 */ 1968 if (proc != RPCSEC_GSS_DATA && nd->nd_procnum != NFSPROC_NULL) { 1969 error = NFSERR_AUTHERR | RPCSEC_GSS_CREDPROBLEM; 1970 goto nfsmout; 1971 } 1972 1973 /* 1974 * If the sequence number is greater than the max 1975 * allowable, reject and have the client init a 1976 * new context. 1977 */ 1978 if (seqnum > GSS_MAXSEQ) { 1979 error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM; 1980 goto nfsmout; 1981 } 1982 1983 nd->nd_sec = 1984 service == RPCSEC_GSS_SVC_NONE ? RPCAUTH_KRB5 : 1985 service == RPCSEC_GSS_SVC_INTEGRITY ? RPCAUTH_KRB5I : 1986 service == RPCSEC_GSS_SVC_PRIVACY ? RPCAUTH_KRB5P : 0; 1987 1988 if (proc == RPCSEC_GSS_INIT) { 1989 /* 1990 * Limit the total number of contexts 1991 */ 1992 if (nfs_gss_ctx_count > nfs_gss_ctx_max) { 1993 error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM; 1994 goto nfsmout; 1995 } 1996 1997 /* 1998 * Set up a new context 1999 */ 2000 MALLOC(cp, struct nfs_gss_svc_ctx *, sizeof(*cp), M_TEMP, M_WAITOK|M_ZERO); 2001 if (cp == NULL) { 2002 error = ENOMEM; 2003 goto nfsmout; 2004 } 2005 cp->gss_svc_mtx = lck_mtx_alloc_init(nfs_gss_svc_grp, LCK_ATTR_NULL); 2006 cp->gss_svc_refcnt = 1; 2007 } else { 2008 2009 /* 2010 * Use the handle to find the context 2011 */ 2012 if (handle_len != sizeof(handle)) { 2013 error = NFSERR_AUTHERR | RPCSEC_GSS_CREDPROBLEM; 2014 goto nfsmout; 2015 } 2016 nfsm_chain_get_32(error, nmc, handle); 2017 if (error) 2018 goto nfsmout; 2019 cp = nfs_gss_svc_ctx_find(handle); 2020 if (cp == NULL) { 2021 error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM; 2022 goto nfsmout; 2023 } 2024 } 2025 2026 cp->gss_svc_proc = proc; 2027 ki = &cp->gss_svc_kinfo; 2028 2029 if (proc == RPCSEC_GSS_DATA || proc == RPCSEC_GSS_DESTROY) { 2030 struct posix_cred temp_pcred; 2031 2032 if (cp->gss_svc_seqwin == 0) { 2033 /* 2034 * Context isn't complete 2035 */ 2036 error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM; 2037 goto nfsmout; 2038 } 2039 2040 if (!nfs_gss_svc_seqnum_valid(cp, seqnum)) { 2041 /* 2042 * Sequence number is bad 2043 */ 2044 error = EINVAL; // drop the request 2045 goto nfsmout; 2046 } 2047 2048 /* Now compute the client's call header checksum */ 2049 nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), 0, 0, cksum1); 2050 2051 /* 2052 * Validate the verifier. 2053 * The verifier contains an encrypted checksum 2054 * of the call header from the XID up to and 2055 * including the credential. We compute the 2056 * checksum and compare it with what came in 2057 * the verifier. 2058 */ 2059 nfsm_chain_get_32(error, nmc, flavor); 2060 nfsm_chain_get_32(error, nmc, verflen); 2061 if (error) 2062 goto nfsmout; 2063 if (flavor != RPCSEC_GSS || verflen != KRB5_SZ_TOKEN(ki->hash_len)) 2064 error = NFSERR_AUTHERR | AUTH_BADVERF; 2065 nfsm_chain_get_opaque(error, nmc, verflen, tokbuf); 2066 if (error) 2067 goto nfsmout; 2068 2069 /* Get the checksum from the token inside the verifier */ 2070 error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 1, 2071 NULL, cksum2); 2072 if (error) 2073 goto nfsmout; 2074 2075 if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) { 2076 error = NFSERR_AUTHERR | RPCSEC_GSS_CTXPROBLEM; 2077 goto nfsmout; 2078 } 2079 2080 nd->nd_gss_seqnum = seqnum; 2081 2082 /* 2083 * Set up the user's cred 2084 */ 2085 bzero(&temp_pcred, sizeof(temp_pcred)); 2086 temp_pcred.cr_uid = cp->gss_svc_uid; 2087 bcopy(cp->gss_svc_gids, temp_pcred.cr_groups, 2088 sizeof(gid_t) * cp->gss_svc_ngroups); 2089 temp_pcred.cr_ngroups = cp->gss_svc_ngroups; 2090 2091 nd->nd_cr = posix_cred_create(&temp_pcred); 2092 if (nd->nd_cr == NULL) { 2093 error = ENOMEM; 2094 goto nfsmout; 2095 } 2096 clock_get_uptime(&cp->gss_svc_incarnation); 2097 2098 /* 2099 * If the call arguments are integrity or privacy protected 2100 * then we need to check them here. 2101 */ 2102 switch (service) { 2103 case RPCSEC_GSS_SVC_NONE: 2104 /* nothing to do */ 2105 break; 2106 case RPCSEC_GSS_SVC_INTEGRITY: 2107 /* 2108 * Here's what we expect in the integrity call args: 2109 * 2110 * - length of seq num + call args (4 bytes) 2111 * - sequence number (4 bytes) 2112 * - call args (variable bytes) 2113 * - length of checksum token (37) 2114 * - checksum of seqnum + call args (37 bytes) 2115 */ 2116 nfsm_chain_get_32(error, nmc, arglen); // length of args 2117 if (arglen > NFS_MAXPACKET) { 2118 error = EBADRPC; 2119 goto nfsmout; 2120 } 2121 2122 /* Compute the checksum over the call args */ 2123 start = nfsm_chain_offset(nmc); 2124 nfs_gss_cksum_chain(ki, nmc, ALG_MIC(ki), start, arglen, cksum1); 2125 2126 /* 2127 * Get the sequence number prepended to the args 2128 * and compare it against the one sent in the 2129 * call credential. 2130 */ 2131 nfsm_chain_get_32(error, nmc, seqnum); 2132 if (seqnum != nd->nd_gss_seqnum) { 2133 error = EBADRPC; // returns as GARBAGEARGS 2134 goto nfsmout; 2135 } 2136 2137 /* 2138 * Advance to the end of the args and 2139 * fetch the checksum computed by the client. 2140 */ 2141 nmc_tmp = *nmc; 2142 arglen -= NFSX_UNSIGNED; // skipped seqnum 2143 nfsm_chain_adv(error, &nmc_tmp, arglen); // skip args 2144 nfsm_chain_get_32(error, &nmc_tmp, cksumlen); // length of checksum 2145 if (cksumlen != KRB5_SZ_TOKEN(ki->hash_len)) { 2146 error = EBADRPC; 2147 goto nfsmout; 2148 } 2149 nfsm_chain_get_opaque(error, &nmc_tmp, cksumlen, tokbuf); 2150 if (error) 2151 goto nfsmout; 2152 error = nfs_gss_token_get(ki, ALG_MIC(ki), tokbuf, 1, 2153 NULL, cksum2); 2154 2155 /* Verify that the checksums are the same */ 2156 if (error || bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) { 2157 error = EBADRPC; 2158 goto nfsmout; 2159 } 2160 break; 2161 case RPCSEC_GSS_SVC_PRIVACY: 2162 /* 2163 * Here's what we expect in the privacy call args: 2164 * 2165 * - length of confounder + seq num + token + call args 2166 * - wrap token (37-40 bytes) 2167 * - confounder (8 bytes) 2168 * - sequence number (4 bytes) 2169 * - call args (encrypted) 2170 */ 2171 nfsm_chain_get_32(error, nmc, arglen); // length of args 2172 if (arglen > NFS_MAXPACKET) { 2173 error = EBADRPC; 2174 goto nfsmout; 2175 } 2176 2177 /* Get the token that prepends the encrypted args */ 2178 nfsm_chain_get_opaque(error, nmc, KRB5_SZ_TOKMAX(ki->hash_len), tokbuf); 2179 if (error) 2180 goto nfsmout; 2181 error = nfs_gss_token_get(ki, ALG_WRAP(ki), tokbuf, 1, 2182 &toklen, cksum1); 2183 if (error) 2184 goto nfsmout; 2185 nfsm_chain_reverse(nmc, nfsm_pad(toklen)); 2186 2187 /* decrypt the 8 byte confounder + seqnum + args */ 2188 start = nfsm_chain_offset(nmc); 2189 arglen -= toklen; 2190 nfs_gss_encrypt_chain(ki, nmc, start, arglen, DES_DECRYPT); 2191 2192 /* Compute a checksum over the sequence number + results */ 2193 nfs_gss_cksum_chain(ki, nmc, ALG_WRAP(ki), start, arglen, cksum2); 2194 2195 /* Verify that the checksums are the same */ 2196 if (bcmp(cksum1, cksum2, HASHLEN(ki)) != 0) { 2197 error = EBADRPC; 2198 goto nfsmout; 2199 } 2200 2201 /* 2202 * Get the sequence number prepended to the args 2203 * and compare it against the one sent in the 2204 * call credential. 2205 */ 2206 nfsm_chain_adv(error, nmc, 8); // skip over the confounder 2207 nfsm_chain_get_32(error, nmc, seqnum); 2208 if (seqnum != nd->nd_gss_seqnum) { 2209 error = EBADRPC; // returns as GARBAGEARGS 2210 goto nfsmout; 2211 } 2212 break; 2213 } 2214 } else { 2215 /* 2216 * If the proc is RPCSEC_GSS_INIT or RPCSEC_GSS_CONTINUE_INIT 2217 * then we expect a null verifier. 2218 */ 2219 nfsm_chain_get_32(error, nmc, flavor); 2220 nfsm_chain_get_32(error, nmc, verflen); 2221 if (error || flavor != RPCAUTH_NULL || verflen > 0) 2222 error = NFSERR_AUTHERR | RPCSEC_GSS_CREDPROBLEM; 2223 if (error) { 2224 if (proc == RPCSEC_GSS_INIT) { 2225 lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp); 2226 FREE(cp, M_TEMP); 2227 cp = NULL; 2228 } 2229 goto nfsmout; 2230 } 2231 } 2232 2233 nd->nd_gss_context = cp; 2234 return 0; 2235nfsmout: 2236 if (cp) 2237 nfs_gss_svc_ctx_deref(cp); 2238 return (error); 2239} 2240 2241/* 2242 * Insert the server's verifier into the RPC reply header. 2243 * It contains a signed checksum of the sequence number that 2244 * was received in the RPC call. 2245 * Then go on to add integrity or privacy if necessary. 2246 */ 2247int 2248nfs_gss_svc_verf_put(struct nfsrv_descript *nd, struct nfsm_chain *nmc) 2249{ 2250 struct nfs_gss_svc_ctx *cp; 2251 int error = 0; 2252 u_char tokbuf[KRB5_SZ_TOKEN(MAX_DIGEST)]; 2253 int toklen; 2254 u_char cksum[MAX_DIGEST]; 2255 gss_key_info *ki; 2256 2257 cp = nd->nd_gss_context; 2258 ki = &cp->gss_svc_kinfo; 2259 2260 if (cp->gss_svc_major != GSS_S_COMPLETE) { 2261 /* 2262 * If the context isn't yet complete 2263 * then return a null verifier. 2264 */ 2265 nfsm_chain_add_32(error, nmc, RPCAUTH_NULL); 2266 nfsm_chain_add_32(error, nmc, 0); 2267 return (error); 2268 } 2269 2270 /* 2271 * Compute checksum of the request seq number 2272 * If it's the final reply of context setup 2273 * then return the checksum of the context 2274 * window size. 2275 */ 2276 if (cp->gss_svc_proc == RPCSEC_GSS_INIT || 2277 cp->gss_svc_proc == RPCSEC_GSS_CONTINUE_INIT) 2278 nfs_gss_cksum_rep(ki, cp->gss_svc_seqwin, cksum); 2279 else 2280 nfs_gss_cksum_rep(ki, nd->nd_gss_seqnum, cksum); 2281 /* 2282 * Now wrap it in a token and add 2283 * the verifier to the reply. 2284 */ 2285 toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 0, 0, cksum); 2286 nfsm_chain_add_32(error, nmc, RPCSEC_GSS); 2287 nfsm_chain_add_32(error, nmc, toklen); 2288 nfsm_chain_add_opaque(error, nmc, tokbuf, toklen); 2289 2290 return (error); 2291} 2292 2293/* 2294 * The results aren't available yet, but if they need to be 2295 * checksummed for integrity protection or encrypted, then 2296 * we can record the start offset here, insert a place-holder 2297 * for the results length, as well as the sequence number. 2298 * The rest of the work is done later by nfs_gss_svc_protect_reply() 2299 * when the results are available. 2300 */ 2301int 2302nfs_gss_svc_prepare_reply(struct nfsrv_descript *nd, struct nfsm_chain *nmc) 2303{ 2304 struct nfs_gss_svc_ctx *cp = nd->nd_gss_context; 2305 int error = 0; 2306 2307 if (cp->gss_svc_proc == RPCSEC_GSS_INIT || 2308 cp->gss_svc_proc == RPCSEC_GSS_CONTINUE_INIT) 2309 return (0); 2310 2311 switch (nd->nd_sec) { 2312 case RPCAUTH_KRB5: 2313 /* Nothing to do */ 2314 break; 2315 case RPCAUTH_KRB5I: 2316 nd->nd_gss_mb = nmc->nmc_mcur; // record current mbuf 2317 nfsm_chain_finish_mbuf(error, nmc); // split the chain here 2318 nfsm_chain_add_32(error, nmc, nd->nd_gss_seqnum); // req sequence number 2319 break; 2320 case RPCAUTH_KRB5P: 2321 nd->nd_gss_mb = nmc->nmc_mcur; // record current mbuf 2322 nfsm_chain_finish_mbuf(error, nmc); // split the chain here 2323 nfsm_chain_add_32(error, nmc, random()); // confounder bytes 1-4 2324 nfsm_chain_add_32(error, nmc, random()); // confounder bytes 5-8 2325 nfsm_chain_add_32(error, nmc, nd->nd_gss_seqnum); // req sequence number 2326 break; 2327 } 2328 2329 return (error); 2330} 2331 2332/* 2333 * The results are checksummed or encrypted for return to the client 2334 */ 2335int 2336nfs_gss_svc_protect_reply(struct nfsrv_descript *nd, mbuf_t mrep) 2337{ 2338 struct nfs_gss_svc_ctx *cp = nd->nd_gss_context; 2339 struct nfsm_chain nmrep_res, *nmc_res = &nmrep_res; 2340 struct nfsm_chain nmrep_pre, *nmc_pre = &nmrep_pre; 2341 mbuf_t mb, results; 2342 uint32_t reslen; 2343 u_char tokbuf[KRB5_SZ_TOKMAX(MAX_DIGEST)]; 2344 int pad, toklen; 2345 u_char cksum[MAX_DIGEST]; 2346 int error = 0; 2347 gss_key_info *ki = &cp->gss_svc_kinfo; 2348 2349 /* 2350 * Using a reference to the mbuf where we previously split the reply 2351 * mbuf chain, we split the mbuf chain argument into two mbuf chains, 2352 * one that allows us to prepend a length field or token, (nmc_pre) 2353 * and the second which holds just the results that we're going to 2354 * checksum and/or encrypt. When we're done, we join the chains back 2355 * together. 2356 */ 2357 nfs_gss_nfsm_chain(nmc_res, mrep); // set up the results chain 2358 mb = nd->nd_gss_mb; // the mbuf where we split 2359 results = mbuf_next(mb); // first mbuf in the results 2360 reslen = nfs_gss_mchain_length(results); // length of results 2361 error = mbuf_setnext(mb, NULL); // disconnect the chains 2362 if (error) 2363 return (error); 2364 nfs_gss_nfsm_chain(nmc_pre, mb); // set up the prepend chain 2365 2366 if (nd->nd_sec == RPCAUTH_KRB5I) { 2367 nfsm_chain_add_32(error, nmc_pre, reslen); 2368 nfsm_chain_build_done(error, nmc_pre); 2369 if (error) 2370 return (error); 2371 nfs_gss_append_chain(nmc_pre, results); // Append the results mbufs 2372 2373 /* Now compute the checksum over the results data */ 2374 nfs_gss_cksum_mchain(ki, results, ALG_MIC(ki), 0, reslen, cksum); 2375 2376 /* Put it into a token and append to the request */ 2377 toklen = nfs_gss_token_put(ki, ALG_MIC(ki), tokbuf, 0, 0, cksum); 2378 nfsm_chain_add_32(error, nmc_res, toklen); 2379 nfsm_chain_add_opaque(error, nmc_res, tokbuf, toklen); 2380 nfsm_chain_build_done(error, nmc_res); 2381 } else { 2382 /* RPCAUTH_KRB5P */ 2383 /* 2384 * Append a pad trailer - per RFC 1964 section 1.2.2.3 2385 * Since XDR data is always 32-bit aligned, it 2386 * needs to be padded either by 4 bytes or 8 bytes. 2387 */ 2388 if (reslen % 8 > 0) { 2389 nfsm_chain_add_32(error, nmc_res, 0x04040404); 2390 reslen += NFSX_UNSIGNED; 2391 } else { 2392 nfsm_chain_add_32(error, nmc_res, 0x08080808); 2393 nfsm_chain_add_32(error, nmc_res, 0x08080808); 2394 reslen += 2 * NFSX_UNSIGNED; 2395 } 2396 nfsm_chain_build_done(error, nmc_res); 2397 2398 /* Now compute the checksum over the results data */ 2399 nfs_gss_cksum_mchain(ki, results, ALG_WRAP(ki), 0, reslen, cksum); 2400 2401 /* Put it into a token and insert in the reply */ 2402 toklen = nfs_gss_token_put(ki, ALG_WRAP(ki), tokbuf, 0, reslen, cksum); 2403 nfsm_chain_add_32(error, nmc_pre, toklen + reslen); 2404 nfsm_chain_add_opaque_nopad(error, nmc_pre, tokbuf, toklen); 2405 nfsm_chain_build_done(error, nmc_pre); 2406 if (error) 2407 return (error); 2408 nfs_gss_append_chain(nmc_pre, results); // Append the results mbufs 2409 2410 /* Encrypt the confounder + seqnum + results */ 2411 nfs_gss_encrypt_mchain(ki, results, 0, reslen, DES_ENCRYPT); 2412 2413 /* Add null XDR pad if the ASN.1 token misaligned the data */ 2414 pad = nfsm_pad(toklen + reslen); 2415 if (pad > 0) { 2416 nfsm_chain_add_opaque_nopad(error, nmc_pre, iv0, pad); 2417 nfsm_chain_build_done(error, nmc_pre); 2418 } 2419 } 2420 2421 return (error); 2422} 2423 2424/* 2425 * This function handles the context setup calls from the client. 2426 * Essentially, it implements the NFS null procedure calls when 2427 * an RPCSEC_GSS credential is used. 2428 * This is the context maintenance function. It creates and 2429 * destroys server contexts at the whim of the client. 2430 * During context creation, it receives GSS-API tokens from the 2431 * client, passes them up to gssd, and returns a received token 2432 * back to the client in the null procedure reply. 2433 */ 2434int 2435nfs_gss_svc_ctx_init(struct nfsrv_descript *nd, struct nfsrv_sock *slp, mbuf_t *mrepp) 2436{ 2437 struct nfs_gss_svc_ctx *cp = NULL; 2438 int error = 0; 2439 int autherr = 0; 2440 struct nfsm_chain *nmreq, nmrep; 2441 int sz; 2442 2443 nmreq = &nd->nd_nmreq; 2444 nfsm_chain_null(&nmrep); 2445 *mrepp = NULL; 2446 cp = nd->nd_gss_context; 2447 nd->nd_repstat = 0; 2448 2449 switch (cp->gss_svc_proc) { 2450 case RPCSEC_GSS_INIT: 2451 nfs_gss_svc_ctx_insert(cp); 2452 /* FALLTHRU */ 2453 2454 case RPCSEC_GSS_CONTINUE_INIT: 2455 /* Get the token from the request */ 2456 nfsm_chain_get_32(error, nmreq, cp->gss_svc_tokenlen); 2457 if (cp->gss_svc_tokenlen == 0) { 2458 autherr = RPCSEC_GSS_CREDPROBLEM; 2459 break; 2460 } 2461 MALLOC(cp->gss_svc_token, u_char *, cp->gss_svc_tokenlen, M_TEMP, M_WAITOK); 2462 if (cp->gss_svc_token == NULL) { 2463 autherr = RPCSEC_GSS_CREDPROBLEM; 2464 break; 2465 } 2466 nfsm_chain_get_opaque(error, nmreq, cp->gss_svc_tokenlen, cp->gss_svc_token); 2467 2468 /* Use the token in a gss_accept_sec_context upcall */ 2469 error = nfs_gss_svc_gssd_upcall(cp); 2470 if (error) { 2471 autherr = RPCSEC_GSS_CREDPROBLEM; 2472 if (error == NFSERR_EAUTH) 2473 error = 0; 2474 break; 2475 } 2476 2477 /* 2478 * If the context isn't complete, pass the new token 2479 * back to the client for another round. 2480 */ 2481 if (cp->gss_svc_major != GSS_S_COMPLETE) 2482 break; 2483 2484 /* 2485 * Now the server context is complete. 2486 * Finish setup. 2487 */ 2488 clock_get_uptime(&cp->gss_svc_incarnation); 2489 2490 cp->gss_svc_seqwin = GSS_SVC_SEQWINDOW; 2491 MALLOC(cp->gss_svc_seqbits, uint32_t *, 2492 nfsm_rndup((cp->gss_svc_seqwin + 7) / 8), M_TEMP, M_WAITOK|M_ZERO); 2493 if (cp->gss_svc_seqbits == NULL) { 2494 autherr = RPCSEC_GSS_CREDPROBLEM; 2495 break; 2496 } 2497 break; 2498 2499 case RPCSEC_GSS_DATA: 2500 /* Just a nullproc ping - do nothing */ 2501 break; 2502 2503 case RPCSEC_GSS_DESTROY: 2504 /* 2505 * Don't destroy the context immediately because 2506 * other active requests might still be using it. 2507 * Instead, schedule it for destruction after 2508 * GSS_CTX_PEND time has elapsed. 2509 */ 2510 cp = nfs_gss_svc_ctx_find(cp->gss_svc_handle); 2511 if (cp != NULL) { 2512 cp->gss_svc_handle = 0; // so it can't be found 2513 lck_mtx_lock(cp->gss_svc_mtx); 2514 clock_interval_to_deadline(GSS_CTX_PEND, NSEC_PER_SEC, 2515 &cp->gss_svc_incarnation); 2516 lck_mtx_unlock(cp->gss_svc_mtx); 2517 } 2518 break; 2519 default: 2520 autherr = RPCSEC_GSS_CREDPROBLEM; 2521 break; 2522 } 2523 2524 /* Now build the reply */ 2525 2526 if (nd->nd_repstat == 0) 2527 nd->nd_repstat = autherr ? (NFSERR_AUTHERR | autherr) : NFSERR_RETVOID; 2528 sz = 7 * NFSX_UNSIGNED + nfsm_rndup(cp->gss_svc_tokenlen); // size of results 2529 error = nfsrv_rephead(nd, slp, &nmrep, sz); 2530 *mrepp = nmrep.nmc_mhead; 2531 if (error || autherr) 2532 goto nfsmout; 2533 2534 if (cp->gss_svc_proc == RPCSEC_GSS_INIT || 2535 cp->gss_svc_proc == RPCSEC_GSS_CONTINUE_INIT) { 2536 nfsm_chain_add_32(error, &nmrep, sizeof(cp->gss_svc_handle)); 2537 nfsm_chain_add_32(error, &nmrep, cp->gss_svc_handle); 2538 2539 nfsm_chain_add_32(error, &nmrep, cp->gss_svc_major); 2540 nfsm_chain_add_32(error, &nmrep, cp->gss_svc_minor); 2541 nfsm_chain_add_32(error, &nmrep, cp->gss_svc_seqwin); 2542 2543 nfsm_chain_add_32(error, &nmrep, cp->gss_svc_tokenlen); 2544 if (cp->gss_svc_token != NULL) { 2545 nfsm_chain_add_opaque(error, &nmrep, cp->gss_svc_token, cp->gss_svc_tokenlen); 2546 FREE(cp->gss_svc_token, M_TEMP); 2547 cp->gss_svc_token = NULL; 2548 } 2549 } 2550 2551nfsmout: 2552 if (autherr != 0) { 2553 nd->nd_gss_context = NULL; 2554 LIST_REMOVE(cp, gss_svc_entries); 2555 if (cp->gss_svc_seqbits != NULL) 2556 FREE(cp->gss_svc_seqbits, M_TEMP); 2557 if (cp->gss_svc_token != NULL) 2558 FREE(cp->gss_svc_token, M_TEMP); 2559 lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp); 2560 FREE(cp, M_TEMP); 2561 } 2562 2563 nfsm_chain_build_done(error, &nmrep); 2564 if (error) { 2565 nfsm_chain_cleanup(&nmrep); 2566 *mrepp = NULL; 2567 } 2568 return (error); 2569} 2570 2571/* 2572 * This is almost a mirror-image of the client side upcall. 2573 * It passes and receives a token, but invokes gss_accept_sec_context. 2574 * If it's the final call of the context setup, then gssd also returns 2575 * the session key and the user's UID. 2576 */ 2577static int 2578nfs_gss_svc_gssd_upcall(struct nfs_gss_svc_ctx *cp) 2579{ 2580 kern_return_t kr; 2581 mach_port_t mp; 2582 int retry_cnt = 0; 2583 gssd_byte_buffer okey = NULL; 2584 uint32_t skeylen = 0; 2585 uint32_t ret_flags; 2586 vm_map_copy_t itoken = NULL; 2587 gssd_byte_buffer otoken = NULL; 2588 mach_msg_type_number_t otokenlen; 2589 int error = 0; 2590 char svcname[] = "nfs"; 2591 2592 kr = host_get_gssd_port(host_priv_self(), &mp); 2593 if (kr != KERN_SUCCESS) { 2594 printf("nfs_gss_svc_gssd_upcall: can't get gssd port, status %x (%d)\n", kr, kr); 2595 goto out; 2596 } 2597 if (!IPC_PORT_VALID(mp)) { 2598 printf("nfs_gss_svc_gssd_upcall: gssd port not valid\n"); 2599 goto out; 2600 } 2601 2602 if (cp->gss_svc_tokenlen > 0) 2603 nfs_gss_mach_alloc_buffer(cp->gss_svc_token, cp->gss_svc_tokenlen, &itoken); 2604 2605retry: 2606 kr = mach_gss_accept_sec_context( 2607 mp, 2608 (gssd_byte_buffer) itoken, (mach_msg_type_number_t) cp->gss_svc_tokenlen, 2609 svcname, 2610 0, 2611 &cp->gss_svc_context, 2612 &cp->gss_svc_cred_handle, 2613 &ret_flags, 2614 &cp->gss_svc_uid, 2615 cp->gss_svc_gids, 2616 &cp->gss_svc_ngroups, 2617 &okey, (mach_msg_type_number_t *) &skeylen, 2618 &otoken, &otokenlen, 2619 &cp->gss_svc_major, 2620 &cp->gss_svc_minor); 2621 2622 if (kr != KERN_SUCCESS) { 2623 printf("nfs_gss_svc_gssd_upcall failed: %x (%d)\n", kr, kr); 2624 if (kr == MIG_SERVER_DIED && cp->gss_svc_context == 0 && 2625 retry_cnt++ < NFS_GSS_MACH_MAX_RETRIES) { 2626 if (cp->gss_svc_tokenlen > 0) 2627 nfs_gss_mach_alloc_buffer(cp->gss_svc_token, cp->gss_svc_tokenlen, &itoken); 2628 goto retry; 2629 } 2630 host_release_special_port(mp); 2631 goto out; 2632 } 2633 2634 host_release_special_port(mp); 2635 2636 if (skeylen > 0) { 2637 if (skeylen != SKEYLEN && skeylen != SKEYLEN3) { 2638 printf("nfs_gss_svc_gssd_upcall: bad key length (%d)\n", skeylen); 2639 vm_map_copy_discard((vm_map_copy_t) okey); 2640 vm_map_copy_discard((vm_map_copy_t) otoken); 2641 goto out; 2642 } 2643 error = nfs_gss_mach_vmcopyout((vm_map_copy_t) okey, skeylen, cp->gss_svc_kinfo.skey); 2644 if (error) { 2645 vm_map_copy_discard((vm_map_copy_t) otoken); 2646 goto out; 2647 } 2648 error = gss_key_init(&cp->gss_svc_kinfo, skeylen); 2649 if (error) 2650 goto out; 2651 2652 } 2653 2654 /* Free context token used as input */ 2655 if (cp->gss_svc_token) 2656 FREE(cp->gss_svc_token, M_TEMP); 2657 cp->gss_svc_token = NULL; 2658 cp->gss_svc_tokenlen = 0; 2659 2660 if (otokenlen > 0) { 2661 /* Set context token to gss output token */ 2662 MALLOC(cp->gss_svc_token, u_char *, otokenlen, M_TEMP, M_WAITOK); 2663 if (cp->gss_svc_token == NULL) { 2664 printf("nfs_gss_svc_gssd_upcall: could not allocate %d bytes\n", otokenlen); 2665 vm_map_copy_discard((vm_map_copy_t) otoken); 2666 return (ENOMEM); 2667 } 2668 error = nfs_gss_mach_vmcopyout((vm_map_copy_t) otoken, otokenlen, cp->gss_svc_token); 2669 if (error) { 2670 FREE(cp->gss_svc_token, M_TEMP); 2671 cp->gss_svc_token = NULL; 2672 return (NFSERR_EAUTH); 2673 } 2674 cp->gss_svc_tokenlen = otokenlen; 2675 } 2676 2677 return (0); 2678 2679out: 2680 FREE(cp->gss_svc_token, M_TEMP); 2681 cp->gss_svc_tokenlen = 0; 2682 cp->gss_svc_token = NULL; 2683 2684 return (NFSERR_EAUTH); 2685} 2686 2687/* 2688 * Validate the sequence number in the credential as described 2689 * in RFC 2203 Section 5.3.3.1 2690 * 2691 * Here the window of valid sequence numbers is represented by 2692 * a bitmap. As each sequence number is received, its bit is 2693 * set in the bitmap. An invalid sequence number lies below 2694 * the lower bound of the window, or is within the window but 2695 * has its bit already set. 2696 */ 2697static int 2698nfs_gss_svc_seqnum_valid(struct nfs_gss_svc_ctx *cp, uint32_t seq) 2699{ 2700 uint32_t *bits = cp->gss_svc_seqbits; 2701 uint32_t win = cp->gss_svc_seqwin; 2702 uint32_t i; 2703 2704 lck_mtx_lock(cp->gss_svc_mtx); 2705 2706 /* 2707 * If greater than the window upper bound, 2708 * move the window up, and set the bit. 2709 */ 2710 if (seq > cp->gss_svc_seqmax) { 2711 if (seq - cp->gss_svc_seqmax > win) 2712 bzero(bits, nfsm_rndup((win + 7) / 8)); 2713 else 2714 for (i = cp->gss_svc_seqmax + 1; i < seq; i++) 2715 win_resetbit(bits, i % win); 2716 win_setbit(bits, seq % win); 2717 cp->gss_svc_seqmax = seq; 2718 lck_mtx_unlock(cp->gss_svc_mtx); 2719 return (1); 2720 } 2721 2722 /* 2723 * Invalid if below the lower bound of the window 2724 */ 2725 if (seq <= cp->gss_svc_seqmax - win) { 2726 lck_mtx_unlock(cp->gss_svc_mtx); 2727 return (0); 2728 } 2729 2730 /* 2731 * In the window, invalid if the bit is already set 2732 */ 2733 if (win_getbit(bits, seq % win)) { 2734 lck_mtx_unlock(cp->gss_svc_mtx); 2735 return (0); 2736 } 2737 win_setbit(bits, seq % win); 2738 lck_mtx_unlock(cp->gss_svc_mtx); 2739 return (1); 2740} 2741 2742/* 2743 * Drop a reference to a context 2744 * 2745 * Note that it's OK for the context to exist 2746 * with a refcount of zero. The refcount isn't 2747 * checked until we're about to reap an expired one. 2748 */ 2749void 2750nfs_gss_svc_ctx_deref(struct nfs_gss_svc_ctx *cp) 2751{ 2752 lck_mtx_lock(cp->gss_svc_mtx); 2753 if (cp->gss_svc_refcnt > 0) 2754 cp->gss_svc_refcnt--; 2755 else 2756 printf("nfs_gss_ctx_deref: zero refcount\n"); 2757 lck_mtx_unlock(cp->gss_svc_mtx); 2758} 2759 2760/* 2761 * Called at NFS server shutdown - destroy all contexts 2762 */ 2763void 2764nfs_gss_svc_cleanup(void) 2765{ 2766 struct nfs_gss_svc_ctx_hashhead *head; 2767 struct nfs_gss_svc_ctx *cp, *ncp; 2768 int i; 2769 2770 lck_mtx_lock(nfs_gss_svc_ctx_mutex); 2771 2772 /* 2773 * Run through all the buckets 2774 */ 2775 for (i = 0; i < SVC_CTX_HASHSZ; i++) { 2776 /* 2777 * Remove and free all entries in the bucket 2778 */ 2779 head = &nfs_gss_svc_ctx_hashtbl[i]; 2780 LIST_FOREACH_SAFE(cp, head, gss_svc_entries, ncp) { 2781 LIST_REMOVE(cp, gss_svc_entries); 2782 if (cp->gss_svc_seqbits) 2783 FREE(cp->gss_svc_seqbits, M_TEMP); 2784 lck_mtx_destroy(cp->gss_svc_mtx, nfs_gss_svc_grp); 2785 FREE(cp, M_TEMP); 2786 } 2787 } 2788 2789 lck_mtx_unlock(nfs_gss_svc_ctx_mutex); 2790} 2791 2792#endif /* NFSSERVER */ 2793 2794 2795/************* 2796 * The following functions are used by both client and server. 2797 */ 2798 2799/* 2800 * Release a host special port that was obtained by host_get_special_port 2801 * or one of its macros (host_get_gssd_port in this case). 2802 * This really should be in a public kpi. 2803 */ 2804 2805/* This should be in a public header if this routine is not */ 2806extern void ipc_port_release_send(ipc_port_t); 2807extern ipc_port_t ipc_port_copy_send(ipc_port_t); 2808 2809static void 2810host_release_special_port(mach_port_t mp) 2811{ 2812 if (IPC_PORT_VALID(mp)) 2813 ipc_port_release_send(mp); 2814} 2815 2816static mach_port_t 2817host_copy_special_port(mach_port_t mp) 2818{ 2819 return (ipc_port_copy_send(mp)); 2820} 2821 2822/* 2823 * The token that is sent and received in the gssd upcall 2824 * has unbounded variable length. Mach RPC does not pass 2825 * the token in-line. Instead it uses page mapping to handle 2826 * these parameters. This function allocates a VM buffer 2827 * to hold the token for an upcall and copies the token 2828 * (received from the client) into it. The VM buffer is 2829 * marked with a src_destroy flag so that the upcall will 2830 * automatically de-allocate the buffer when the upcall is 2831 * complete. 2832 */ 2833static void 2834nfs_gss_mach_alloc_buffer(u_char *buf, uint32_t buflen, vm_map_copy_t *addr) 2835{ 2836 kern_return_t kr; 2837 vm_offset_t kmem_buf; 2838 vm_size_t tbuflen; 2839 2840 *addr = NULL; 2841 if (buf == NULL || buflen == 0) 2842 return; 2843 2844 tbuflen = round_page(buflen); 2845 kr = vm_allocate(ipc_kernel_map, &kmem_buf, tbuflen, VM_FLAGS_ANYWHERE); 2846 if (kr != 0) { 2847 printf("nfs_gss_mach_alloc_buffer: vm_allocate failed\n"); 2848 return; 2849 } 2850 2851 kr = vm_map_wire(ipc_kernel_map, vm_map_trunc_page(kmem_buf), 2852 vm_map_round_page(kmem_buf + tbuflen), 2853 VM_PROT_READ|VM_PROT_WRITE, FALSE); 2854 if (kr != 0) { 2855 printf("nfs_gss_mach_alloc_buffer: vm_map_wire failed\n"); 2856 return; 2857 } 2858 2859 bcopy(buf, (void *) kmem_buf, buflen); 2860 // Shouldn't need to bzero below since vm_allocate returns zeroed pages 2861 // bzero(kmem_buf + buflen, tbuflen - buflen); 2862 2863 kr = vm_map_unwire(ipc_kernel_map, vm_map_trunc_page(kmem_buf), 2864 vm_map_round_page(kmem_buf + tbuflen), FALSE); 2865 if (kr != 0) { 2866 printf("nfs_gss_mach_alloc_buffer: vm_map_unwire failed\n"); 2867 return; 2868 } 2869 2870 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t) kmem_buf, 2871 (vm_map_size_t) buflen, TRUE, addr); 2872 if (kr != 0) { 2873 printf("nfs_gss_mach_alloc_buffer: vm_map_copyin failed\n"); 2874 return; 2875 } 2876} 2877 2878/* 2879 * Here we handle a token received from the gssd via an upcall. 2880 * The received token resides in an allocate VM buffer. 2881 * We copy the token out of this buffer to a chunk of malloc'ed 2882 * memory of the right size, then de-allocate the VM buffer. 2883 */ 2884static int 2885nfs_gss_mach_vmcopyout(vm_map_copy_t in, uint32_t len, u_char *out) 2886{ 2887 vm_map_offset_t map_data; 2888 vm_offset_t data; 2889 int error; 2890 2891 error = vm_map_copyout(ipc_kernel_map, &map_data, in); 2892 if (error) 2893 return (error); 2894 2895 data = CAST_DOWN(vm_offset_t, map_data); 2896 bcopy((void *) data, out, len); 2897 vm_deallocate(ipc_kernel_map, data, len); 2898 2899 return (0); 2900} 2901 2902/* 2903 * Encode an ASN.1 token to be wrapped in an RPCSEC_GSS verifier. 2904 * Returns the size of the token, since it contains a variable 2905 * length DER encoded size field. 2906 */ 2907static int 2908nfs_gss_token_put( 2909 gss_key_info *ki, 2910 u_char *alg, 2911 u_char *p, 2912 int initiator, 2913 int datalen, 2914 u_char *cksum) 2915{ 2916 static uint32_t seqnum = 0; 2917 u_char *psave = p; 2918 u_char plain[8]; 2919 int toklen, i; 2920 2921 /* 2922 * Fill in the token header: 2 octets. 2923 * This is 0x06 - an ASN.1 tag for APPLICATION, 0, SEQUENCE 2924 * followed by the length of the token: 35 + 0 octets for a 2925 * MIC token, or 35 + encrypted octets for a wrap token; 2926 */ 2927 *p++ = 0x060; 2928 toklen = KRB5_SZ_MECH + KRB5_SZ_ALG + KRB5_SZ_SEQ + HASHLEN(ki); 2929 nfs_gss_der_length_put(&p, toklen + datalen); 2930 2931 /* 2932 * Fill in the DER encoded mech OID for Kerberos v5. 2933 * This represents the Kerberos OID 1.2.840.113554.1.2.2 2934 * described in RFC 2623, section 4.2 2935 */ 2936 bcopy(krb5_mech, p, sizeof(krb5_mech)); 2937 p += sizeof(krb5_mech); 2938 2939 /* 2940 * Now at the token described in RFC 1964, section 1.2.1 2941 * Fill in the token ID, integrity algorithm indicator, 2942 * for DES MAC MD5, and four filler octets. 2943 * The alg string encodes the bytes to represent either 2944 * a MIC token or a WRAP token for Kerberos. 2945 */ 2946 bcopy(alg, p, KRB5_SZ_ALG); 2947 p += KRB5_SZ_ALG; 2948 2949 /* 2950 * Now encode the sequence number according to 2951 * RFC 1964, section 1.2.1.2 which dictates 4 octets 2952 * of sequence number followed by 4 bytes of direction 2953 * indicator: 0x00 for initiator or 0xff for acceptor. 2954 * We DES CBC encrypt the sequence number using the first 2955 * 8 octets of the checksum field as an initialization 2956 * vector. 2957 * Note that this sequence number is not at all related 2958 * to the RPCSEC_GSS protocol sequence number. This 2959 * number is private to the ASN.1 token. The only 2960 * requirement is that it not be repeated in case the 2961 * server has replay detection on, which normally should 2962 * not be the case, since RFC 2203 section 5.2.3 says that 2963 * replay detection and sequence checking must be turned off. 2964 */ 2965 seqnum++; 2966 for (i = 0; i < 4; i++) 2967 plain[i] = (u_char) ((seqnum >> (i * 8)) & 0xff); 2968 for (i = 4; i < 8; i++) 2969 plain[i] = initiator ? 0x00 : 0xff; 2970 gss_des_crypt(ki, (des_cblock *) plain, (des_cblock *) p, 8, 2971 (des_cblock *) cksum, NULL, DES_ENCRYPT, KG_USAGE_SEQ); 2972 p += 8; 2973 2974 /* 2975 * Finally, append the octets of the 2976 * checksum of the alg + plaintext data. 2977 * The plaintext could be an RPC call header, 2978 * the window value, or a sequence number. 2979 */ 2980 bcopy(cksum, p, HASHLEN(ki)); 2981 p += HASHLEN(ki); 2982 2983 return (p - psave); 2984} 2985 2986/* 2987 * Determine size of ASN.1 DER length 2988 */ 2989static int 2990nfs_gss_der_length_size(int len) 2991{ 2992 return 2993 len < (1 << 7) ? 1 : 2994 len < (1 << 8) ? 2 : 2995 len < (1 << 16) ? 3 : 2996 len < (1 << 24) ? 4 : 5; 2997} 2998 2999/* 3000 * Encode an ASN.1 DER length field 3001 */ 3002static void 3003nfs_gss_der_length_put(u_char **pp, int len) 3004{ 3005 int sz = nfs_gss_der_length_size(len); 3006 u_char *p = *pp; 3007 3008 if (sz == 1) { 3009 *p++ = (u_char) len; 3010 } else { 3011 *p++ = (u_char) ((sz-1) | 0x80); 3012 sz -= 1; 3013 while (sz--) 3014 *p++ = (u_char) ((len >> (sz * 8)) & 0xff); 3015 } 3016 3017 *pp = p; 3018} 3019 3020/* 3021 * Decode an ASN.1 DER length field 3022 */ 3023static int 3024nfs_gss_der_length_get(u_char **pp) 3025{ 3026 u_char *p = *pp; 3027 uint32_t flen, len = 0; 3028 3029 flen = *p & 0x7f; 3030 3031 if ((*p++ & 0x80) == 0) 3032 len = flen; 3033 else { 3034 if (flen > sizeof(uint32_t)) 3035 return (-1); 3036 while (flen--) 3037 len = (len << 8) + *p++; 3038 } 3039 *pp = p; 3040 return (len); 3041} 3042 3043/* 3044 * Decode an ASN.1 token from an RPCSEC_GSS verifier. 3045 */ 3046static int 3047nfs_gss_token_get( 3048 gss_key_info *ki, 3049 u_char *alg, 3050 u_char *p, 3051 int initiator, 3052 uint32_t *len, 3053 u_char *cksum) 3054{ 3055 u_char d, plain[8]; 3056 u_char *psave = p; 3057 int seqnum, i; 3058 3059 /* 3060 * Check that we have a valid token header 3061 */ 3062 if (*p++ != 0x60) 3063 return (AUTH_BADCRED); 3064 (void) nfs_gss_der_length_get(&p); // ignore the size 3065 3066 /* 3067 * Check that we have the DER encoded Kerberos v5 mech OID 3068 */ 3069 if (bcmp(p, krb5_mech, sizeof(krb5_mech) != 0)) 3070 return (AUTH_BADCRED); 3071 p += sizeof(krb5_mech); 3072 3073 /* 3074 * Now check the token ID, DES MAC MD5 algorithm 3075 * indicator, and filler octets. 3076 */ 3077 if (bcmp(p, alg, KRB5_SZ_ALG) != 0) 3078 return (AUTH_BADCRED); 3079 p += KRB5_SZ_ALG; 3080 3081 /* 3082 * Now decrypt the sequence number. 3083 * Note that the gss decryption uses the first 8 octets 3084 * of the checksum field as an initialization vector (p + 8). 3085 * Per RFC 2203 section 5.2.2 we don't check the sequence number 3086 * in the ASN.1 token because the RPCSEC_GSS protocol has its 3087 * own sequence number described in section 5.3.3.1 3088 */ 3089 seqnum = 0; 3090 gss_des_crypt(ki, (des_cblock *)p, (des_cblock *) plain, 8, 3091 (des_cblock *) (p + 8), NULL, DES_DECRYPT, KG_USAGE_SEQ); 3092 p += 8; 3093 for (i = 0; i < 4; i++) 3094 seqnum |= plain[i] << (i * 8); 3095 3096 /* 3097 * Make sure the direction 3098 * indicator octets are correct. 3099 */ 3100 d = initiator ? 0x00 : 0xff; 3101 for (i = 4; i < 8; i++) 3102 if (plain[i] != d) 3103 return (AUTH_BADCRED); 3104 3105 /* 3106 * Finally, get the checksum 3107 */ 3108 bcopy(p, cksum, HASHLEN(ki)); 3109 p += HASHLEN(ki); 3110 3111 if (len != NULL) 3112 *len = p - psave; 3113 3114 return (0); 3115} 3116 3117/* 3118 * Return the number of bytes in an mbuf chain. 3119 */ 3120static int 3121nfs_gss_mchain_length(mbuf_t mhead) 3122{ 3123 mbuf_t mb; 3124 int len = 0; 3125 3126 for (mb = mhead; mb; mb = mbuf_next(mb)) 3127 len += mbuf_len(mb); 3128 3129 return (len); 3130} 3131 3132/* 3133 * Append an args or results mbuf chain to the header chain 3134 */ 3135static int 3136nfs_gss_append_chain(struct nfsm_chain *nmc, mbuf_t mc) 3137{ 3138 int error = 0; 3139 mbuf_t mb, tail; 3140 3141 /* Connect the mbuf chains */ 3142 error = mbuf_setnext(nmc->nmc_mcur, mc); 3143 if (error) 3144 return (error); 3145 3146 /* Find the last mbuf in the chain */ 3147 tail = NULL; 3148 for (mb = mc; mb; mb = mbuf_next(mb)) 3149 tail = mb; 3150 3151 nmc->nmc_mcur = tail; 3152 nmc->nmc_ptr = (caddr_t) mbuf_data(tail) + mbuf_len(tail); 3153 nmc->nmc_left = mbuf_trailingspace(tail); 3154 3155 return (0); 3156} 3157 3158/* 3159 * Convert an mbuf chain to an NFS mbuf chain 3160 */ 3161static void 3162nfs_gss_nfsm_chain(struct nfsm_chain *nmc, mbuf_t mc) 3163{ 3164 mbuf_t mb, tail; 3165 3166 /* Find the last mbuf in the chain */ 3167 tail = NULL; 3168 for (mb = mc; mb; mb = mbuf_next(mb)) 3169 tail = mb; 3170 3171 nmc->nmc_mhead = mc; 3172 nmc->nmc_mcur = tail; 3173 nmc->nmc_ptr = (caddr_t) mbuf_data(tail) + mbuf_len(tail); 3174 nmc->nmc_left = mbuf_trailingspace(tail); 3175 nmc->nmc_flags = 0; 3176} 3177 3178 3179/* 3180 * Compute a checksum over an mbuf chain. 3181 * Start building an MD5 digest at the given offset and keep 3182 * going until the end of data in the current mbuf is reached. 3183 * Then convert the 16 byte MD5 digest to an 8 byte DES CBC 3184 * checksum. 3185 */ 3186static void 3187nfs_gss_cksum_mchain( 3188 gss_key_info *ki, 3189 mbuf_t mhead, 3190 u_char *alg, 3191 int offset, 3192 int len, 3193 u_char *digest) 3194{ 3195 mbuf_t mb; 3196 u_char *ptr; 3197 int left, bytes; 3198 GSS_DIGEST_CTX context; 3199 3200 gss_digest_Init(&context, ki); 3201 3202 /* 3203 * Logically prepend the first 8 bytes of the algorithm 3204 * field as required by RFC 1964, section 1.2.1.1 3205 */ 3206 gss_digest_Update(&context, alg, KRB5_SZ_ALG); 3207 3208 /* 3209 * Move down the mbuf chain until we reach the given 3210 * byte offset, then start MD5 on the mbuf data until 3211 * we've done len bytes. 3212 */ 3213 3214 for (mb = mhead; mb && len > 0; mb = mbuf_next(mb)) { 3215 ptr = mbuf_data(mb); 3216 left = mbuf_len(mb); 3217 if (offset >= left) { 3218 /* Offset not yet reached */ 3219 offset -= left; 3220 continue; 3221 } 3222 /* At or beyond offset - checksum data */ 3223 ptr += offset; 3224 left -= offset; 3225 offset = 0; 3226 3227 bytes = left < len ? left : len; 3228 if (bytes > 0) 3229 gss_digest_Update(&context, ptr, bytes); 3230 len -= bytes; 3231 } 3232 3233 gss_digest_Final(&context, digest); 3234} 3235 3236/* 3237 * Compute a checksum over an NFS mbuf chain. 3238 * Start building an MD5 digest at the given offset and keep 3239 * going until the end of data in the current mbuf is reached. 3240 * Then convert the 16 byte MD5 digest to an 8 byte DES CBC 3241 * checksum. 3242 */ 3243static void 3244nfs_gss_cksum_chain( 3245 gss_key_info *ki, 3246 struct nfsm_chain *nmc, 3247 u_char *alg, 3248 int offset, 3249 int len, 3250 u_char *cksum) 3251{ 3252 /* 3253 * If the length parameter is zero, then we need 3254 * to use the length from the offset to the current 3255 * encode/decode offset. 3256 */ 3257 if (len == 0) 3258 len = nfsm_chain_offset(nmc) - offset; 3259 3260 return (nfs_gss_cksum_mchain(ki, nmc->nmc_mhead, alg, offset, len, cksum)); 3261} 3262 3263/* 3264 * Compute a checksum of the sequence number (or sequence window) 3265 * of an RPCSEC_GSS reply. 3266 */ 3267static void 3268nfs_gss_cksum_rep(gss_key_info *ki, uint32_t seqnum, u_char *cksum) 3269{ 3270 GSS_DIGEST_CTX context; 3271 uint32_t val = htonl(seqnum); 3272 3273 gss_digest_Init(&context, ki); 3274 3275 /* 3276 * Logically prepend the first 8 bytes of the MIC 3277 * token as required by RFC 1964, section 1.2.1.1 3278 */ 3279 gss_digest_Update(&context, ALG_MIC(ki), KRB5_SZ_ALG); 3280 3281 /* 3282 * Compute the digest of the seqnum in network order 3283 */ 3284 gss_digest_Update(&context, &val, 4); 3285 gss_digest_Final(&context, cksum); 3286} 3287 3288/* 3289 * Encrypt or decrypt data in an mbuf chain with des-cbc. 3290 */ 3291static void 3292nfs_gss_encrypt_mchain( 3293 gss_key_info *ki, 3294 mbuf_t mhead, 3295 int offset, 3296 int len, 3297 int encrypt) 3298{ 3299 mbuf_t mb, mbn; 3300 u_char *ptr, *nptr; 3301 u_char tmp[8], ivec[8]; 3302 int left, left8, remain; 3303 3304 3305 bzero(ivec, 8); 3306 3307 /* 3308 * Move down the mbuf chain until we reach the given 3309 * byte offset, then start encrypting the mbuf data until 3310 * we've done len bytes. 3311 */ 3312 3313 for (mb = mhead; mb && len > 0; mb = mbn) { 3314 mbn = mbuf_next(mb); 3315 ptr = mbuf_data(mb); 3316 left = mbuf_len(mb); 3317 if (offset >= left) { 3318 /* Offset not yet reached */ 3319 offset -= left; 3320 continue; 3321 } 3322 /* At or beyond offset - encrypt data */ 3323 ptr += offset; 3324 left -= offset; 3325 offset = 0; 3326 3327 /* 3328 * DES or DES3 CBC has to encrypt 8 bytes at a time. 3329 * If the number of bytes to be encrypted in this 3330 * mbuf isn't some multiple of 8 bytes, encrypt all 3331 * the 8 byte blocks, then combine the remaining 3332 * bytes with enough from the next mbuf to make up 3333 * an 8 byte block and encrypt that block separately, 3334 * i.e. that block is split across two mbufs. 3335 */ 3336 remain = left % 8; 3337 left8 = left - remain; 3338 left = left8 < len ? left8 : len; 3339 if (left > 0) { 3340 gss_des_crypt(ki, (des_cblock *) ptr, (des_cblock *) ptr, 3341 left, &ivec, &ivec, encrypt, KG_USAGE_SEAL); 3342 len -= left; 3343 } 3344 3345 if (mbn && remain > 0) { 3346 nptr = mbuf_data(mbn); 3347 offset = 8 - remain; 3348 bcopy(ptr + left, tmp, remain); // grab from this mbuf 3349 bcopy(nptr, tmp + remain, offset); // grab from next mbuf 3350 gss_des_crypt(ki, (des_cblock *) tmp, (des_cblock *) tmp, 8, 3351 &ivec, &ivec, encrypt, KG_USAGE_SEAL); 3352 bcopy(tmp, ptr + left, remain); // return to this mbuf 3353 bcopy(tmp + remain, nptr, offset); // return to next mbuf 3354 len -= 8; 3355 } 3356 } 3357} 3358 3359/* 3360 * Encrypt or decrypt data in an NFS mbuf chain with des-cbc. 3361 */ 3362static void 3363nfs_gss_encrypt_chain( 3364 gss_key_info *ki, 3365 struct nfsm_chain *nmc, 3366 int offset, 3367 int len, 3368 int encrypt) 3369{ 3370 /* 3371 * If the length parameter is zero, then we need 3372 * to use the length from the offset to the current 3373 * encode/decode offset. 3374 */ 3375 if (len == 0) 3376 len = nfsm_chain_offset(nmc) - offset; 3377 3378 return (nfs_gss_encrypt_mchain(ki, nmc->nmc_mhead, offset, len, encrypt)); 3379} 3380 3381/* 3382 * The routines that follow provide abstractions for doing digests and crypto. 3383 */ 3384 3385static void 3386gss_digest_Init(GSS_DIGEST_CTX *ctx, gss_key_info *ki) 3387{ 3388 ctx->type = ki->type; 3389 switch (ki->type) { 3390 case NFS_GSS_1DES: MD5_DESCBC_Init(&ctx->m_ctx, &ki->ks_u.des.gss_sched); 3391 break; 3392 case NFS_GSS_3DES: HMAC_SHA1_DES3KD_Init(&ctx->h_ctx, ki->ks_u.des3.ckey, 0); 3393 break; 3394 default: 3395 printf("gss_digest_Init: Unknown key info type %d\n", ki->type); 3396 } 3397} 3398 3399static void 3400gss_digest_Update(GSS_DIGEST_CTX *ctx, void *data, size_t len) 3401{ 3402 switch (ctx->type) { 3403 case NFS_GSS_1DES: MD5_DESCBC_Update(&ctx->m_ctx, data, len); 3404 break; 3405 case NFS_GSS_3DES: HMAC_SHA1_DES3KD_Update(&ctx->h_ctx, data, len); 3406 break; 3407 } 3408} 3409 3410static void 3411gss_digest_Final(GSS_DIGEST_CTX *ctx, void *digest) 3412{ 3413 switch (ctx->type) { 3414 case NFS_GSS_1DES: MD5_DESCBC_Final(digest, &ctx->m_ctx); 3415 break; 3416 case NFS_GSS_3DES: HMAC_SHA1_DES3KD_Final(digest, &ctx->h_ctx); 3417 break; 3418 } 3419} 3420 3421static void 3422gss_des_crypt(gss_key_info *ki, des_cblock *in, des_cblock *out, 3423 int32_t len, des_cblock *iv, des_cblock *retiv, int encrypt, int usage) 3424{ 3425 switch (ki->type) { 3426 case NFS_GSS_1DES: 3427 { 3428 des_cbc_key_schedule *sched = ((usage == KG_USAGE_SEAL) ? 3429 &ki->ks_u.des.gss_sched_Ke : 3430 &ki->ks_u.des.gss_sched); 3431 des_cbc_encrypt(in, out, len, sched, iv, retiv, encrypt); 3432 } 3433 break; 3434 case NFS_GSS_3DES: 3435 3436 des3_cbc_encrypt(in, out, len, &ki->ks_u.des3.gss_sched, iv, retiv, encrypt); 3437 break; 3438 } 3439} 3440 3441static int 3442gss_key_init(gss_key_info *ki, uint32_t skeylen) 3443{ 3444 size_t i; 3445 int rc; 3446 des_cblock k[3]; 3447 3448 ki->keybytes = skeylen; 3449 switch (skeylen) { 3450 case sizeof(des_cblock): 3451 ki->type = NFS_GSS_1DES; 3452 ki->hash_len = MD5_DESCBC_DIGEST_LENGTH; 3453 ki->ks_u.des.key = (des_cblock *)ki->skey; 3454 rc = des_cbc_key_sched(ki->ks_u.des.key, &ki->ks_u.des.gss_sched); 3455 if (rc) 3456 return (rc); 3457 for (i = 0; i < ki->keybytes; i++) 3458 k[0][i] = 0xf0 ^ (*ki->ks_u.des.key)[i]; 3459 rc = des_cbc_key_sched(&k[0], &ki->ks_u.des.gss_sched_Ke); 3460 break; 3461 case 3*sizeof(des_cblock): 3462 ki->type = NFS_GSS_3DES; 3463 ki->hash_len = SHA_DIGEST_LENGTH; 3464 ki->ks_u.des3.key = (des_cblock (*)[3])ki->skey; 3465 des3_derive_key(*ki->ks_u.des3.key, ki->ks_u.des3.ckey, 3466 KEY_USAGE_DES3_SIGN, KEY_USAGE_LEN); 3467 rc = des3_cbc_key_sched(*ki->ks_u.des3.key, &ki->ks_u.des3.gss_sched); 3468 if (rc) 3469 return (rc); 3470 break; 3471 default: 3472 printf("gss_key_init: Invalid key length %d\n", skeylen); 3473 rc = EINVAL; 3474 break; 3475 } 3476 3477 return (rc); 3478} 3479 3480#if 0 3481#define DISPLAYLEN 16 3482#define MAXDISPLAYLEN 256 3483 3484static void 3485hexdump(const char *msg, void *data, size_t len) 3486{ 3487 size_t i, j; 3488 u_char *d = data; 3489 char *p, disbuf[3*DISPLAYLEN+1]; 3490 3491 printf("NFS DEBUG %s len=%d:\n", msg, (uint32_t)len); 3492 if (len > MAXDISPLAYLEN) 3493 len = MAXDISPLAYLEN; 3494 3495 for (i = 0; i < len; i += DISPLAYLEN) { 3496 for (p = disbuf, j = 0; (j + i) < len && j < DISPLAYLEN; j++, p += 3) 3497 snprintf(p, 4, "%02x ", d[i + j]); 3498 printf("\t%s\n", disbuf); 3499 } 3500} 3501#endif 3502