Path: blob/main/crypto/krb5/src/lib/rpc/auth_gssapi.c
39536 views
/*1* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.2*3*/45#include <stdio.h>6#include <string.h>7#include <sys/errno.h>89#include <gssapi/gssapi.h>10#include <gssapi/gssapi_generic.h>11#ifdef GSSAPI_KRB512#include <gssapi/gssapi_krb5.h>13#endif1415#include <gssrpc/rpc.h>16#include <gssrpc/auth_gssapi.h>1718#include "gssrpcint.h"1920#ifdef __CODECENTER__21#define DEBUG_GSSAPI 122#endif2324#ifdef DEBUG_GSSAPI25int auth_debug_gssapi = DEBUG_GSSAPI;26extern void gssrpcint_printf(const char *format, ...);27#define L_PRINTF(l,args) if (auth_debug_gssapi >= l) gssrpcint_printf args28#define PRINTF(args) L_PRINTF(99, args)29#define AUTH_GSSAPI_DISPLAY_STATUS(args) \30if (auth_debug_gssapi) auth_gssapi_display_status args31#else32#define PRINTF(args)33#define L_PRINTF(l, args)34#define AUTH_GSSAPI_DISPLAY_STATUS(args)35#endif3637static void auth_gssapi_nextverf(AUTH *);38static bool_t auth_gssapi_marshall(AUTH *, XDR *);39static bool_t auth_gssapi_validate(AUTH *, struct opaque_auth *);40static bool_t auth_gssapi_refresh(AUTH *, struct rpc_msg *);41static bool_t auth_gssapi_wrap(AUTH *, XDR *, xdrproc_t, caddr_t);42static bool_t auth_gssapi_unwrap(AUTH *, XDR *, xdrproc_t, caddr_t);43static void auth_gssapi_destroy(AUTH *);4445static bool_t marshall_new_creds(AUTH *, bool_t, gss_buffer_t);4647static struct auth_ops auth_gssapi_ops = {48auth_gssapi_nextverf,49auth_gssapi_marshall,50auth_gssapi_validate,51auth_gssapi_refresh,52auth_gssapi_destroy,53auth_gssapi_wrap,54auth_gssapi_unwrap,55};5657/*58* the ah_private data structure for an auth_handle59*/60struct auth_gssapi_data {61bool_t established;62CLIENT *clnt;63gss_ctx_id_t context;64gss_buffer_desc client_handle;65uint32_t seq_num;66int def_cred;6768/* pre-serialized ah_cred */69unsigned char cred_buf[MAX_AUTH_BYTES];70uint32_t cred_len;71};72#define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)7374/*75* Function: auth_gssapi_create_default76*77* Purpose: Create a GSS-API style authenticator, with default78* options, and return the handle.79*80* Effects: See design document, section XXX.81*/82AUTH *auth_gssapi_create_default(CLIENT *clnt, char *service_name)83{84AUTH *auth;85OM_uint32 gssstat, minor_stat;86gss_buffer_desc input_name;87gss_name_t target_name;8889input_name.value = service_name;90input_name.length = strlen(service_name) + 1;9192gssstat = gss_import_name(&minor_stat, &input_name,93gss_nt_service_name, &target_name);94if (gssstat != GSS_S_COMPLETE) {95AUTH_GSSAPI_DISPLAY_STATUS(("parsing name", gssstat,96minor_stat));97rpc_createerr.cf_stat = RPC_SYSTEMERROR;98rpc_createerr.cf_error.re_errno = ENOMEM;99return NULL;100}101102auth = auth_gssapi_create(clnt,103&gssstat,104&minor_stat,105GSS_C_NO_CREDENTIAL,106target_name,107GSS_C_NULL_OID,108GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG,1090,110NULL,111NULL,112NULL);113114gss_release_name(&minor_stat, &target_name);115return auth;116}117118/*119* Function: auth_gssapi_create120*121* Purpose: Create a GSS-API style authenticator, with all the122* options, and return the handle.123*124* Effects: See design document, section XXX.125*/126AUTH *auth_gssapi_create(127CLIENT *clnt,128OM_uint32 *gssstat,129OM_uint32 *minor_stat,130gss_cred_id_t claimant_cred_handle,131gss_name_t target_name,132gss_OID mech_type,133OM_uint32 req_flags,134OM_uint32 time_req,135gss_OID *actual_mech_type,136OM_uint32 *ret_flags,137OM_uint32 *time_rec)138{139AUTH *auth, *save_auth;140struct auth_gssapi_data *pdata;141struct gss_channel_bindings_struct bindings, *bindp;142struct sockaddr_in laddr, raddr;143enum clnt_stat callstat;144struct timeval timeout;145int bindings_failed;146rpcproc_t init_func;147148auth_gssapi_init_arg call_arg;149auth_gssapi_init_res call_res;150gss_buffer_desc *input_token, isn_buf;151152memset(&rpc_createerr, 0, sizeof(rpc_createerr));153154/* this timeout is only used if clnt_control(clnt, CLSET_TIMEOUT) */155/* has not already been called.. therefore, we can just pick */156/* something reasonable-sounding.. */157timeout.tv_sec = 30;158timeout.tv_usec = 0;159160auth = NULL;161pdata = NULL;162163/* don't assume the caller will want to change clnt->cl_auth */164save_auth = clnt->cl_auth;165166auth = (AUTH *) malloc(sizeof(*auth));167pdata = (struct auth_gssapi_data *) malloc(sizeof(*pdata));168if (auth == NULL || pdata == NULL) {169/* They needn't both have failed; clean up. */170free(auth);171free(pdata);172auth = NULL;173pdata = NULL;174rpc_createerr.cf_stat = RPC_SYSTEMERROR;175rpc_createerr.cf_error.re_errno = ENOMEM;176goto cleanup;177}178memset(auth, 0, sizeof(*auth));179memset(pdata, 0, sizeof(*pdata));180181auth->ah_ops = &auth_gssapi_ops;182auth->ah_private = (caddr_t) pdata;183184/* initial creds are auth_msg TRUE and no handle */185marshall_new_creds(auth, TRUE, NULL);186187/* initial verifier is empty */188auth->ah_verf.oa_flavor = AUTH_GSSAPI;189auth->ah_verf.oa_base = NULL;190auth->ah_verf.oa_length = 0;191192AUTH_PRIVATE(auth)->established = FALSE;193AUTH_PRIVATE(auth)->clnt = clnt;194AUTH_PRIVATE(auth)->def_cred = (claimant_cred_handle ==195GSS_C_NO_CREDENTIAL);196197clnt->cl_auth = auth;198199/* start by trying latest version */200call_arg.version = 4;201bindings_failed = 0;202203try_new_version:204/* set state for initial call to init_sec_context */205input_token = GSS_C_NO_BUFFER;206AUTH_PRIVATE(auth)->context = GSS_C_NO_CONTEXT;207init_func = AUTH_GSSAPI_INIT;208209#ifdef GSSAPI_KRB5210/*211* OV servers up to version 3 used the old mech id. Beta 7212* servers used version 3 with the new mech id; however, the beta213* 7 gss-api accept_sec_context accepts either mech id. Thus, if214* any server rejects version 4, we fall back to version 3 with215* the old mech id; for the OV server it will be right, and for216* the beta 7 server it will be accepted. Not ideal, but it217* works.218*/219if (call_arg.version < 4 && (mech_type == gss_mech_krb5 ||220mech_type == GSS_C_NULL_OID))221mech_type = (gss_OID) gss_mech_krb5_old;222#endif223224if (!bindings_failed && call_arg.version >= 3) {225if (clnt_control(clnt, CLGET_LOCAL_ADDR, &laddr) == FALSE) {226PRINTF(("gssapi_create: CLGET_LOCAL_ADDR failed"));227goto cleanup;228}229if (clnt_control(clnt, CLGET_SERVER_ADDR, &raddr) == FALSE) {230PRINTF(("gssapi_create: CLGET_SERVER_ADDR failed"));231goto cleanup;232}233234memset(&bindings, 0, sizeof(bindings));235bindings.application_data.length = 0;236bindings.initiator_addrtype = GSS_C_AF_INET;237bindings.initiator_address.length = 4;238bindings.initiator_address.value = &laddr.sin_addr.s_addr;239240bindings.acceptor_addrtype = GSS_C_AF_INET;241bindings.acceptor_address.length = 4;242bindings.acceptor_address.value = &raddr.sin_addr.s_addr;243bindp = &bindings;244} else {245bindp = NULL;246}247248memset(&call_res, 0, sizeof(call_res));249250next_token:251*gssstat = gss_init_sec_context(minor_stat,252claimant_cred_handle,253&AUTH_PRIVATE(auth)->context,254target_name,255mech_type,256req_flags,257time_req,258bindp,259input_token,260actual_mech_type,261&call_arg.token,262ret_flags,263time_rec);264265if (*gssstat != GSS_S_COMPLETE && *gssstat != GSS_S_CONTINUE_NEEDED) {266AUTH_GSSAPI_DISPLAY_STATUS(("initializing context", *gssstat,267*minor_stat));268goto cleanup;269}270271/* if we got a token, pass it on */272if (call_arg.token.length != 0) {273274/*275* sanity check: if we received a signed isn in the last276* response then there *cannot* be another token to send277*/278if (call_res.signed_isn.length != 0) {279PRINTF(("gssapi_create: unexpected token from init_sec\n"));280goto cleanup;281}282283PRINTF(("gssapi_create: calling GSSAPI_INIT (%d)\n", init_func));284285xdr_free((xdrproc_t)xdr_authgssapi_init_res, &call_res);286memset(&call_res, 0, sizeof(call_res));287callstat = clnt_call(clnt, init_func,288(xdrproc_t)xdr_authgssapi_init_arg, &call_arg,289(xdrproc_t)xdr_authgssapi_init_res, &call_res,290timeout);291gss_release_buffer(minor_stat, &call_arg.token);292293if (callstat != RPC_SUCCESS) {294struct rpc_err err;295296clnt_geterr(clnt, &err);297if (callstat == RPC_AUTHERROR &&298(err.re_why == AUTH_BADCRED || err.re_why == AUTH_FAILED)299&& call_arg.version >= 1) {300L_PRINTF(1,301("call_arg protocol version %d rejected, trying %d.\n",302call_arg.version, call_arg.version-1));303call_arg.version--;304goto try_new_version;305} else {306PRINTF(("gssapi_create: GSSAPI_INIT (%d) failed, stat %d\n",307init_func, callstat));308}309310goto cleanup;311} else if (call_res.version != call_arg.version &&312!(call_arg.version == 2 && call_res.version == 1)) {313/*314* The Secure 1.1 servers always respond with version315* 1. Thus, if we just tried a version >=3, fall all316* the way back to version 1 since that is all they317* understand318*/319if (call_arg.version > 2 && call_res.version == 1) {320L_PRINTF(1,321("Talking to Secure 1.1 server, using version 1.\n"));322call_arg.version = 1;323goto try_new_version;324}325326PRINTF(("gssapi_create: invalid call_res vers %d\n",327call_res.version));328goto cleanup;329} else if (call_res.gss_major != GSS_S_COMPLETE) {330AUTH_GSSAPI_DISPLAY_STATUS(("in response from server",331call_res.gss_major,332call_res.gss_minor));333goto cleanup;334}335336PRINTF(("gssapi_create: GSSAPI_INIT (%d) succeeded\n", init_func));337init_func = AUTH_GSSAPI_CONTINUE_INIT;338339/* check for client_handle */340if (AUTH_PRIVATE(auth)->client_handle.length == 0) {341if (call_res.client_handle.length == 0) {342PRINTF(("gssapi_create: expected client_handle\n"));343goto cleanup;344} else {345PRINTF(("gssapi_create: got client_handle %d\n",346*((uint32_t *)call_res.client_handle.value)));347348GSS_DUP_BUFFER(AUTH_PRIVATE(auth)->client_handle,349call_res.client_handle);350351/* auth_msg is TRUE; there may be more tokens */352marshall_new_creds(auth, TRUE,353&AUTH_PRIVATE(auth)->client_handle);354}355} else if (!GSS_BUFFERS_EQUAL(AUTH_PRIVATE(auth)->client_handle,356call_res.client_handle)) {357PRINTF(("gssapi_create: got different client_handle\n"));358goto cleanup;359}360361/* check for token */362if (call_res.token.length==0 && *gssstat==GSS_S_CONTINUE_NEEDED) {363PRINTF(("gssapi_create: expected token\n"));364goto cleanup;365} else if (call_res.token.length != 0) {366if (*gssstat == GSS_S_COMPLETE) {367PRINTF(("gssapi_create: got unexpected token\n"));368goto cleanup;369} else {370/* assumes call_res is safe until init_sec_context */371input_token = &call_res.token;372PRINTF(("gssapi_create: got new token\n"));373}374}375}376377/* check for isn */378if (*gssstat == GSS_S_COMPLETE) {379if (call_res.signed_isn.length == 0) {380PRINTF(("gssapi_created: expected signed isn\n"));381goto cleanup;382} else {383PRINTF(("gssapi_create: processing signed isn\n"));384385/* don't check conf (integ only) or qop (accept default) */386*gssstat = gss_unseal(minor_stat,387AUTH_PRIVATE(auth)->context,388&call_res.signed_isn,389&isn_buf, NULL, NULL);390391if (*gssstat != GSS_S_COMPLETE) {392AUTH_GSSAPI_DISPLAY_STATUS(("unsealing isn",393*gssstat, *minor_stat));394goto cleanup;395} else if (isn_buf.length != sizeof(uint32_t)) {396PRINTF(("gssapi_create: gss_unseal gave %d bytes\n",397(int) isn_buf.length));398goto cleanup;399}400401AUTH_PRIVATE(auth)->seq_num = (uint32_t)402ntohl(*((uint32_t*)isn_buf.value));403*gssstat = gss_release_buffer(minor_stat, &isn_buf);404if (*gssstat != GSS_S_COMPLETE) {405AUTH_GSSAPI_DISPLAY_STATUS(("releasing unsealed isn",406*gssstat, *minor_stat));407goto cleanup;408}409410PRINTF(("gssapi_create: isn is %d\n",411AUTH_PRIVATE(auth)->seq_num));412}413} else if (call_res.signed_isn.length != 0) {414PRINTF(("gssapi_create: got signed isn, can't check yet\n"));415}416417/* results were okay.. continue if necessary */418if (*gssstat == GSS_S_CONTINUE_NEEDED) {419PRINTF(("gssapi_create: not done, continuing\n"));420goto next_token;421}422423/*424* Done! Context is established, we have client_handle and isn.425*/426AUTH_PRIVATE(auth)->established = TRUE;427428marshall_new_creds(auth, FALSE,429&AUTH_PRIVATE(auth)->client_handle);430431PRINTF(("gssapi_create: done. client_handle %#x, isn %d\n\n",432*((uint32_t *)AUTH_PRIVATE(auth)->client_handle.value),433AUTH_PRIVATE(auth)->seq_num));434435/* don't assume the caller will want to change clnt->cl_auth */436clnt->cl_auth = save_auth;437438xdr_free((xdrproc_t)xdr_authgssapi_init_res, &call_res);439return auth;440441/******************************************************************/442443cleanup:444PRINTF(("gssapi_create: bailing\n\n"));445446if (auth) {447if (AUTH_PRIVATE(auth))448auth_gssapi_destroy(auth);449else450free(auth);451auth = NULL;452}453454/* don't assume the caller will want to change clnt->cl_auth */455clnt->cl_auth = save_auth;456457if (rpc_createerr.cf_stat == 0)458rpc_createerr.cf_stat = RPC_AUTHERROR;459460xdr_free((xdrproc_t)xdr_authgssapi_init_res, &call_res);461return auth;462}463464/*465* Function: marshall_new_creds466*467* Purpose: (pre-)serialize auth_msg and client_handle fields of468* auth_gssapi_creds into auth->cred_buf469*470* Arguments:471*472* auth (r/w) the AUTH structure to modify473* auth_msg (r) the auth_msg field to serialize474* client_handle (r) the client_handle field to serialize, or475* NULL476*477* Returns: TRUE if successful, FALSE if not478*479* Requires: auth must point to a valid GSS-API auth structure, auth_msg480* must be TRUE or FALSE, client_handle must be a gss_buffer_t with a valid481* value and length field or NULL.482*483* Effects: auth->ah_cred is set to the serialized auth_gssapi_creds484* version 2 structure (stored in the cred_buf field of private data)485* containing version, auth_msg and client_handle.486* auth->ah_cred.oa_flavor is set to AUTH_GSSAPI. If cliend_handle is487* NULL, it is treated as if it had a length of 0 and a value of NULL.488*489* Modifies: auth490*/491static bool_t marshall_new_creds(492AUTH *auth,493bool_t auth_msg,494gss_buffer_t client_handle)495{496auth_gssapi_creds creds;497XDR xdrs;498499PRINTF(("marshall_new_creds: starting\n"));500501creds.version = 2;502503creds.auth_msg = auth_msg;504if (client_handle)505GSS_COPY_BUFFER(creds.client_handle, *client_handle)506else {507creds.client_handle.length = 0;508creds.client_handle.value = NULL;509}510511xdrmem_create(&xdrs, (caddr_t) AUTH_PRIVATE(auth)->cred_buf,512MAX_AUTH_BYTES, XDR_ENCODE);513if (! xdr_authgssapi_creds(&xdrs, &creds)) {514PRINTF(("marshall_new_creds: failed encoding auth_gssapi_creds\n"));515XDR_DESTROY(&xdrs);516return FALSE;517}518AUTH_PRIVATE(auth)->cred_len = xdr_getpos(&xdrs);519XDR_DESTROY(&xdrs);520521PRINTF(("marshall_new_creds: auth_gssapi_creds is %d bytes\n",522AUTH_PRIVATE(auth)->cred_len));523524auth->ah_cred.oa_flavor = AUTH_GSSAPI;525auth->ah_cred.oa_base = (char *) AUTH_PRIVATE(auth)->cred_buf;526auth->ah_cred.oa_length = AUTH_PRIVATE(auth)->cred_len;527528PRINTF(("marshall_new_creds: succeeding\n"));529530return TRUE;531}532533534/*535* Function: auth_gssapi_nextverf536*537* Purpose: None.538*539* Effects: None. Never called.540*/541static void auth_gssapi_nextverf(AUTH *auth)542{543}544545/*546* Function: auth_gssapi_marhsall547*548* Purpose: Marshall RPC credentials and verifier onto xdr stream.549*550* Arguments:551*552* auth (r/w) AUTH structure for client553* xdrs (r/w) XDR stream to marshall to554*555* Returns: boolean indicating success/failure556*557* Effects:558*559* The pre-serialized credentials in cred_buf are serialized. If the560* context is established, the sealed sequence number is serialized as561* the verifier. If the context is not established, an empty verifier562* is serialized. The sequence number is *not* incremented, because563* this function is called multiple times if retransmission is required.564*565* If this took all the header fields as arguments, it could sign566* them.567*/568static bool_t auth_gssapi_marshall(569AUTH *auth,570XDR *xdrs)571{572OM_uint32 minor_stat;573gss_buffer_desc out_buf;574uint32_t seq_num;575576if (AUTH_PRIVATE(auth)->established == TRUE) {577PRINTF(("gssapi_marshall: starting\n"));578579seq_num = AUTH_PRIVATE(auth)->seq_num + 1;580581PRINTF(("gssapi_marshall: sending seq_num %d\n", seq_num));582583if (auth_gssapi_seal_seq(AUTH_PRIVATE(auth)->context, seq_num,584&out_buf) == FALSE) {585PRINTF(("gssapi_marhshall: seal failed\n"));586}587588auth->ah_verf.oa_base = out_buf.value;589auth->ah_verf.oa_length = out_buf.length;590591if (! xdr_opaque_auth(xdrs, &auth->ah_cred) ||592! xdr_opaque_auth(xdrs, &auth->ah_verf)) {593(void) gss_release_buffer(&minor_stat, &out_buf);594return FALSE;595}596(void) gss_release_buffer(&minor_stat, &out_buf);597} else {598PRINTF(("gssapi_marshall: not established, sending null verf\n"));599600auth->ah_verf.oa_base = NULL;601auth->ah_verf.oa_length = 0;602603if (! xdr_opaque_auth(xdrs, &auth->ah_cred) ||604! xdr_opaque_auth(xdrs, &auth->ah_verf)) {605return FALSE;606}607}608609return TRUE;610}611612/*613* Function: auth_gssapi_validate614*615* Purpose: Validate RPC response verifier from server.616*617* Effects: See design document, section XXX.618*/619static bool_t auth_gssapi_validate(620AUTH *auth,621struct opaque_auth *verf)622{623gss_buffer_desc in_buf;624uint32_t seq_num;625626if (AUTH_PRIVATE(auth)->established == FALSE) {627PRINTF(("gssapi_validate: not established, noop\n"));628return TRUE;629}630631PRINTF(("gssapi_validate: starting\n"));632633in_buf.length = verf->oa_length;634in_buf.value = verf->oa_base;635if (auth_gssapi_unseal_seq(AUTH_PRIVATE(auth)->context, &in_buf,636&seq_num) == FALSE) {637PRINTF(("gssapi_validate: failed unsealing verifier\n"));638return FALSE;639}640641/* we sent seq_num+1, so we should get back seq_num+2 */642if (AUTH_PRIVATE(auth)->seq_num+2 != seq_num) {643PRINTF(("gssapi_validate: expecting seq_num %d, got %d (%#x)\n",644AUTH_PRIVATE(auth)->seq_num + 2, seq_num, seq_num));645return FALSE;646}647PRINTF(("gssapi_validate: seq_num %d okay\n", seq_num));648649/* +1 for successful transmission, +1 for successful validation */650AUTH_PRIVATE(auth)->seq_num += 2;651652PRINTF(("gssapi_validate: succeeding\n"));653654return TRUE;655}656657/*658* Function: auth_gssapi_refresh659*660* Purpose: Attempts to resyncrhonize the sequence number.661*662* Effects:663*664* When the server receives a properly authenticated RPC call, it665* increments the sequence number it is expecting from the client.666* But if the server's response is lost for any reason, the client667* can't know whether the server ever received it, assumes it didn't,668* and does *not* increment its sequence number. Thus, the client's669* next call will fail with AUTH_REJECTEDCRED because the server will670* think it is a replay attack.671*672* When an AUTH_REJECTEDCRED error arrives, this function attempts to673* resyncrhonize by incrementing the client's sequence number and674* returning TRUE. If any other error arrives, it returns FALSE.675*/676static bool_t auth_gssapi_refresh(677AUTH *auth,678struct rpc_msg *msg)679{680if (msg->rm_reply.rp_rjct.rj_stat == AUTH_ERROR &&681msg->rm_reply.rp_rjct.rj_why == AUTH_REJECTEDVERF) {682PRINTF(("gssapi_refresh: rejected verifier, incrementing\n"));683AUTH_PRIVATE(auth)->seq_num++;684return TRUE;685} else {686PRINTF(("gssapi_refresh: failing\n"));687return FALSE;688}689}690691/*692* Function: auth_gssapi_destroy693*694* Purpose: Destroy a GSS-API authentication structure.695*696* Effects: This function destroys the GSS-API authentication697* context, and sends a message to the server instructing it to698* invokte gss_process_token() and thereby destroy its corresponding699* context. Since the client doesn't really care whether the server700* gets this message, no failures are reported.701*/702static void auth_gssapi_destroy(AUTH *auth)703{704struct timeval timeout;705OM_uint32 gssstat, minor_stat;706gss_cred_id_t cred;707int callstat;708709if (AUTH_PRIVATE(auth)->client_handle.length == 0) {710PRINTF(("gssapi_destroy: no client_handle, not calling destroy\n"));711goto skip_call;712}713714PRINTF(("gssapi_destroy: marshalling new creds\n"));715if (!marshall_new_creds(auth, TRUE, &AUTH_PRIVATE(auth)->client_handle)) {716PRINTF(("gssapi_destroy: marshall_new_creds failed\n"));717goto skip_call;718}719720PRINTF(("gssapi_destroy: calling GSSAPI_DESTROY\n"));721timeout.tv_sec = 1;722timeout.tv_usec = 0;723callstat = clnt_call(AUTH_PRIVATE(auth)->clnt, AUTH_GSSAPI_DESTROY,724xdr_void, NULL, xdr_void, NULL, timeout);725if (callstat != RPC_SUCCESS)726clnt_sperror(AUTH_PRIVATE(auth)->clnt,727"gssapi_destroy: GSSAPI_DESTROY failed");728729skip_call:730PRINTF(("gssapi_destroy: deleting context\n"));731gssstat = gss_delete_sec_context(&minor_stat,732&AUTH_PRIVATE(auth)->context,733NULL);734if (gssstat != GSS_S_COMPLETE)735AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat,736minor_stat));737if (AUTH_PRIVATE(auth)->def_cred) {738cred = GSS_C_NO_CREDENTIAL;739gssstat = gss_release_cred(&minor_stat, &cred);740if (gssstat != GSS_S_COMPLETE)741AUTH_GSSAPI_DISPLAY_STATUS(("deleting default credential",742gssstat, minor_stat));743}744745free(AUTH_PRIVATE(auth)->client_handle.value);746free(auth->ah_private);747free(auth);748PRINTF(("gssapi_destroy: done\n"));749}750751/*752* Function: auth_gssapi_wrap753*754* Purpose: encrypt the serialized arguments from xdr_func applied to755* xdr_ptr and write the result to xdrs.756*757* Effects: See design doc, section XXX.758*/759static bool_t auth_gssapi_wrap(760AUTH *auth,761XDR *out_xdrs,762xdrproc_t xdr_func,763caddr_t xdr_ptr)764{765OM_uint32 gssstat, minor_stat;766767if (! AUTH_PRIVATE(auth)->established) {768PRINTF(("gssapi_wrap: context not established, noop\n"));769return (*xdr_func)(out_xdrs, xdr_ptr);770} else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat,771AUTH_PRIVATE(auth)->context,772AUTH_PRIVATE(auth)->seq_num+1,773out_xdrs, xdr_func, xdr_ptr)) {774if (gssstat != GSS_S_COMPLETE)775AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments",776gssstat, minor_stat));777return FALSE;778} else779return TRUE;780}781782/*783* Function: auth_gssapi_unwrap784*785* Purpose: read encrypted arguments from xdrs, decrypt, and786* deserialize with xdr_func into xdr_ptr.787*788* Effects: See design doc, section XXX.789*/790static bool_t auth_gssapi_unwrap(791AUTH *auth,792XDR *in_xdrs,793xdrproc_t xdr_func,794caddr_t xdr_ptr)795{796OM_uint32 gssstat, minor_stat;797798if (! AUTH_PRIVATE(auth)->established) {799PRINTF(("gssapi_unwrap: context not established, noop\n"));800return (*xdr_func)(in_xdrs, xdr_ptr);801} else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat,802AUTH_PRIVATE(auth)->context,803AUTH_PRIVATE(auth)->seq_num,804in_xdrs, xdr_func, xdr_ptr)) {805if (gssstat != GSS_S_COMPLETE)806AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments",807gssstat, minor_stat));808return FALSE;809} else810return TRUE;811}812813814