/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * Copyright 2012 Milan Jurik. All rights reserved. */ /* * GSSAPI library stub module for gssd. */ #include #include "gssd_prot.h" #include #include #include #include #include #include #include #ifdef GSSDEBUG /* * Kernel kgssd module debugging aid. The global variable "gss_log" * is a bit mask which allows various types of debugging messages * to be printed out. * * gss_log & 1 will cause actual failures to be printed. * gss_log & 2 will cause informational messages to be * printed on the client side of kgssd. * gss_log & 4 will cause informational messages to be * printed on the server side of kgssd. * gss_log & 8 will cause informational messages to be * printed on both client and server side of kgssd. */ uint_t gss_log = 1; #endif /* GSSDEBUG */ #ifdef DEBUG extern void prom_printf(const char *, ...); #endif char *server = "localhost"; static OM_uint32 kgss_sign_wrapped(void *, OM_uint32 *, gss_ctx_id_t, int, gss_buffer_t, gss_buffer_t, OM_uint32); static OM_uint32 kgss_verify_wrapped(void *, OM_uint32 *, gss_ctx_id_t, gss_buffer_t, gss_buffer_t, int *qop_state, OM_uint32); static OM_uint32 kgss_seal_wrapped(void *, OM_uint32 *, gss_ctx_id_t, int, int, gss_buffer_t, int *, gss_buffer_t, OM_uint32); static OM_uint32 kgss_unseal_wrapped(void *, OM_uint32 *, gss_ctx_id_t, gss_buffer_t, gss_buffer_t, int *conf_state, int *qop_state, OM_uint32); static OM_uint32 kgss_delete_sec_context_wrapped(void *, OM_uint32 *, gssd_ctx_id_t *, gss_buffer_t, OM_uint32); static void __kgss_reset_mech(gss_mechanism *, gss_OID); #define DEFAULT_MINOR_STAT ((OM_uint32) ~0) OM_uint32 kgss_acquire_cred_wrapped(minor_status, desired_name, time_req, desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec, uid, gssd_cred_verifier) OM_uint32 *minor_status; const gss_name_t desired_name; OM_uint32 time_req; const gss_OID_set desired_mechs; int cred_usage; gssd_cred_id_t *output_cred_handle; gss_OID_set *actual_mechs; OM_uint32 *time_rec; uid_t uid; OM_uint32 *gssd_cred_verifier; { CLIENT *clnt; OM_uint32 minor_status_temp; gss_buffer_desc external_name; gss_OID name_type; enum clnt_stat client_stat; int i; gss_acquire_cred_arg arg; gss_acquire_cred_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_acquire_cred: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* convert the desired name from internal to external format */ if (gss_display_name(&minor_status_temp, desired_name, &external_name, &name_type) != GSS_S_COMPLETE) { *minor_status = (OM_uint32) minor_status_temp; killgssd_handle(clnt); GSSLOG0(1, "kgss_acquire_cred: display name failed\n"); return ((OM_uint32) GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32) uid; arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length; arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value; arg.name_type.GSS_OID_len = name_type == GSS_C_NULL_OID ? 0 : (uint_t)name_type->length; arg.name_type.GSS_OID_val = name_type == GSS_C_NULL_OID ? (char *)NULL : (char *)name_type->elements; arg.time_req = time_req; if (desired_mechs != GSS_C_NULL_OID_SET) { arg.desired_mechs.GSS_OID_SET_len = (uint_t)desired_mechs->count; arg.desired_mechs.GSS_OID_SET_val = (GSS_OID *) MALLOC(sizeof (GSS_OID) * desired_mechs->count); for (i = 0; i < desired_mechs->count; i++) { arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len = (uint_t)desired_mechs->elements[i].length; arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val = (char *)MALLOC(desired_mechs->elements[i].length); (void) memcpy( arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val, desired_mechs->elements[i].elements, desired_mechs->elements[i].length); } } else arg.desired_mechs.GSS_OID_SET_len = 0; arg.cred_usage = cred_usage; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); client_stat = gss_acquire_cred_1(&arg, &res, clnt); (void) gss_release_buffer(&minor_status_temp, &external_name); if (desired_mechs != GSS_C_NULL_OID_SET) { for (i = 0; i < desired_mechs->count; i++) FREE(arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_val, arg.desired_mechs.GSS_OID_SET_val[i].GSS_OID_len); FREE(arg.desired_mechs.GSS_OID_SET_val, arg.desired_mechs.GSS_OID_SET_len * sizeof (GSS_OID)); } if (client_stat != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, * set minor_status to its maximum value, and return * GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (output_cred_handle != NULL) *output_cred_handle = 0; if (actual_mechs != NULL) *actual_mechs = NULL; if (time_rec != NULL) *time_rec = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_acquire_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (output_cred_handle != NULL && (res.status == GSS_S_COMPLETE)) { *output_cred_handle = *((gssd_cred_id_t *)res.output_cred_handle.GSS_CRED_ID_T_val); *gssd_cred_verifier = res.gssd_cred_verifier; } if (res.status == GSS_S_COMPLETE && res.actual_mechs.GSS_OID_SET_len != 0 && actual_mechs != NULL) { *actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); (*actual_mechs)->count = (int)res.actual_mechs.GSS_OID_SET_len; (*actual_mechs)->elements = (gss_OID) MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count); for (i = 0; i < (*actual_mechs)->count; i++) { (*actual_mechs)->elements[i].length = (OM_uint32) res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len; (*actual_mechs)->elements[i].elements = (void *) MALLOC((*actual_mechs)->elements[i].length); (void) memcpy((*actual_mechs)->elements[i].elements, res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val, (*actual_mechs)->elements[i].length); } } else { if (res.status == GSS_S_COMPLETE && actual_mechs != NULL) (*actual_mechs) = NULL; } if (time_rec != NULL) *time_rec = res.time_rec; /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_acquire_cred_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_acquire_cred(minor_status, desired_name, time_req, desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec, uid) OM_uint32 *minor_status; const gss_name_t desired_name; OM_uint32 time_req; const gss_OID_set desired_mechs; int cred_usage; gss_cred_id_t *output_cred_handle; gss_OID_set *actual_mechs; OM_uint32 *time_rec; uid_t uid; { OM_uint32 err; struct kgss_cred *kcred; kcred = KGSS_CRED_ALLOC(); *output_cred_handle = (gss_cred_id_t)kcred; err = kgss_acquire_cred_wrapped(minor_status, desired_name, time_req, desired_mechs, cred_usage, &kcred->gssd_cred, actual_mechs, time_rec, uid, &kcred->gssd_cred_verifier); if (GSS_ERROR(err)) { KGSS_CRED_FREE(kcred); *output_cred_handle = GSS_C_NO_CREDENTIAL; } return (err); } OM_uint32 kgss_add_cred_wrapped(minor_status, input_cred_handle, gssd_cred_verifier, desired_name, desired_mech_type, cred_usage, initiator_time_req, acceptor_time_req, actual_mechs, initiator_time_rec, acceptor_time_rec, uid) OM_uint32 *minor_status; gssd_cred_id_t input_cred_handle; OM_uint32 gssd_cred_verifier; gss_name_t desired_name; gss_OID desired_mech_type; int cred_usage; int initiator_time_req; int acceptor_time_req; gss_OID_set *actual_mechs; OM_uint32 *initiator_time_rec; OM_uint32 *acceptor_time_rec; uid_t uid; { CLIENT *clnt; OM_uint32 minor_status_temp; gss_buffer_desc external_name; gss_OID name_type; int i; gss_add_cred_arg arg; gss_add_cred_res res; /* * NULL the params here once * If there are errors then we won't * have to do it for every error * case */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (actual_mechs != NULL) *actual_mechs = NULL; if (initiator_time_rec != NULL) *initiator_time_rec = 0; if (acceptor_time_rec != NULL) *acceptor_time_rec = 0; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_add_cred: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* convert the desired name from internal to external format */ if (gss_display_name(&minor_status_temp, desired_name, &external_name, &name_type) != GSS_S_COMPLETE) { *minor_status = (OM_uint32) minor_status_temp; killgssd_handle(clnt); GSSLOG0(1, "kgss_acquire_cred: display name failed\n"); return ((OM_uint32) GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32)uid; arg.input_cred_handle.GSS_CRED_ID_T_len = input_cred_handle == GSSD_NO_CREDENTIAL ? 0 : (uint_t)sizeof (gssd_cred_id_t); arg.input_cred_handle.GSS_CRED_ID_T_val = (char *)&input_cred_handle; arg.gssd_cred_verifier = gssd_cred_verifier; arg.desired_name.GSS_BUFFER_T_len = (uint_t)external_name.length; arg.desired_name.GSS_BUFFER_T_val = (char *)external_name.value; arg.name_type.GSS_OID_len = name_type == GSS_C_NULL_OID ? 0 : (uint_t)name_type->length; arg.name_type.GSS_OID_val = name_type == GSS_C_NULL_OID ? (char *)NULL : (char *)name_type->elements; arg.desired_mech_type.GSS_OID_len = (uint_t)(desired_mech_type != GSS_C_NULL_OID ? desired_mech_type->length : 0); arg.desired_mech_type.GSS_OID_val = (char *)(desired_mech_type != GSS_C_NULL_OID ? desired_mech_type->elements : 0); arg.cred_usage = cred_usage; arg.initiator_time_req = initiator_time_req; arg.acceptor_time_req = acceptor_time_req; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_add_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, * set minor_status to its maximum value, and return * GSS_S_FAILURE */ killgssd_handle(clnt); (void) gss_release_buffer(&minor_status_temp, &external_name); GSSLOG0(1, "kgss_add_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* free the allocated memory for the flattened name */ (void) gss_release_buffer(&minor_status_temp, &external_name); /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (res.status == GSS_S_COMPLETE && res.actual_mechs.GSS_OID_SET_len != 0 && actual_mechs != NULL) { *actual_mechs = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); (*actual_mechs)->count = (int)res.actual_mechs.GSS_OID_SET_len; (*actual_mechs)->elements = (gss_OID) MALLOC(sizeof (gss_OID_desc) * (*actual_mechs)->count); for (i = 0; i < (*actual_mechs)->count; i++) { (*actual_mechs)->elements[i].length = (OM_uint32) res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_len; (*actual_mechs)->elements[i].elements = (void *) MALLOC((*actual_mechs)->elements[i].length); (void) memcpy((*actual_mechs)->elements[i].elements, res.actual_mechs.GSS_OID_SET_val[i].GSS_OID_val, (*actual_mechs)->elements[i].length); } } else { if (res.status == GSS_S_COMPLETE && actual_mechs != NULL) (*actual_mechs) = NULL; } if (initiator_time_rec != NULL) *initiator_time_rec = res.acceptor_time_rec; if (acceptor_time_rec != NULL) *acceptor_time_rec = res.acceptor_time_rec; /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_add_cred_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_add_cred(minor_status, input_cred_handle, desired_name, desired_mech_type, cred_usage, initiator_time_req, acceptor_time_req, actual_mechs, initiator_time_rec, acceptor_time_rec, uid) OM_uint32 *minor_status; gss_cred_id_t input_cred_handle; gss_name_t desired_name; gss_OID desired_mech_type; int cred_usage; int initiator_time_req; int acceptor_time_req; gss_OID_set *actual_mechs; OM_uint32 *initiator_time_rec; OM_uint32 *acceptor_time_rec; uid_t uid; { OM_uint32 err; OM_uint32 gssd_cred_verifier; gssd_cred_id_t gssd_input_cred_handle; if (input_cred_handle != GSS_C_NO_CREDENTIAL) { gssd_cred_verifier = KCRED_TO_CREDV(input_cred_handle); gssd_input_cred_handle = KCRED_TO_CRED(input_cred_handle); } else { gssd_input_cred_handle = GSSD_NO_CREDENTIAL; } err = kgss_add_cred_wrapped(minor_status, gssd_input_cred_handle, gssd_cred_verifier, desired_name, desired_mech_type, cred_usage, initiator_time_req, acceptor_time_req, actual_mechs, initiator_time_rec, acceptor_time_rec, uid); return (err); } OM_uint32 kgss_release_cred_wrapped(minor_status, cred_handle, uid, gssd_cred_verifier) OM_uint32 *minor_status; gssd_cred_id_t *cred_handle; uid_t uid; OM_uint32 gssd_cred_verifier; { CLIENT *clnt; gss_release_cred_arg arg; gss_release_cred_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_release_cred: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32)uid; arg.gssd_cred_verifier = gssd_cred_verifier; if (cred_handle != NULL) { arg.cred_handle.GSS_CRED_ID_T_len = (uint_t)sizeof (gssd_cred_id_t); arg.cred_handle.GSS_CRED_ID_T_val = (char *)cred_handle; } else arg.cred_handle.GSS_CRED_ID_T_len = 0; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_release_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (cred_handle != NULL) *cred_handle = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_release_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* if the release succeeded, null out the cred_handle */ if (res.status == GSS_S_COMPLETE && cred_handle != NULL) *cred_handle = 0; /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; /* return with status returned in rpc call */ killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_release_cred(minor_status, cred_handle, uid) OM_uint32 *minor_status; gss_cred_id_t *cred_handle; uid_t uid; { OM_uint32 err; struct kgss_cred *kcred; if (*cred_handle == GSS_C_NO_CREDENTIAL) return (GSS_S_COMPLETE); else kcred = KCRED_TO_KGSS_CRED(*cred_handle); err = kgss_release_cred_wrapped(minor_status, &kcred->gssd_cred, uid, kcred->gssd_cred_verifier); KGSS_CRED_FREE(kcred); *cred_handle = GSS_C_NO_CREDENTIAL; return (err); } static OM_uint32 kgss_init_sec_context_wrapped( OM_uint32 *minor_status, const gssd_cred_id_t claimant_cred_handle, OM_uint32 gssd_cred_verifier, gssd_ctx_id_t *context_handle, OM_uint32 *gssd_context_verifier, const gss_name_t target_name, const gss_OID mech_type, int req_flags, OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID *actual_mech_type, gss_buffer_t output_token, int *ret_flags, OM_uint32 *time_rec, uid_t uid) { CLIENT *clnt; OM_uint32 minor_status_temp; gss_buffer_desc external_name; gss_OID name_type; gss_init_sec_context_arg arg; gss_init_sec_context_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_init_sec_context: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* convert the target name from internal to external format */ if (gss_display_name(&minor_status_temp, target_name, &external_name, &name_type) != GSS_S_COMPLETE) { *minor_status = (OM_uint32) minor_status_temp; killgssd_handle(clnt); GSSLOG0(1, "kgss_init_sec_context: can't display name\n"); return ((OM_uint32) GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32)uid; arg.context_handle.GSS_CTX_ID_T_len = *context_handle == GSSD_NO_CONTEXT ? 0 : (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; arg.gssd_context_verifier = *gssd_context_verifier; arg.claimant_cred_handle.GSS_CRED_ID_T_len = claimant_cred_handle == GSSD_NO_CREDENTIAL ? 0 : (uint_t)sizeof (gssd_cred_id_t); arg.claimant_cred_handle.GSS_CRED_ID_T_val = (char *)&claimant_cred_handle; arg.gssd_cred_verifier = gssd_cred_verifier; arg.target_name.GSS_BUFFER_T_len = (uint_t)external_name.length; arg.target_name.GSS_BUFFER_T_val = (char *)external_name.value; arg.name_type.GSS_OID_len = name_type == GSS_C_NULL_OID ? 0 : (uint_t)name_type->length; arg.name_type.GSS_OID_val = name_type == GSS_C_NULL_OID ? (char *)NULL : (char *)name_type->elements; arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ? mech_type->length : 0); arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ? mech_type->elements : 0); arg.req_flags = req_flags; arg.time_req = time_req; if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) { arg.input_chan_bindings.present = YES; arg.input_chan_bindings.initiator_addrtype = input_chan_bindings->initiator_addrtype; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = (uint_t)input_chan_bindings->initiator_address.length; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = (void *)input_chan_bindings->initiator_address.value; arg.input_chan_bindings.acceptor_addrtype = input_chan_bindings->acceptor_addrtype; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = (uint_t)input_chan_bindings->acceptor_address.length; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = (void *)input_chan_bindings->acceptor_address.value; arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = (uint_t)input_chan_bindings->application_data.length; arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = (void *)input_chan_bindings->application_data.value; } else { arg.input_chan_bindings.present = NO; arg.input_chan_bindings.initiator_addrtype = 0; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0; arg.input_chan_bindings.acceptor_addrtype = 0; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0; arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0; arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0; } arg.input_token.GSS_BUFFER_T_len = (uint_t)(input_token != GSS_C_NO_BUFFER ? input_token->length : 0); arg.input_token.GSS_BUFFER_T_val = (char *)(input_token != GSS_C_NO_BUFFER ? input_token->value : 0); /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_init_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (actual_mech_type != NULL) *actual_mech_type = NULL; if (output_token != NULL) output_token->length = 0; if (ret_flags != NULL) *ret_flags = 0; if (time_rec != NULL) *time_rec = 0; killgssd_handle(clnt); (void) gss_release_buffer(&minor_status_temp, &external_name); GSSLOG0(1, "kgss_init_sec_context: RPC call times out\n"); return (GSS_S_FAILURE); } /* free the allocated memory for the flattened name */ (void) gss_release_buffer(&minor_status_temp, &external_name); if (minor_status != NULL) *minor_status = res.minor_status; if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) { output_token->length = (size_t)res.output_token.GSS_BUFFER_T_len; output_token->value = (void *)MALLOC(output_token->length); (void) memcpy(output_token->value, res.output_token.GSS_BUFFER_T_val, output_token->length); } /* if the call was successful, copy out the results */ if (res.status == (OM_uint32) GSS_S_COMPLETE || res.status == (OM_uint32) GSS_S_CONTINUE_NEEDED) { /* * if the return code is GSS_S_CONTINUE_NEEDED * ignore all return parameters except for * status codes, output token and context handle. */ *context_handle = *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val); *gssd_context_verifier = res.gssd_context_verifier; if (res.status == GSS_S_COMPLETE) { if (actual_mech_type != NULL) { *actual_mech_type = (gss_OID) MALLOC(sizeof (gss_OID_desc)); (*actual_mech_type)->length = (OM_UINT32)res.actual_mech_type.GSS_OID_len; (*actual_mech_type)->elements = (void *)MALLOC((*actual_mech_type)->length); (void) memcpy((*actual_mech_type)->elements, (void *)res.actual_mech_type.GSS_OID_val, (*actual_mech_type)->length); } if (ret_flags != NULL) *ret_flags = res.ret_flags; if (time_rec != NULL) *time_rec = res.time_rec; } } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_init_sec_context_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } static struct gss_config default_gc = { { 0, NULL}, NULL, NULL, 0, kgss_unseal_wrapped, NULL, /* kgss_delete_sec_context_wrapped */ kgss_seal_wrapped, NULL, /* kgss_import_sec_context */ kgss_sign_wrapped, kgss_verify_wrapped }; void kgss_free_oid(gss_OID oid) { FREE(oid->elements, oid->length); FREE(oid, sizeof (gss_OID_desc)); } OM_uint32 kgss_init_sec_context( OM_uint32 *minor_status, const gss_cred_id_t claimant_cred_handle, gss_ctx_id_t *context_handle, const gss_name_t target_name, const gss_OID mech_type, int req_flags, OM_uint32 time_req, const gss_channel_bindings_t input_chan_bindings, const gss_buffer_t input_token, gss_OID *actual_mech_type, gss_buffer_t output_token, int *ret_flags, OM_uint32 *time_rec, uid_t uid) { OM_uint32 err; struct kgss_ctx *kctx; gss_OID amt; gssd_cred_id_t gssd_cl_cred_handle; OM_uint32 gssd_cred_verifier; /* * If this is an initial call, we'll need to create the * wrapper struct that contains kernel state information, and * a reference to the handle from gssd. */ if (*context_handle == GSS_C_NO_CONTEXT) { kctx = KGSS_ALLOC(); /* * The default gss-mechanism struct as pointers to * the sign/seal/verify/unseal routines that make * upcalls to gssd. */ kctx->mech = &default_gc; kctx->gssd_ctx = GSSD_NO_CONTEXT; *context_handle = (gss_ctx_id_t)kctx; } else kctx = (struct kgss_ctx *)*context_handle; if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) { gssd_cred_verifier = KCRED_TO_CREDV(claimant_cred_handle); gssd_cl_cred_handle = KCRED_TO_CRED(claimant_cred_handle); } else { gssd_cl_cred_handle = GSSD_NO_CREDENTIAL; } /* * We need to know the resulting mechanism oid, so allocate * it if the caller won't. */ if (actual_mech_type == NULL) actual_mech_type = &amt; err = kgss_init_sec_context_wrapped(minor_status, gssd_cl_cred_handle, gssd_cred_verifier, &kctx->gssd_ctx, &kctx->gssd_ctx_verifier, target_name, mech_type, req_flags, time_req, input_chan_bindings, input_token, actual_mech_type, output_token, ret_flags, time_rec, uid); if (GSS_ERROR(err)) { KGSS_FREE(kctx); *context_handle = GSS_C_NO_CONTEXT; } else if (err == GSS_S_COMPLETE) { /* * Now check if there is a kernel module for this * mechanism OID. If so, set the gss_mechanism structure * in the wrapper context to point to the kernel mech. */ __kgss_reset_mech(&kctx->mech, *actual_mech_type); /* * If the mech oid was allocated for us, free it. */ if (&amt == actual_mech_type) { kgss_free_oid(amt); } } return (err); } static OM_uint32 kgss_accept_sec_context_wrapped( OM_uint32 *minor_status, gssd_ctx_id_t *context_handle, OM_uint32 *gssd_context_verifier, const gssd_cred_id_t verifier_cred_handle, OM_uint32 gssd_cred_verifier, const gss_buffer_t input_token, const gss_channel_bindings_t input_chan_bindings, gss_buffer_t src_name, gss_OID *mech_type, gss_buffer_t output_token, int *ret_flags, OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle, uid_t uid) { CLIENT *clnt; gss_accept_sec_context_arg arg; gss_accept_sec_context_res res; struct kgss_cred *kcred; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_accept_sec_context: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32)uid; arg.context_handle.GSS_CTX_ID_T_len = *context_handle == GSSD_NO_CONTEXT ? 0 : (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; arg.gssd_context_verifier = *gssd_context_verifier; arg.verifier_cred_handle.GSS_CRED_ID_T_len = verifier_cred_handle == GSSD_NO_CREDENTIAL ? 0 : (uint_t)sizeof (gssd_cred_id_t); arg.verifier_cred_handle.GSS_CRED_ID_T_val = (char *)&verifier_cred_handle; arg.gssd_cred_verifier = gssd_cred_verifier; arg.input_token_buffer.GSS_BUFFER_T_len = (uint_t)(input_token != GSS_C_NO_BUFFER ? input_token->length : 0); arg.input_token_buffer.GSS_BUFFER_T_val = (char *)(input_token != GSS_C_NO_BUFFER ? input_token->value : 0); if (input_chan_bindings != GSS_C_NO_CHANNEL_BINDINGS) { arg.input_chan_bindings.present = YES; arg.input_chan_bindings.initiator_addrtype = input_chan_bindings->initiator_addrtype; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = (uint_t)input_chan_bindings->initiator_address.length; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = (void *)input_chan_bindings->initiator_address.value; arg.input_chan_bindings.acceptor_addrtype = input_chan_bindings->acceptor_addrtype; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = (uint_t)input_chan_bindings->acceptor_address.length; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = (void *)input_chan_bindings->acceptor_address.value; arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = (uint_t)input_chan_bindings->application_data.length; arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = (void *)input_chan_bindings->application_data.value; } else { arg.input_chan_bindings.present = NO; arg.input_chan_bindings.initiator_addrtype = 0; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_len = 0; arg.input_chan_bindings.initiator_address.GSS_BUFFER_T_val = 0; arg.input_chan_bindings.acceptor_addrtype = 0; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_len = 0; arg.input_chan_bindings.acceptor_address.GSS_BUFFER_T_val = 0; arg.input_chan_bindings.application_data.GSS_BUFFER_T_len = 0; arg.input_chan_bindings.application_data.GSS_BUFFER_T_val = 0; } /* set the return parameters in case of errors.... */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (src_name != NULL) { src_name->length = 0; src_name->value = NULL; } if (mech_type != NULL) *mech_type = NULL; if (output_token != NULL) output_token->length = 0; if (ret_flags != NULL) *ret_flags = 0; if (time_rec != NULL) *time_rec = 0; if (delegated_cred_handle != NULL) *delegated_cred_handle = NULL; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_accept_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { killgssd_handle(clnt); GSSLOG0(1, "kgss_accept_sec_context: RPC call times out\n"); return (GSS_S_FAILURE); } if (minor_status != NULL) *minor_status = res.minor_status; if (output_token != NULL && res.output_token.GSS_BUFFER_T_val != NULL) { output_token->length = res.output_token.GSS_BUFFER_T_len; output_token->value = (void *)MALLOC(output_token->length); (void) memcpy(output_token->value, res.output_token.GSS_BUFFER_T_val, output_token->length); } /* if the call was successful, copy out the results */ if (res.status == (OM_uint32)GSS_S_COMPLETE || res.status == (OM_uint32)GSS_S_CONTINUE_NEEDED) { /* * the only parameters that are ready when we * get GSS_S_CONTINUE_NEEDED are: minor, ctxt_handle, * and the output token to send to the peer. */ *context_handle = *((gssd_ctx_id_t *) res.context_handle.GSS_CTX_ID_T_val); *gssd_context_verifier = res.gssd_context_verifier; /* these other parameters are only ready upon GSS_S_COMPLETE */ if (res.status == (OM_uint32)GSS_S_COMPLETE) { if (src_name != NULL) { src_name->length = res.src_name.GSS_BUFFER_T_len; src_name->value = res.src_name.GSS_BUFFER_T_val; res.src_name.GSS_BUFFER_T_val = NULL; res.src_name.GSS_BUFFER_T_len = 0; } /* * move mech type returned to mech_type * for gss_import_name_for_mech() */ if (mech_type != NULL) { *mech_type = (gss_OID)MALLOC(sizeof (gss_OID_desc)); (*mech_type)->length = (OM_UINT32)res.mech_type.GSS_OID_len; (*mech_type)->elements = (void *)MALLOC((*mech_type)->length); (void) memcpy((*mech_type)->elements, res.mech_type.GSS_OID_val, (*mech_type)->length); } if (ret_flags != NULL) *ret_flags = res.ret_flags; if (time_rec != NULL) *time_rec = res.time_rec; if ((delegated_cred_handle != NULL) && (res.delegated_cred_handle.GSS_CRED_ID_T_len != 0)) { kcred = KGSS_CRED_ALLOC(); kcred->gssd_cred = *((gssd_cred_id_t *) res.delegated_cred_handle.GSS_CRED_ID_T_val); kcred->gssd_cred_verifier = res.gssd_context_verifier; *delegated_cred_handle = (gss_cred_id_t)kcred; } } } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_accept_sec_context_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_accept_sec_context( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, const gss_cred_id_t verifier_cred_handle, const gss_buffer_t input_token, const gss_channel_bindings_t input_chan_bindings, gss_buffer_t src_name, gss_OID *mech_type, gss_buffer_t output_token, int *ret_flags, OM_uint32 *time_rec, gss_cred_id_t *delegated_cred_handle, uid_t uid) { OM_uint32 err; struct kgss_ctx *kctx; gss_OID mt; OM_uint32 gssd_cred_verifier; gssd_cred_id_t gssd_ver_cred_handle; /* * See kgss_init_sec_context() to get an idea of what is going * on here. */ if (mech_type == NULL) mech_type = &mt; if (*context_handle == GSS_C_NO_CONTEXT) { kctx = KGSS_ALLOC(); kctx->mech = &default_gc; kctx->gssd_ctx = GSSD_NO_CONTEXT; *context_handle = (gss_ctx_id_t)kctx; } else kctx = (struct kgss_ctx *)*context_handle; if (verifier_cred_handle != GSS_C_NO_CREDENTIAL) { gssd_cred_verifier = KCRED_TO_CREDV(verifier_cred_handle); gssd_ver_cred_handle = KCRED_TO_CRED(verifier_cred_handle); } else { gssd_ver_cred_handle = GSSD_NO_CREDENTIAL; } err = kgss_accept_sec_context_wrapped(minor_status, &kctx->gssd_ctx, &kctx->gssd_ctx_verifier, gssd_ver_cred_handle, gssd_cred_verifier, input_token, input_chan_bindings, src_name, mech_type, output_token, ret_flags, time_rec, delegated_cred_handle, uid); if (GSS_ERROR(err)) { KGSS_FREE(kctx); *context_handle = GSS_C_NO_CONTEXT; } else if (err == GSS_S_COMPLETE) { __kgss_reset_mech(&kctx->mech, *mech_type); /* * If the mech oid was allocated for us, free it. */ if (&mt == mech_type) { kgss_free_oid(mt); } } return (err); } OM_uint32 kgss_process_context_token(minor_status, context_handle, token_buffer, uid) OM_uint32 *minor_status; const gss_ctx_id_t context_handle; gss_buffer_t token_buffer; uid_t uid; { CLIENT *clnt; OM_uint32 gssd_context_verifier; gssd_ctx_id_t gssd_ctx_handle; gss_process_context_token_arg arg; gss_process_context_token_res res; gssd_context_verifier = KGSS_CTX_TO_GSSD_CTXV(context_handle); gssd_ctx_handle = (gssd_ctx_id_t)KGSS_CTX_TO_GSSD_CTX(context_handle); /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_process_context_token: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32) uid; arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&gssd_ctx_handle; arg.gssd_context_verifier = gssd_context_verifier; arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length; arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value; /* call the remote procedure */ bzero(&res, sizeof (res)); if (gss_process_context_token_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; GSSLOG0(1, "kgss_process_context_token: RPC call times out\n"); killgssd_handle(clnt); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; /* return with status returned in rpc call */ killgssd_handle(clnt); return (res.status); } /*ARGSUSED*/ static OM_uint32 kgss_delete_sec_context_wrapped(void *private, OM_uint32 *minor_status, gssd_ctx_id_t *context_handle, gss_buffer_t output_token, OM_uint32 gssd_context_verifier) { CLIENT *clnt; gss_delete_sec_context_arg arg; gss_delete_sec_context_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_delete_sec_context: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.context_handle.GSS_CTX_ID_T_len = *context_handle == GSSD_NO_CONTEXT ? 0 : (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; arg.gssd_context_verifier = gssd_context_verifier; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_delete_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (context_handle != NULL) *context_handle = 0; if (output_token != NULL) output_token->length = 0; killgssd_handle(clnt); GSSLOG0(1, "kgssd_delete_sec_context: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (res.context_handle.GSS_CTX_ID_T_len == 0) *context_handle = 0; else *context_handle = *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val); if (output_token != NULL) { output_token->length = res.output_token.GSS_BUFFER_T_len; output_token->value = res.output_token.GSS_BUFFER_T_val; res.output_token.GSS_BUFFER_T_len = 0; res.output_token.GSS_BUFFER_T_val = NULL; } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_delete_sec_context_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_delete_sec_context( OM_uint32 *minor_status, gss_ctx_id_t *context_handle, gss_buffer_t output_token) { OM_uint32 err; struct kgss_ctx *kctx; if (*context_handle == GSS_C_NO_CONTEXT) { GSSLOG0(8, "kgss_delete_sec_context: Null context handle \n"); return (GSS_S_COMPLETE); } else kctx = (struct kgss_ctx *)*context_handle; if (kctx->ctx_imported == FALSE) { if (kctx->gssd_ctx == GSSD_NO_CONTEXT) { KGSS_FREE(kctx); *context_handle = GSS_C_NO_CONTEXT; return (GSS_S_COMPLETE); } err = kgss_delete_sec_context_wrapped( KCTX_TO_PRIVATE(*context_handle), minor_status, &kctx->gssd_ctx, output_token, kctx->gssd_ctx_verifier); } else { if (kctx->gssd_i_ctx == (gss_ctx_id_t)GSS_C_NO_CONTEXT) { KGSS_FREE(kctx); *context_handle = GSS_C_NO_CONTEXT; return (GSS_S_COMPLETE); } err = KGSS_DELETE_SEC_CONTEXT(minor_status, kctx, &kctx->gssd_i_ctx, output_token); } KGSS_FREE(kctx); *context_handle = GSS_C_NO_CONTEXT; return (err); } OM_uint32 kgss_export_sec_context_wrapped(minor_status, context_handle, output_token, gssd_context_verifier) OM_uint32 *minor_status; gssd_ctx_id_t *context_handle; gss_buffer_t output_token; OM_uint32 gssd_context_verifier; { CLIENT *clnt; gss_export_sec_context_arg arg; gss_export_sec_context_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_export_sec_context_wrapped :" " can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)context_handle; arg.gssd_context_verifier = gssd_context_verifier; /* call the remote procedure */ (void) memset(&res, 0, sizeof (res)); if (gss_export_sec_context_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, * set minor_status to its maximum value, and return * GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (context_handle != NULL) *context_handle = 0; if (output_token != NULL) output_token->length = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_export_sec_context_wrapped: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (res.context_handle.GSS_CTX_ID_T_len == 0) *context_handle = 0; else *context_handle = *((gssd_ctx_id_t *)res.context_handle.GSS_CTX_ID_T_val); if (output_token != NULL) { output_token->length = res.output_token.GSS_BUFFER_T_len; output_token->value = (void *) MALLOC(output_token->length); (void) memcpy(output_token->value, res.output_token.GSS_BUFFER_T_val, output_token->length); } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_export_sec_context_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_export_sec_context(minor_status, context_handle, output_token) OM_uint32 *minor_status; gss_ctx_id_t context_handle; gss_buffer_t output_token; { struct kgss_ctx *kctx; if (context_handle == GSS_C_NO_CONTEXT) return (GSS_S_FAILURE); else kctx = (struct kgss_ctx *)context_handle; /* * If there is a kernel module then import_sec context must be * supported and we make an upcall to export_sec_context. * If there is no kernel module then we return an error */ *minor_status = 0; if (kctx->mech->gss_import_sec_context) { GSSLOG0(8, "kgss_export_sec_context: Kernel mod available \n"); return (kgss_export_sec_context_wrapped(minor_status, &kctx->gssd_ctx, output_token, kctx->gssd_ctx_verifier)); } else { /* * This is not the right error value; instead of * inventing new error we return GSS_S_NAME_NOT_MN * This error is not returned by the export routine */ GSSLOG0(8, "kgss_export_sec_context: Kernel mod " "unavailable \n"); return (GSS_S_NAME_NOT_MN); } } OM_uint32 kgss_import_sec_context(minor_status, interprocess_token, context_handle) OM_uint32 * minor_status; const gss_buffer_t interprocess_token; gss_ctx_id_t context_handle; { OM_uint32 status; struct kgss_ctx *kctx; size_t length; char *p; gss_buffer_desc token; gss_ctx_id_t internal_ctx_id; kctx = (struct kgss_ctx *)context_handle; if (kctx->gssd_ctx != GSSD_NO_CONTEXT) { return (GSS_S_FAILURE); } if (!(KCTX_TO_MECH(context_handle)->gss_import_sec_context)) { /* * This should never happen * If Kernel import sec context does not exist the export * sec context should have caught this and returned an error * and the caller should not have called this routine */ GSSLOG0(1, "import_sec_context called improperly\n"); return (GSS_S_FAILURE); } *minor_status = 0; if (interprocess_token->length == 0 || interprocess_token->value == 0) return (GSS_S_DEFECTIVE_TOKEN); status = GSS_S_FAILURE; p = interprocess_token->value; length = *p++; length = (length << 8) + *p++; length = (length << 8) + *p++; length = (length << 8) + *p++; p += length; token.length = interprocess_token->length - 4 - length; token.value = p; /* * select the approprate underlying mechanism routine and * call it. */ status = KGSS_IMPORT_SEC_CONTEXT(minor_status, &token, kctx, &internal_ctx_id); if (status == GSS_S_COMPLETE) { KCTX_TO_I_CTX(kctx) = internal_ctx_id; kctx->ctx_imported = TRUE; return (GSS_S_COMPLETE); } else return (status); } /*ARGSUSED*/ OM_uint32 kgss_context_time(minor_status, context_handle, time_rec, uid) OM_uint32 *minor_status; const gss_ctx_id_t context_handle; OM_uint32 *time_rec; uid_t uid; { return (GSS_S_FAILURE); } /*ARGSUSED*/ static OM_uint32 kgss_sign_wrapped(void *private, OM_uint32 *minor_status, const gss_ctx_id_t ctx_handle, int qop_req, const gss_buffer_t message_buffer, gss_buffer_t msg_token, OM_uint32 gssd_context_verifier) { CLIENT *clnt; gssd_ctx_id_t context_handle; gss_sign_arg arg; gss_sign_res res; context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle); /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_sign: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.gssd_context_verifier = gssd_context_verifier; arg.qop_req = qop_req; arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length; arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_sign_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (msg_token != NULL) msg_token->length = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_sign: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (msg_token != NULL) { msg_token->length = res.msg_token.GSS_BUFFER_T_len; msg_token->value = (void *) MALLOC(msg_token->length); (void) memcpy(msg_token->value, res.msg_token.GSS_BUFFER_T_val, msg_token->length); } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_sign_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_sign( OM_uint32 *minor_status, const gss_ctx_id_t context_handle, int qop_req, const gss_buffer_t message_buffer, gss_buffer_t msg_token) { if (context_handle == GSS_C_NO_CONTEXT) return (GSS_S_FAILURE); return (KGSS_SIGN(minor_status, context_handle, qop_req, message_buffer, msg_token)); } /*ARGSUSED*/ static OM_uint32 kgss_verify_wrapped(void *private, OM_uint32 *minor_status, const gss_ctx_id_t ctx_handle, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, int *qop_state, OM_uint32 gssd_context_verifier) { CLIENT *clnt; gssd_ctx_id_t context_handle; gss_verify_arg arg; gss_verify_res res; context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle); /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_verify: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.gssd_context_verifier = gssd_context_verifier; arg.message_buffer.GSS_BUFFER_T_len = (uint_t)message_buffer->length; arg.message_buffer.GSS_BUFFER_T_val = (char *)message_buffer->value; arg.token_buffer.GSS_BUFFER_T_len = (uint_t)token_buffer->length; arg.token_buffer.GSS_BUFFER_T_val = (char *)token_buffer->value; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_verify_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (qop_state != NULL) *qop_state = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_verify: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (qop_state != NULL) *qop_state = res.qop_state; /* return with status returned in rpc call */ killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_verify(OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t message_buffer, const gss_buffer_t token_buffer, int *qop_state) { if (context_handle == GSS_C_NO_CONTEXT) return (GSS_S_FAILURE); return (KGSS_VERIFY(minor_status, context_handle, message_buffer, token_buffer, qop_state)); } /*ARGSUSED*/ static OM_uint32 kgss_seal_wrapped(void *private, OM_uint32 *minor_status, const gss_ctx_id_t ctx_handle, int conf_req_flag, int qop_req, const gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer, OM_uint32 gssd_context_verifier) { CLIENT *clnt; gssd_ctx_id_t context_handle; gss_seal_arg arg; gss_seal_res res; context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle); /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_seal: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (OM_uint32); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.gssd_context_verifier = gssd_context_verifier; arg.conf_req_flag = conf_req_flag; arg.qop_req = qop_req; arg.input_message_buffer.GSS_BUFFER_T_len = (uint_t)input_message_buffer->length; arg.input_message_buffer.GSS_BUFFER_T_val = (char *)input_message_buffer->value; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_seal_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (conf_state != NULL) *conf_state = 0; if (output_message_buffer != NULL) output_message_buffer->length = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_seal: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (conf_state != NULL) *conf_state = res.conf_state; if (output_message_buffer != NULL) { output_message_buffer->length = res.output_message_buffer.GSS_BUFFER_T_len; output_message_buffer->value = (void *) MALLOC(output_message_buffer->length); (void) memcpy(output_message_buffer->value, res.output_message_buffer.GSS_BUFFER_T_val, output_message_buffer->length); } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_seal_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } /*ARGSUSED*/ OM_uint32 kgss_seal(OM_uint32 *minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, int qop_req, const gss_buffer_t input_message_buffer, int *conf_state, gss_buffer_t output_message_buffer) { if (context_handle == GSS_C_NO_CONTEXT) return (GSS_S_FAILURE); return (KGSS_SEAL(minor_status, context_handle, conf_req_flag, qop_req, input_message_buffer, conf_state, output_message_buffer)); } /*ARGSUSED*/ static OM_uint32 kgss_unseal_wrapped(void *private, OM_uint32 *minor_status, const gss_ctx_id_t ctx_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, int *qop_state, OM_uint32 gssd_context_verifier) { CLIENT *clnt; gss_unseal_arg arg; gss_unseal_res res; gssd_ctx_id_t context_handle; context_handle = (gssd_ctx_id_t)KCTX_TO_GSSD_CTX(ctx_handle); /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_unseal: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gss_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.context_handle.GSS_CTX_ID_T_len = (uint_t)sizeof (gssd_ctx_id_t); arg.context_handle.GSS_CTX_ID_T_val = (char *)&context_handle; arg.gssd_context_verifier = gssd_context_verifier; arg.input_message_buffer.GSS_BUFFER_T_len = (uint_t)input_message_buffer->length; arg.input_message_buffer.GSS_BUFFER_T_val = (char *)input_message_buffer->value; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_unseal_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (output_message_buffer != NULL) output_message_buffer->length = 0; if (conf_state != NULL) *conf_state = 0; if (qop_state != NULL) *qop_state = 0; killgssd_handle(clnt); GSSLOG0(1, "kgss_unseal: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (output_message_buffer != NULL) { output_message_buffer->length = res.output_message_buffer.GSS_BUFFER_T_len; output_message_buffer->value = (void *) MALLOC(output_message_buffer->length); (void) memcpy(output_message_buffer->value, res.output_message_buffer.GSS_BUFFER_T_val, output_message_buffer->length); } if (conf_state != NULL) *conf_state = res.conf_state; if (qop_state != NULL) *qop_state = res.qop_state; /* * free the memory allocated for the results and return with the * status received in the rpc call */ clnt_freeres(clnt, xdr_gss_unseal_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_unseal(OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t input_message_buffer, const gss_buffer_t output_message_buffer, int *conf_state, int *qop_state) { if (context_handle == GSS_C_NO_CONTEXT) return (GSS_S_FAILURE); return (KGSS_UNSEAL(minor_status, context_handle, input_message_buffer, output_message_buffer, conf_state, qop_state)); } OM_uint32 kgss_display_status(minor_status, status_value, status_type, mech_type, message_context, status_string, uid) OM_uint32 *minor_status; OM_uint32 status_value; int status_type; const gss_OID mech_type; int *message_context; gss_buffer_t status_string; uid_t uid; { CLIENT *clnt; gss_display_status_arg arg; gss_display_status_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_display_status: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32) uid; arg.status_value = status_value; arg.status_type = status_type; arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ? mech_type->length : 0); arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ? mech_type->elements : 0); arg.message_context = *message_context; /* call the remote procedure */ if (message_context != NULL) *message_context = 0; if (status_string != NULL) { status_string->length = 0; status_string->value = NULL; } bzero((caddr_t)&res, sizeof (res)); if (gss_display_status_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; killgssd_handle(clnt); GSSLOG0(1, "kgss_display_status: RPC call time out\n"); return (GSS_S_FAILURE); } /* now process the results and pass them back to the caller */ if (res.status == GSS_S_COMPLETE) { if (minor_status != NULL) *minor_status = res.minor_status; if (message_context != NULL) *message_context = res.message_context; if (status_string != NULL) { status_string->length = (size_t)res.status_string.GSS_BUFFER_T_len; status_string->value = (void *) MALLOC(status_string->length); (void) memcpy(status_string->value, res.status_string.GSS_BUFFER_T_val, status_string->length); } } clnt_freeres(clnt, xdr_gss_display_status_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } /*ARGSUSED*/ OM_uint32 kgss_indicate_mechs(minor_status, mech_set, uid) OM_uint32 *minor_status; gss_OID_set *mech_set; uid_t uid; { CLIENT *clnt; void *arg; gss_indicate_mechs_res res; int i; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_indicate_mechs: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } bzero((caddr_t)&res, sizeof (res)); if (gss_indicate_mechs_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (mech_set != NULL) *mech_set = NULL; killgssd_handle(clnt); GSSLOG0(1, "kgss_indicate_mechs: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; if (mech_set != NULL) { *mech_set = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); (*mech_set)->count = res.mech_set.GSS_OID_SET_len; (*mech_set)->elements = (void *) MALLOC ((*mech_set)->count * sizeof (gss_OID_desc)); for (i = 0; i < (*mech_set)->count; i++) { (*mech_set)->elements[i].length = res.mech_set.GSS_OID_SET_val[i].GSS_OID_len; (*mech_set)->elements[i].elements = (void *) MALLOC ((*mech_set)->elements[i].length); (void) memcpy((*mech_set)->elements[i].elements, res.mech_set.GSS_OID_SET_val[i].GSS_OID_val, (*mech_set)->elements[i].length); } } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_indicate_mechs_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_inquire_cred_wrapped(minor_status, cred_handle, gssd_cred_verifier, name, lifetime, cred_usage, mechanisms, uid) OM_uint32 *minor_status; const gssd_cred_id_t cred_handle; OM_uint32 gssd_cred_verifier; gss_name_t *name; OM_uint32 *lifetime; int *cred_usage; gss_OID_set *mechanisms; uid_t uid; { CLIENT *clnt; OM_uint32 minor_status_temp; gss_buffer_desc external_name; gss_OID_desc name_type; int i; gss_inquire_cred_arg arg; gss_inquire_cred_res res; /* * NULL the params here once * If there are errors then we won't * have to do it for every error * case */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; if (name != NULL) *name = NULL; if (lifetime != NULL) *lifetime = 0; if (cred_usage != NULL) *cred_usage = 0; if (mechanisms != NULL) *mechanisms = NULL; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_inquire_cred: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32) uid; arg.cred_handle.GSS_CRED_ID_T_len = cred_handle == GSSD_NO_CREDENTIAL ? 0 : (uint_t)sizeof (gssd_cred_id_t); arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle; arg.gssd_cred_verifier = gssd_cred_verifier; /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_inquire_cred_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out * kill the handle and return GSS_S_FAILURE * the parameters have been set to NULL already */ killgssd_handle(clnt); GSSLOG0(1, "kgss_inquire_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; /* convert name from external to internal format */ if (name != NULL) { external_name.length = res.name.GSS_BUFFER_T_len; external_name.value = res.name.GSS_BUFFER_T_val; /* * we can pass a pointer to res structure * since gss_import_name treats the name_type * parameter as read only and performs a copy */ name_type.length = res.name_type.GSS_OID_len; name_type.elements = (void *)res.name_type.GSS_OID_val; if (gss_import_name(&minor_status_temp, &external_name, &name_type, name) != GSS_S_COMPLETE) { *minor_status = (OM_uint32) minor_status_temp; clnt_freeres(clnt, xdr_gss_inquire_cred_res, (caddr_t)&res); killgssd_handle(clnt); GSSLOG0(1, "kgss_inquire_cred: import name fails\n"); return ((OM_uint32) GSS_S_FAILURE); } } if (lifetime != NULL) *lifetime = res.lifetime; if (cred_usage != NULL) *cred_usage = res.cred_usage; if (res.status == GSS_S_COMPLETE && res.mechanisms.GSS_OID_SET_len != 0 && mechanisms != NULL) { *mechanisms = (gss_OID_set) MALLOC(sizeof (gss_OID_set_desc)); (*mechanisms)->count = (int)res.mechanisms.GSS_OID_SET_len; (*mechanisms)->elements = (gss_OID) MALLOC(sizeof (gss_OID_desc) * (*mechanisms)->count); for (i = 0; i < (*mechanisms)->count; i++) { (*mechanisms)->elements[i].length = (OM_uint32) res.mechanisms.GSS_OID_SET_val[i].GSS_OID_len; (*mechanisms)->elements[i].elements = (void *) MALLOC((*mechanisms)->elements[i].length); (void) memcpy((*mechanisms)->elements[i].elements, res.mechanisms.GSS_OID_SET_val[i].GSS_OID_val, (*mechanisms)->elements[i].length); } } else { if (res.status == GSS_S_COMPLETE && mechanisms != NULL) (*mechanisms) = NULL; } /* * free the memory allocated for the results and return with the status * received in the rpc call */ clnt_freeres(clnt, xdr_gss_inquire_cred_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_inquire_cred(minor_status, cred_handle, name, lifetime, cred_usage, mechanisms, uid) OM_uint32 *minor_status; const gss_cred_id_t cred_handle; gss_name_t *name; OM_uint32 *lifetime; int *cred_usage; gss_OID_set * mechanisms; uid_t uid; { OM_uint32 gssd_cred_verifier; OM_uint32 gssd_cred_handle; gssd_cred_verifier = KCRED_TO_CREDV(cred_handle); gssd_cred_handle = KCRED_TO_CRED(cred_handle); return (kgss_inquire_cred_wrapped(minor_status, gssd_cred_handle, gssd_cred_verifier, name, lifetime, cred_usage, mechanisms, uid)); } OM_uint32 kgss_inquire_cred_by_mech_wrapped(minor_status, cred_handle, gssd_cred_verifier, mech_type, uid) OM_uint32 *minor_status; gssd_cred_id_t cred_handle; OM_uint32 gssd_cred_verifier; gss_OID mech_type; uid_t uid; { CLIENT *clnt; gss_inquire_cred_by_mech_arg arg; gss_inquire_cred_by_mech_res res; /* get the client handle to GSSD */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_inquire_cred: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments into the rpc arg parameter */ arg.uid = (OM_uint32) uid; arg.cred_handle.GSS_CRED_ID_T_len = cred_handle == GSSD_NO_CREDENTIAL ? 0 : (uint_t)sizeof (gssd_cred_id_t); arg.cred_handle.GSS_CRED_ID_T_val = (char *)&cred_handle; arg.gssd_cred_verifier = gssd_cred_verifier; arg.mech_type.GSS_OID_len = (uint_t)(mech_type != GSS_C_NULL_OID ? mech_type->length : 0); arg.mech_type.GSS_OID_val = (char *)(mech_type != GSS_C_NULL_OID ? mech_type->elements : 0); /* call the remote procedure */ bzero((caddr_t)&res, sizeof (res)); if (gss_inquire_cred_by_mech_1(&arg, &res, clnt) != RPC_SUCCESS) { /* * if the RPC call times out, null out all return arguments, set * minor_status to its maximum value, and return GSS_S_FAILURE */ if (minor_status != NULL) *minor_status = DEFAULT_MINOR_STAT; killgssd_handle(clnt); GSSLOG0(1, "kgss_inquire_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the rpc results into the return arguments */ if (minor_status != NULL) *minor_status = res.minor_status; clnt_freeres(clnt, xdr_gss_inquire_cred_by_mech_res, (caddr_t)&res); killgssd_handle(clnt); return (res.status); } OM_uint32 kgss_inquire_cred_by_mech(minor_status, cred_handle, mech_type, uid) OM_uint32 *minor_status; gss_cred_id_t cred_handle; gss_OID mech_type; uid_t uid; { OM_uint32 gssd_cred_verifier; OM_uint32 gssd_cred_handle; gssd_cred_verifier = KCRED_TO_CREDV(cred_handle); gssd_cred_handle = KCRED_TO_CRED(cred_handle); return (kgss_inquire_cred_by_mech_wrapped(minor_status, gssd_cred_handle, gssd_cred_verifier, mech_type, uid)); } OM_uint32 kgsscred_expname_to_unix_cred(expName, uidOut, gidOut, gids, gidsLen, uid) const gss_buffer_t expName; uid_t *uidOut; gid_t *gidOut; gid_t *gids[]; int *gidsLen; uid_t uid; { CLIENT *clnt; gsscred_expname_to_unix_cred_arg args; gsscred_expname_to_unix_cred_res res; /* check input/output parameters */ if (expName == NULL || expName->value == NULL) return (GSS_S_CALL_INACCESSIBLE_READ); if (uidOut == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); /* NULL out output parameters */ *uidOut = UID_NOBODY; if (gidsLen) *gidsLen = 0; if (gids) *gids = NULL; /* get the client handle to gssd */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgsscred_expname_to_unix_cred:" " can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* copy the procedure arguments */ args.uid = uid; args.expname.GSS_BUFFER_T_val = expName->value; args.expname.GSS_BUFFER_T_len = expName->length; /* null out the return buffer and call the remote proc */ bzero(&res, sizeof (res)); if (gsscred_expname_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS) { killgssd_handle(clnt); GSSLOG0(1, "kgsscred_expname_to_unix_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the results into the result parameters */ if (res.major == GSS_S_COMPLETE) { *uidOut = res.uid; if (gidOut) *gidOut = res.gid; if (gids && gidsLen) { *gids = res.gids.GSSCRED_GIDS_val; *gidsLen = res.gids.GSSCRED_GIDS_len; res.gids.GSSCRED_GIDS_val = NULL; res.gids.GSSCRED_GIDS_len = 0; } } /* free RPC results */ clnt_freeres(clnt, xdr_gsscred_expname_to_unix_cred_res, (caddr_t)&res); killgssd_handle(clnt); return (res.major); } /* kgsscred_expname_to_unix_cred */ OM_uint32 kgsscred_name_to_unix_cred(intName, mechType, uidOut, gidOut, gids, gidsLen, uid) const gss_name_t intName; const gss_OID mechType; uid_t *uidOut; gid_t *gidOut; gid_t *gids[]; int *gidsLen; uid_t uid; { CLIENT *clnt; gsscred_name_to_unix_cred_arg args; gsscred_name_to_unix_cred_res res; OM_uint32 major, minor; gss_OID nameOid; gss_buffer_desc flatName = GSS_C_EMPTY_BUFFER; /* check the input/output parameters */ if (intName == NULL || mechType == NULL) return (GSS_S_CALL_INACCESSIBLE_READ); if (uidOut == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); /* NULL out the output parameters */ *uidOut = UID_NOBODY; if (gids) *gids = NULL; if (gidsLen) *gidsLen = 0; /* get the client handle to gssd */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgsscred_name_to_unix_cred: can't connect to server %s\n", server); return (GSS_S_FAILURE); } /* convert the name to flat representation */ if ((major = gss_display_name(&minor, intName, &flatName, &nameOid)) != GSS_S_COMPLETE) { killgssd_handle(clnt); GSSLOG0(1, "kgsscred_name_to_unix_cred: display name failed\n"); return (major); } /* set the rpc parameters */ args.uid = uid; args.pname.GSS_BUFFER_T_len = flatName.length; args.pname.GSS_BUFFER_T_val = flatName.value; args.name_type.GSS_OID_len = nameOid->length; args.name_type.GSS_OID_val = nameOid->elements; args.mech_type.GSS_OID_len = mechType->length; args.mech_type.GSS_OID_val = mechType->elements; /* call the remote procedure */ bzero(&res, sizeof (res)); if (gsscred_name_to_unix_cred_1(&args, &res, clnt) != RPC_SUCCESS) { killgssd_handle(clnt); (void) gss_release_buffer(&minor, &flatName); GSSLOG0(1, "kgsscred_name_to_unix_cred: RPC call times out\n"); return (GSS_S_FAILURE); } /* delete the flat name buffer */ (void) gss_release_buffer(&minor, &flatName); /* copy the output parameters on output */ if (res.major == GSS_S_COMPLETE) { *uidOut = res.uid; if (gidOut) *gidOut = res.gid; if (gids && gidsLen) { *gids = res.gids.GSSCRED_GIDS_val; *gidsLen = res.gids.GSSCRED_GIDS_len; res.gids.GSSCRED_GIDS_val = NULL; res.gids.GSSCRED_GIDS_len = 0; } } /* delete RPC allocated memory */ clnt_freeres(clnt, xdr_gsscred_name_to_unix_cred_res, (caddr_t)&res); killgssd_handle(clnt); return (res.major); } /* kgsscred_name_to_unix_cred */ OM_uint32 kgss_get_group_info(puid, gidOut, gids, gidsLen, uid) const uid_t puid; gid_t *gidOut; gid_t *gids[]; int *gidsLen; uid_t uid; { CLIENT *clnt; gss_get_group_info_arg args; gss_get_group_info_res res; /* check the output parameters */ if (gidOut == NULL || gids == NULL || gidsLen == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); /* get the client GSSD handle */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_get_group_info: can't connect to server on %s\n", server); return (GSS_S_FAILURE); } /* set the input parameters */ args.uid = uid; args.puid = puid; /* call the remote procedure */ bzero(&res, sizeof (res)); if (gss_get_group_info_1(&args, &res, clnt) != RPC_SUCCESS) { killgssd_handle(clnt); GSSLOG0(1, "kgss_get_group_info: RPC call times out\n"); return (GSS_S_FAILURE); } /* copy the results */ if (res.major == GSS_S_COMPLETE) { *gidOut = res.gid; *gids = res.gids.GSSCRED_GIDS_val; *gidsLen = res.gids.GSSCRED_GIDS_len; res.gids.GSSCRED_GIDS_val = NULL; res.gids.GSSCRED_GIDS_len = 0; } /* no results to free */ killgssd_handle(clnt); return (res.major); } /* kgss_get_group_info */ static char * kgss_get_kmod(gss_OID mech_oid) { CLIENT *clnt; gss_get_kmod_arg args; gss_get_kmod_res res; /* get the client GSSD handle */ if ((clnt = getgssd_handle()) == NULL) { GSSLOG(1, "kgss_get_kmod: can't connect to server on %s\n", server); return (NULL); } /* set the input parameters */ args.mech_oid.GSS_OID_len = mech_oid->length; args.mech_oid.GSS_OID_val = mech_oid->elements; /* call the remote procedure */ bzero(&res, sizeof (res)); if (gss_get_kmod_1(&args, &res, clnt) != RPC_SUCCESS) { killgssd_handle(clnt); GSSLOG0(1, "gss_get_kmod_1: RPC call times out\n"); return (NULL); } /* no results to free */ killgssd_handle(clnt); if (res.module_follow == TRUE) { return (res.gss_get_kmod_res_u.modname); } else return (NULL); } /* kgss_get_kmod */ static gss_mechanism kgss_mech_head; static gss_mechanism kgss_mech_tail; kmutex_t __kgss_mech_lock; /* * See if there is kernel mechanism module, and if so, attempt to * load it and reset the pointer (gss_mechanism) to the sign/seal/etc. * entry points to that of the kernel module. */ static void __kgss_reset_mech(gss_mechanism *mechp, gss_OID mech_oid) { gss_mechanism mech; char *kmod; /* * We can search the list without a mutex, becuase the list never * shrinks and we always add to the end. */ mech = __kgss_get_mechanism(mech_oid); if (mech) { *mechp = mech; return; } /* * Get the module name from the kernel. */ kmod = kgss_get_kmod(mech_oid); if (kmod) { extern int modload(const char *, const char *); if (modload("misc/kgss", kmod) < 0) { /* * Modload of 'kmod' failed, so log an * appropriate comment */ cmn_err(CE_NOTE, "kgss_reset_mech: Algorithm modload " "(%s) failed. Userland gssd will now handle " "all GSSAPI calls, which may result in " "reduced performance.\n", kmod); }; /* * Allocated in the XDR routine called by gss_get_kmod_1(). */ FREE(kmod, strlen(kmod)+1); mech = __kgss_get_mechanism(mech_oid); if (mech) { *mechp = mech; } /* * If for some reason the module load didn't take, * we return anyway and hope that the next context * creation succeeds. */ return; } /* * No kernel module, so enter this mech oid into the list * using the default sign/seal/etc. operations that upcall to * gssd. */ mutex_enter(&__kgss_mech_lock); mech = __kgss_get_mechanism(mech_oid); if (mech) { mutex_exit(&__kgss_mech_lock); *mechp = mech; return; } /* * Allocate space for the mechanism entry. */ mech = kmem_zalloc(sizeof (struct gss_config), KM_SLEEP); /* * Copy basic information from default mechanism struct. */ *mech = default_gc; /* * Record the real mech OID. */ mech->mech_type.length = mech_oid->length; mech->mech_type.elements = MALLOC(mech_oid->length); bcopy(mech_oid->elements, mech->mech_type.elements, mech_oid->length); /* * Add it to the table. */ __kgss_add_mechanism(mech); mutex_exit(&__kgss_mech_lock); *mechp = mech; } /* * Called with __kgss_mech_lock held. */ void __kgss_add_mechanism(gss_mechanism mech) { gss_mechanism tmp; tmp = kgss_mech_tail; kgss_mech_tail = mech; if (tmp != NULL) tmp->next = mech; if (kgss_mech_head == NULL) kgss_mech_head = mech; } /* * given the mechs_array and a mechanism OID, return the * pointer to the mechanism, or NULL if that mechanism is * not supported. */ gss_mechanism __kgss_get_mechanism(gss_OID type) { gss_mechanism mech; mech = kgss_mech_head; /* * Note that a reader can scan this list without the mutex held. * This is safe because we always append, and never shrink the list. * Moreover, the entry is fully initialized before it is ever * added to the list. */ while (mech != NULL) { if ((mech->mech_type.length == type->length) && (bcmp(mech->mech_type.elements, type->elements, type->length) == 0)) return (mech); mech = mech->next; } return (NULL); }