Merge commit '06307114472bd8aad5ff18ccdb8e25f128ae6652'
[unleashed.git] / usr / src / lib / rpcsec_gss / rpcsec_gss.c
blobcee55fa0eb01209755eb2e7bc6d517d183e98261
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
30 * $Header:
31 * /afs/gza.com/product/secure/rel-eng/src/1.1/rpc/RCS/auth_gssapi.c,v
32 * 1.14 1995/03/22 22:07:55 jik Exp $
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <strings.h>
38 #include <errno.h>
39 #include <pthread.h>
40 #include <thread.h>
41 #include <syslog.h>
42 #include <gssapi/gssapi.h>
43 #include <rpc/rpc.h>
44 #include <rpc/rpcsec_defs.h>
46 static void rpc_gss_nextverf();
47 static bool_t rpc_gss_marshall();
48 static bool_t rpc_gss_validate();
49 static bool_t rpc_gss_refresh();
50 static void rpc_gss_destroy();
51 static void rpc_gss_destroy_pvt();
52 static bool_t rpc_gss_seccreate_pvt();
53 static bool_t validate_seqwin();
56 * Globals that should have header files but don't.
58 extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
61 static struct auth_ops rpc_gss_ops = {
62 rpc_gss_nextverf,
63 rpc_gss_marshall,
64 rpc_gss_validate,
65 rpc_gss_refresh,
66 rpc_gss_destroy
70 * Private data for RPCSEC_GSS.
72 typedef struct _rpc_gss_data {
73 bool_t established; /* TRUE when established */
74 CLIENT *clnt; /* associated client handle */
75 uint_t version; /* RPCSEC version */
76 gss_ctx_id_t context; /* GSS context id */
77 gss_buffer_desc ctx_handle; /* RPCSEC context handle */
78 uint_t seq_num; /* last sequence number rcvd */
79 gss_cred_id_t my_cred; /* GSS credentials */
80 OM_uint32 qop; /* requested QOP */
81 rpc_gss_service_t service; /* requested service */
82 uint_t gss_proc; /* GSS control procedure */
83 gss_name_t target_name; /* target server */
84 int req_flags; /* GSS request bits */
85 gss_OID mech_type; /* GSS mechanism */
86 OM_uint32 time_req; /* requested cred lifetime */
87 bool_t invalid; /* can't use this any more */
88 OM_uint32 seq_window; /* server sequence window */
89 struct opaque_auth *verifier; /* rpc reply verifier saved for */
90 /* validating the sequence window */
91 gss_channel_bindings_t icb;
92 } rpc_gss_data;
93 #define AUTH_PRIVATE(auth) ((rpc_gss_data *)auth->ah_private)
96 * Create a context.
98 AUTH *
99 __rpc_gss_seccreate(clnt, server_name, mech, service, qop, options_req,
100 options_ret)
101 CLIENT *clnt; /* associated client handle */
102 char *server_name; /* target server */
103 char *mech; /* security mechanism */
104 rpc_gss_service_t service; /* security service */
105 char *qop; /* requested QOP */
106 rpc_gss_options_req_t *options_req; /* requested options */
107 rpc_gss_options_ret_t *options_ret; /* returned options */
109 OM_uint32 gssstat;
110 OM_uint32 minor_stat;
111 gss_name_t target_name;
112 gss_OID mech_type;
113 OM_uint32 ret_flags;
114 OM_uint32 time_rec;
115 gss_buffer_desc input_name;
116 AUTH *auth = NULL;
117 rpc_gss_data *ap = NULL;
118 OM_uint32 qop_num;
121 * convert ascii strings to GSS values
123 if (!__rpc_gss_qop_to_num(qop, mech, &qop_num)) {
124 return (NULL);
127 if (!__rpc_gss_mech_to_oid(mech, &mech_type)) {
128 return (NULL);
132 * convert name to GSS internal type
134 input_name.value = server_name;
135 input_name.length = strlen(server_name);
136 gssstat = gss_import_name(&minor_stat, &input_name,
137 (gss_OID)GSS_C_NT_HOSTBASED_SERVICE,
138 &target_name);
139 if (gssstat != GSS_S_COMPLETE) {
140 rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
141 rpc_gss_err.system_error = ENOMEM;
142 return (NULL);
146 * Create AUTH handle. Save the necessary interface information
147 * so that the client can refresh the handle later if needed.
149 if ((auth = (AUTH *) malloc(sizeof (*auth))) != NULL)
150 ap = (rpc_gss_data *) malloc(sizeof (*ap));
151 if (auth == NULL || ap == NULL) {
152 rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
153 rpc_gss_err.system_error = ENOMEM;
154 if (auth != NULL)
155 free((char *)auth);
156 (void) gss_release_name(&minor_stat, &target_name);
157 return (NULL);
160 memset((char *)ap, 0, sizeof (*ap));
161 ap->clnt = clnt;
162 ap->version = RPCSEC_GSS_VERSION;
163 if (options_req != NULL) {
164 ap->my_cred = options_req->my_cred;
165 ap->req_flags = options_req->req_flags;
166 ap->time_req = options_req->time_req;
167 ap->icb = options_req->input_channel_bindings;
168 } else {
169 ap->my_cred = GSS_C_NO_CREDENTIAL;
170 ap->req_flags = GSS_C_MUTUAL_FLAG;
171 ap->time_req = 0;
172 ap->icb = NULL;
174 if ((ap->service = service) == rpc_gss_svc_default)
175 ap->service = rpc_gss_svc_integrity;
176 ap->qop = qop_num;
177 ap->target_name = target_name;
178 ap->mech_type = mech_type;
181 * Now invoke the real interface that sets up the context from
182 * the information stashed away in the private data.
184 if (!rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap,
185 &mech_type, &ret_flags, &time_rec)) {
186 if (ap->target_name)
187 (void) gss_release_name(&minor_stat, &ap->target_name);
188 free((char *)ap);
189 free((char *)auth);
190 return (NULL);
194 * Make sure that the requested service is supported. In all
195 * cases, integrity service must be available.
197 if ((ap->service == rpc_gss_svc_privacy &&
198 !(ret_flags & GSS_C_CONF_FLAG)) ||
199 !(ret_flags & GSS_C_INTEG_FLAG)) {
200 rpc_gss_destroy(auth);
201 rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
202 rpc_gss_err.system_error = EPROTONOSUPPORT;
203 return (NULL);
207 * return option values if requested
209 if (options_ret != NULL) {
210 char *s;
212 options_ret->major_status = gssstat;
213 options_ret->minor_status = minor_stat;
214 options_ret->rpcsec_version = ap->version;
215 options_ret->ret_flags = ret_flags;
216 options_ret->time_ret = time_rec;
217 options_ret->gss_context = ap->context;
218 if ((s = __rpc_gss_oid_to_mech(mech_type)) != NULL)
219 strcpy(options_ret->actual_mechanism, s);
220 else
221 options_ret->actual_mechanism[0] = '\0';
223 return (auth);
227 * Private interface to create a context. This is the interface
228 * that's invoked when the context has to be refreshed.
230 static bool_t
231 rpc_gss_seccreate_pvt(gssstat, minor_stat, auth, ap, actual_mech_type,
232 ret_flags, time_rec)
233 OM_uint32 *gssstat;
234 OM_uint32 *minor_stat;
235 AUTH *auth;
236 rpc_gss_data *ap;
237 gss_OID *actual_mech_type;
238 OM_uint32 *ret_flags;
239 OM_uint32 *time_rec;
241 CLIENT *clnt = ap->clnt;
242 AUTH *save_auth;
243 enum clnt_stat callstat;
244 rpc_gss_init_arg call_arg;
245 rpc_gss_init_res call_res;
246 gss_buffer_desc *input_token_p, input_token;
247 bool_t free_results = FALSE;
250 * initialize error
252 memset(&rpc_createerr, 0, sizeof (rpc_createerr));
255 * (re)initialize AUTH handle and private data.
257 memset((char *)auth, 0, sizeof (*auth));
258 auth->ah_ops = &rpc_gss_ops;
259 auth->ah_private = (caddr_t)ap;
260 auth->ah_cred.oa_flavor = RPCSEC_GSS;
262 ap->established = FALSE;
263 ap->ctx_handle.length = 0;
264 ap->ctx_handle.value = NULL;
265 ap->context = GSS_C_NO_CONTEXT;
266 ap->seq_num = 0;
267 ap->gss_proc = RPCSEC_GSS_INIT;
270 * should not change clnt->cl_auth at this time, so save
271 * old handle
273 save_auth = clnt->cl_auth;
274 clnt->cl_auth = auth;
277 * set state for starting context setup
279 input_token_p = GSS_C_NO_BUFFER;
281 next_token:
282 *gssstat = gss_init_sec_context(minor_stat,
283 ap->my_cred,
284 &ap->context,
285 ap->target_name,
286 ap->mech_type,
287 ap->req_flags,
288 ap->time_req,
289 NULL,
290 input_token_p,
291 actual_mech_type,
292 &call_arg,
293 ret_flags,
294 time_rec);
296 if (input_token_p != GSS_C_NO_BUFFER) {
297 OM_uint32 minor_stat2;
299 (void) gss_release_buffer(&minor_stat2, input_token_p);
300 input_token_p = GSS_C_NO_BUFFER;
303 if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {
305 goto cleanup;
309 * if we got a token, pass it on
311 if (call_arg.length != 0) {
312 struct timeval timeout = {30, 0};
314 memset((char *)&call_res, 0, sizeof (call_res));
315 callstat = clnt_call(clnt, NULLPROC,
316 __xdr_rpc_gss_init_arg, (caddr_t)&call_arg,
317 __xdr_rpc_gss_init_res, (caddr_t)&call_res,
318 timeout);
319 (void) gss_release_buffer(minor_stat, &call_arg);
321 if (callstat != RPC_SUCCESS) {
322 goto cleanup;
325 * we have results - note that these need to be freed
327 free_results = TRUE;
329 if (call_res.gss_major != GSS_S_COMPLETE &&
330 call_res.gss_major != GSS_S_CONTINUE_NEEDED)
331 goto cleanup;
333 ap->gss_proc = RPCSEC_GSS_CONTINUE_INIT;
336 * check for ctx_handle
338 if (ap->ctx_handle.length == 0) {
339 if (call_res.ctx_handle.length == 0)
340 goto cleanup;
341 GSS_DUP_BUFFER(ap->ctx_handle,
342 call_res.ctx_handle);
343 } else if (!GSS_BUFFERS_EQUAL(ap->ctx_handle,
344 call_res.ctx_handle))
345 goto cleanup;
348 * check for token
350 if (call_res.token.length != 0) {
351 if (*gssstat == GSS_S_COMPLETE)
352 goto cleanup;
353 GSS_DUP_BUFFER(input_token, call_res.token);
354 input_token_p = &input_token;
356 } else if (*gssstat != GSS_S_COMPLETE)
357 goto cleanup;
359 /* save the sequence window value; validate later */
360 ap->seq_window = call_res.seq_window;
361 xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
362 free_results = FALSE;
366 * results were okay.. continue if necessary
368 if (*gssstat == GSS_S_CONTINUE_NEEDED)
369 goto next_token;
372 * Validate the sequence window - RFC 2203 section 5.2.3.1
374 if (!validate_seqwin(ap)) {
375 goto cleanup;
379 * Done! Security context creation is successful.
380 * Ready for exchanging data.
382 ap->established = TRUE;
383 ap->seq_num = 1;
384 ap->gss_proc = RPCSEC_GSS_DATA;
385 ap->invalid = FALSE;
387 clnt->cl_auth = save_auth; /* restore cl_auth */
388 return (TRUE);
390 cleanup:
391 if (ap->context != GSS_C_NO_CONTEXT)
392 rpc_gss_destroy_pvt(auth);
393 if (free_results)
394 xdr_free(__xdr_rpc_gss_init_res, (caddr_t)&call_res);
395 clnt->cl_auth = save_auth; /* restore cl_auth */
398 * if (rpc_createerr.cf_stat == 0)
399 * rpc_createerr.cf_stat = RPC_AUTHERROR;
401 if (rpc_createerr.cf_stat == 0) {
402 rpc_gss_err.rpc_gss_error = RPC_GSS_ER_SYSTEMERROR;
403 rpc_gss_err.system_error = RPC_AUTHERROR;
406 return (FALSE);
410 * Set service defaults.
412 bool_t
413 __rpc_gss_set_defaults(auth, service, qop)
414 AUTH *auth;
415 rpc_gss_service_t service;
416 char *qop;
418 /*LINTED*/
419 rpc_gss_data *ap = AUTH_PRIVATE(auth);
420 char *mech;
421 OM_uint32 qop_num;
423 switch (service) {
424 case rpc_gss_svc_integrity:
425 case rpc_gss_svc_privacy:
426 case rpc_gss_svc_none:
427 break;
428 case rpc_gss_svc_default:
429 service = rpc_gss_svc_integrity;
430 break;
431 default:
432 return (FALSE);
435 if ((mech = __rpc_gss_oid_to_mech(ap->mech_type)) == NULL)
436 return (FALSE);
438 if (!__rpc_gss_qop_to_num(qop, mech, &qop_num))
439 return (FALSE);
441 ap->qop = qop_num;
442 ap->service = service;
443 return (TRUE);
447 * Marshall credentials.
449 static bool_t
450 marshall_creds(ap, xdrs)
451 rpc_gss_data *ap;
452 XDR *xdrs;
454 rpc_gss_creds ag_creds;
455 char cred_buf[MAX_AUTH_BYTES];
456 struct opaque_auth creds;
457 XDR cred_xdrs;
459 ag_creds.version = ap->version;
460 ag_creds.gss_proc = ap->gss_proc;
461 ag_creds.seq_num = ap->seq_num;
462 ag_creds.service = ap->service;
465 * If context has not been set up yet, use NULL handle.
467 if (ap->ctx_handle.length > 0)
468 ag_creds.ctx_handle = ap->ctx_handle;
469 else {
470 ag_creds.ctx_handle.length = 0;
471 ag_creds.ctx_handle.value = NULL;
474 xdrmem_create(&cred_xdrs, (caddr_t)cred_buf, MAX_AUTH_BYTES,
475 XDR_ENCODE);
476 if (!__xdr_rpc_gss_creds(&cred_xdrs, &ag_creds)) {
477 XDR_DESTROY(&cred_xdrs);
478 return (FALSE);
481 creds.oa_flavor = RPCSEC_GSS;
482 creds.oa_base = cred_buf;
483 creds.oa_length = xdr_getpos(&cred_xdrs);
484 XDR_DESTROY(&cred_xdrs);
486 if (!xdr_opaque_auth(xdrs, &creds))
487 return (FALSE);
489 return (TRUE);
493 * Marshall verifier. The verifier is the checksum of the RPC header
494 * up to and including the credential field. The XDR handle that's
495 * passed in has the header up to and including the credential field
496 * encoded. A pointer to the transmit buffer is also passed in.
498 static bool_t
499 marshall_verf(ap, xdrs, buf)
500 rpc_gss_data *ap;
501 XDR *xdrs; /* send XDR */
502 char *buf; /* pointer of send buffer */
504 struct opaque_auth verf;
505 OM_uint32 major, minor;
506 gss_buffer_desc in_buf, out_buf;
507 bool_t ret = FALSE;
510 * If context is not established yet, use NULL verifier.
512 if (!ap->established) {
513 verf.oa_flavor = AUTH_NONE;
514 verf.oa_base = NULL;
515 verf.oa_length = 0;
516 return (xdr_opaque_auth(xdrs, &verf));
519 verf.oa_flavor = RPCSEC_GSS;
520 in_buf.length = xdr_getpos(xdrs);
521 in_buf.value = buf;
522 if ((major = gss_sign(&minor, ap->context, ap->qop, &in_buf,
523 &out_buf)) != GSS_S_COMPLETE) {
524 if (major == GSS_S_CONTEXT_EXPIRED) {
525 ap->invalid = TRUE;
527 return (FALSE);
529 verf.oa_base = out_buf.value;
530 verf.oa_length = out_buf.length;
531 ret = xdr_opaque_auth(xdrs, &verf);
532 (void) gss_release_buffer(&minor, &out_buf);
534 return (ret);
538 * Function: rpc_gss_nextverf. Not used.
540 static void
541 rpc_gss_nextverf()
546 * Function: rpc_gss_marshall - not used.
548 static bool_t
549 rpc_gss_marshall(auth, xdrs)
550 AUTH *auth;
551 XDR *xdrs;
553 if (!xdr_opaque_auth(xdrs, &auth->ah_cred) ||
554 !xdr_opaque_auth(xdrs, &auth->ah_verf))
555 return (FALSE);
556 return (TRUE);
560 * Validate sequence window upon a successful RPCSEC_GSS INIT session.
561 * The sequence window sent back by the server should be verifiable by
562 * the verifier which is a checksum of the sequence window.
564 static bool_t
565 validate_seqwin(rpc_gss_data *ap)
567 uint_t seq_win_net;
568 OM_uint32 major = 0, minor = 0;
569 gss_buffer_desc msg_buf, tok_buf;
570 int qop_state = 0;
572 seq_win_net = (uint_t)htonl(ap->seq_window);
573 msg_buf.length = sizeof (seq_win_net);
574 msg_buf.value = (char *)&seq_win_net;
575 tok_buf.length = ap->verifier->oa_length;
576 tok_buf.value = ap->verifier->oa_base;
577 major = gss_verify(&minor, ap->context, &msg_buf, &tok_buf, &qop_state);
578 if (major != GSS_S_COMPLETE)
579 return (FALSE);
580 return (TRUE);
584 * Validate RPC response verifier from server. The response verifier
585 * is the checksum of the request sequence number.
587 static bool_t
588 rpc_gss_validate(auth, verf)
589 AUTH *auth;
590 struct opaque_auth *verf;
592 /*LINTED*/
593 rpc_gss_data *ap = AUTH_PRIVATE(auth);
594 uint_t seq_num_net;
595 OM_uint32 major, minor;
596 gss_buffer_desc msg_buf, tok_buf;
597 int qop_state;
600 * If context is not established yet, save the verifier for
601 * validating the sequence window later at the end of context
602 * creation session.
604 if (!ap->established) {
605 if (ap->verifier == NULL) {
606 ap->verifier = malloc(sizeof (struct opaque_auth));
607 memset(ap->verifier, 0, sizeof (struct opaque_auth));
608 if (verf->oa_length > 0)
609 ap->verifier->oa_base = malloc(verf->oa_length);
610 } else {
611 if (ap->verifier->oa_length > 0)
612 free(ap->verifier->oa_base);
613 if (verf->oa_length > 0)
614 ap->verifier->oa_base = malloc(verf->oa_length);
616 ap->verifier->oa_length = verf->oa_length;
617 bcopy(verf->oa_base, ap->verifier->oa_base, verf->oa_length);
618 return (TRUE);
621 seq_num_net = (uint_t)htonl(ap->seq_num);
622 msg_buf.length = sizeof (seq_num_net);
623 msg_buf.value = (char *)&seq_num_net;
624 tok_buf.length = verf->oa_length;
625 tok_buf.value = verf->oa_base;
626 major = gss_verify(&minor, ap->context, &msg_buf, &tok_buf, &qop_state);
627 if (major != GSS_S_COMPLETE)
628 return (FALSE);
629 return (TRUE);
633 * Refresh client context. This is necessary sometimes because the
634 * server will ocassionally destroy contexts based on LRU method, or
635 * because of expired credentials.
637 static bool_t
638 rpc_gss_refresh(auth, msg)
639 AUTH *auth;
640 struct rpc_msg *msg;
642 /*LINTED*/
643 rpc_gss_data *ap = AUTH_PRIVATE(auth);
644 OM_uint32 gssstat, minor_stat;
647 * The context needs to be recreated only when the error status
648 * returned from the server is one of the following:
649 * RPCSEC_GSS_NOCRED and RPCSEC_GSS_FAILED
650 * The existing context should not be destroyed unless the above
651 * error status codes are received or if the context has not
652 * been set up.
655 if (msg->rjcted_rply.rj_why == RPCSEC_GSS_NOCRED ||
656 msg->rjcted_rply.rj_why == RPCSEC_GSS_FAILED ||
657 !ap->established) {
659 * Destroy the context if necessary. Use the same memory
660 * for the new context since we've already passed a pointer
661 * to it to the user.
663 if (ap->context != GSS_C_NO_CONTEXT) {
664 (void) gss_delete_sec_context(&minor_stat, &ap->context,
665 NULL);
666 ap->context = GSS_C_NO_CONTEXT;
668 if (ap->ctx_handle.length != 0) {
669 (void) gss_release_buffer(&minor_stat,
670 &ap->ctx_handle);
671 ap->ctx_handle.length = 0;
672 ap->ctx_handle.value = NULL;
676 * If the context was not already established, don't try to
677 * recreate it.
679 if (!ap->established) {
680 ap->invalid = TRUE;
681 return (FALSE);
685 * Recreate context.
687 if (rpc_gss_seccreate_pvt(&gssstat, &minor_stat, auth, ap,
688 (gss_OID *)0, (OM_uint32 *)0, (OM_uint32 *)0))
689 return (TRUE);
690 else {
691 ap->invalid = TRUE;
692 return (FALSE);
695 return (FALSE);
699 * Destroy a context.
701 static void
702 rpc_gss_destroy(auth)
703 AUTH *auth;
705 /*LINTED*/
706 rpc_gss_data *ap = AUTH_PRIVATE(auth);
708 rpc_gss_destroy_pvt(auth);
709 free((char *)ap);
710 free(auth);
714 * Private interface to destroy a context without freeing up
715 * the memory used by it. We need to do this when a refresh
716 * fails, for example, so the user will still have a handle.
718 static void
719 rpc_gss_destroy_pvt(auth)
720 AUTH *auth;
722 struct timeval timeout;
723 OM_uint32 minor_stat;
724 /*LINTED*/
725 rpc_gss_data *ap = AUTH_PRIVATE(auth);
728 * If we have a server context id, inform server that we are
729 * destroying the context.
731 if (ap->ctx_handle.length != 0) {
732 ap->gss_proc = RPCSEC_GSS_DESTROY;
733 timeout.tv_sec = 1;
734 timeout.tv_usec = 0;
735 (void) clnt_call(ap->clnt, NULLPROC, xdr_void, NULL,
736 xdr_void, NULL, timeout);
738 (void) gss_release_buffer(&minor_stat, &ap->ctx_handle);
739 ap->ctx_handle.length = 0;
740 ap->ctx_handle.value = NULL;
744 * Destroy local GSS context.
746 if (ap->context != GSS_C_NO_CONTEXT) {
747 (void) gss_delete_sec_context(&minor_stat, &ap->context, NULL);
748 ap->context = GSS_C_NO_CONTEXT;
752 * Looks like we need to release default credentials if we use it.
753 * Non-default creds need to be released by user.
755 if (ap->my_cred == GSS_C_NO_CREDENTIAL)
756 (void) gss_release_cred(&minor_stat, &ap->my_cred);
759 * Release any internal name structures.
761 if (ap->target_name != NULL) {
762 (void) gss_release_name(&minor_stat, &ap->target_name);
763 ap->target_name = NULL;
767 * Free the verifier saved for sequence window checking.
769 if (ap->verifier != NULL) {
770 if (ap->verifier->oa_length > 0)
771 free(ap->verifier->oa_base);
772 free(ap->verifier);
773 ap->verifier = NULL;
778 * Wrap client side data. The encoded header is passed in through
779 * buf and buflen. The header is up to but not including the
780 * credential field.
782 bool_t
783 __rpc_gss_wrap(auth, buf, buflen, out_xdrs, xdr_func, xdr_ptr)
784 AUTH *auth;
785 char *buf; /* encoded header */
786 uint_t buflen; /* encoded header length */
787 XDR *out_xdrs;
788 bool_t (*xdr_func)();
789 caddr_t xdr_ptr;
791 /*LINTED*/
792 rpc_gss_data *ap = AUTH_PRIVATE(auth);
793 XDR xdrs;
794 char tmp_buf[512];
798 * Reject an invalid context.
800 if (ap->invalid)
801 return (FALSE);
804 * If context is established, bump up sequence number.
806 if (ap->established)
807 ap->seq_num++;
810 * Create the header in a temporary XDR context and buffer
811 * before putting it out.
813 xdrmem_create(&xdrs, tmp_buf, sizeof (tmp_buf), XDR_ENCODE);
814 if (!XDR_PUTBYTES(&xdrs, buf, buflen))
815 return (FALSE);
818 * create cred field
820 if (!marshall_creds(ap, &xdrs))
821 return (FALSE);
824 * create verifier
826 if (!marshall_verf(ap, &xdrs, tmp_buf))
827 return (FALSE);
830 * write out header and destroy temp structures
832 if (!XDR_PUTBYTES(out_xdrs, tmp_buf, XDR_GETPOS(&xdrs)))
833 return (FALSE);
834 XDR_DESTROY(&xdrs);
837 * If context is not established, or if neither integrity
838 * nor privacy is used, just XDR encode data.
840 if (!ap->established || ap->service == rpc_gss_svc_none)
841 return ((*xdr_func)(out_xdrs, xdr_ptr));
843 return (__rpc_gss_wrap_data(ap->service, ap->qop, ap->context,
844 ap->seq_num, out_xdrs, xdr_func, xdr_ptr));
848 * Unwrap received data.
850 bool_t
851 __rpc_gss_unwrap(auth, in_xdrs, xdr_func, xdr_ptr)
852 AUTH *auth;
853 XDR *in_xdrs;
854 bool_t (*xdr_func)();
855 caddr_t xdr_ptr;
857 /*LINTED*/
858 rpc_gss_data *ap = AUTH_PRIVATE(auth);
861 * If context is not established, of if neither integrity
862 * nor privacy is used, just XDR encode data.
864 if (!ap->established || ap->service == rpc_gss_svc_none)
865 return ((*xdr_func)(in_xdrs, xdr_ptr));
867 return (__rpc_gss_unwrap_data(ap->service,
868 ap->context,
869 ap->seq_num,
870 ap->qop,
871 in_xdrs, xdr_func, xdr_ptr));
875 __rpc_gss_max_data_length(auth, max_tp_unit_len)
876 AUTH *auth;
877 int max_tp_unit_len;
879 /*LINTED*/
880 rpc_gss_data *ap = AUTH_PRIVATE(auth);
882 if (!ap->established || max_tp_unit_len <= 0)
883 return (0);
885 return (__find_max_data_length(ap->service,
886 ap->context,
887 ap->qop,
888 max_tp_unit_len));
891 void
892 __rpc_gss_get_error(rpc_gss_error_t *error)
894 *error = rpc_gss_err;
897 #undef rpc_gss_err
899 rpc_gss_error_t rpc_gss_err;
901 rpc_gss_error_t *
902 __rpc_gss_err()
904 static thread_key_t rpc_gss_err_key = THR_ONCE_KEY;
905 rpc_gss_error_t *tsd;
907 if (thr_main())
908 return (&rpc_gss_err);
909 if (thr_keycreate_once(&rpc_gss_err_key, free) != 0)
910 return (&rpc_gss_err);
911 tsd = pthread_getspecific(rpc_gss_err_key);
912 if (tsd == NULL) {
913 tsd = (rpc_gss_error_t *)calloc(1, sizeof (rpc_gss_error_t));
914 if (thr_setspecific(rpc_gss_err_key, tsd) != 0) {
915 free(tsd);
916 return (&rpc_gss_err);
919 return (tsd);