gssd_proc.c revision 004388ebfdfe2ed7dfd2d153a876dfcc22d2c006
/*
* 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
* 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 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* RPC server procedures for the gssapi usermode daemon gssd.
*/
#include <stdio.h>
#include <stdio_ext.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <strings.h>
#include <limits.h>
#include <mechglueP.h>
#include "gssd.h"
#include <stdlib.h>
#include <syslog.h>
#include <sys/resource.h>
#define SRVTAB ""
extern int gssd_debug; /* declared in gssd.c */
struct gssd_ctx_slot {
struct gssd_ctx_slot *lru_next;
struct gssd_ctx_slot *lru_prev;
};
struct gssd_ctx_slot *gssd_ctx_slot_tbl;
struct gssd_ctx_slot *gssd_lru_head;
static int max_contexts;
extern void set_gssd_uid(uid_t);
void
gssd_setup(char *arg)
{
int i;
/*
* Use low order bits of high resolution time to get a reasonably
* random number to start the context sequencing. This alternative
* to using a time value avoid clock resets via NTP or ntpdate.
*/
high_res_time = gethrtime();
/*
* sec_context calls before we're able to export them. This can
* happen in very heavily load environments where gssd doesn't get
* much time to work on its backlog.
*/
}
gssd_ctx_slot_tbl = (struct gssd_ctx_slot *)
if (gssd_ctx_slot_tbl == NULL) {
gettext("[%s] could not allocate %d byte context table"
"\n"), arg,
(sizeof (struct gssd_ctx_slot) * max_contexts));
exit(1);
}
for (i = 1; i < max_contexts; i++) {
gssd_ctx_slot_tbl[i].verf = 0;
gssd_ctx_slot_tbl[i].create_time = 0;
}
gssd_ctx_slot_tbl[0].verf = 0;
gssd_ctx_slot_tbl[0].create_time = 0;
gssd_lru_head = &gssd_ctx_slot_tbl[0];
}
static struct gssd_ctx_slot *
{
struct gssd_ctx_slot *lru;
static OM_uint32 last_syslog = 0;
static int tooks;
lru = gssd_lru_head;
if (last_syslog == 0)
(void) gss_delete_sec_context(&minor_status,
tooks++;
first_take) {
"context slot of age %u seconds (%d slots re-"
"used during last %u seconds)"),
tooks = 0;
first_take = FALSE;
}
}
/*
* Assign the next context verifier to the context (avoiding zero).
*/
context_verf++;
if (context_verf == 0)
context_verf = 1;
return (lru);
}
/*
* We always add 1 because we don't want slot 0 to be confused
* with GSS_C_NO_CONTEXT.
*/
static struct gssd_ctx_slot *
{
intptr_t i;
if (h->GSS_CTX_ID_T_len == 0) {
return (NULL);
}
if (h->GSS_CTX_ID_T_len != sizeof (i))
return (NULL);
if (i < 0 || i >= max_contexts)
return (NULL);
return (&gssd_ctx_slot_tbl[i]);
}
static void
{
return;
/*
* Remove entry from its current location in list
*/
/*
* Since it is no longer in use, it is the least recently
* used.
*/
gssd_lru_head = lru;
}
static void
struct gssd_ctx_slot **slotp)
{
struct gssd_ctx_slot *slot;
*context_verf_ok = FALSE;
if (h->GSS_CTX_ID_T_len == 0) {
*context_verf_ok = TRUE;
return;
}
slot = gssd_handle_to_slot(h);
return;
return;
*context_verf_ok = TRUE;
}
{
int cred_usage;
int i, j;
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/* convert the desired name from external to internal format */
if (!external_name.value)
return (GSS_S_FAILURE);
} else {
return (GSS_S_FAILURE);
}
}
&desired_name) != GSS_S_COMPLETE) {
if (name_type != GSS_C_NULL_OID)
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local GSSAPI
* variables.
*/
if (!desired_mechs->elements) {
return (GSS_S_FAILURE);
}
for (i = 0; i < desired_mechs->count; i++) {
length);
for (j = 0; j < (i -1); j++) {
}
return (GSS_S_FAILURE);
}
}
} else
/* call the gssapi routine */
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
(void *)malloc(sizeof (gss_cred_id_t));
for (i = 0; i < desired_mechs->count; i++) {
}
return (GSS_S_FAILURE);
}
sizeof (gss_cred_id_t));
if (actual_mechs != GSS_C_NULL_OID_SET) {
for (i = 0; i < desired_mechs->count; i++) {
}
return (GSS_S_FAILURE);
}
for (i = 0; i < actual_mechs->count; i++) {
length);
for (j = 0; j < desired_mechs->count; j++) {
}
for (j = 0; j < (i - 1); j++) {
(res->actual_mechs.
}
return (GSS_S_FAILURE);
}
}
} else
/*
* set the time verifier for credential handle. To ensure that the
* timestamp is not the same as previous gssd process, verify that
* time is not the same as set earlier at start of process. If it
* is, sleep one second and reset. (due to one second granularity)
*/
sleep(1);
}
}
/*
* now release the space allocated by the underlying gssapi mechanism
* library for actual_mechs as well as by this routine for
* external_name, name_type and desired_name
*/
if (name_type != GSS_C_NULL_OID)
if (actual_mechs != GSS_C_NULL_OID_SET) {
for (i = 0; i < actual_mechs->count; i++)
}
if (desired_mechs != GSS_C_NULL_OID_SET) {
for (i = 0; i < desired_mechs->count; i++)
}
/* return to caller */
return (TRUE);
}
{
int cred_usage;
int i, j;
if (gssd_debug)
res->minor_status = 0;
res->initiator_time_rec = 0;
res->acceptor_time_rec = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/* convert the desired name from external to internal format */
&desired_name) != GSS_S_COMPLETE) {
if (gssd_debug)
gettext("gss_add_cred:import name"),
gettext(" failed status %d \n"),
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local GSSAPI
* variables.
*/
else {
if (!desired_mech_type->elements) {
return (GSS_S_FAILURE);
}
}
/*LINTED*/
if (input_cred_handle != GSS_C_NO_CREDENTIAL)
/* verify the input_cred_handle */
res->minor_status = 0;
return (TRUE);
}
/* call the gssapi routine */
NULL,
&res->acceptor_time_rec);
(gssd_debug))
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
if (actual_mechs != GSS_C_NULL_OID_SET) {
return (GSS_S_FAILURE);
}
for (i = 0; i < actual_mechs->count; i++) {
length);
for (j = 0; j < (i - 1); j++) {
(res->actual_mechs.
}
return (GSS_S_FAILURE);
}
}
} else
/*
* now release the space allocated for
* desired_name and desired_mech_type
*/
/*
* if (actual_mechs != GSS_C_NULL_OID_SET) {
* for (i = 0; i < actual_mechs->count; i++)
* free(actual_mechs->elements[i].elements);
* free(actual_mechs->elements);
* free(actual_mechs);
* }
*/
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
return (FALSE);
/* set the uid sent as the RPC argument */
/*
* if the cred_handle verifier is not correct,
* set status to GSS_S_DEFECTIVE_CREDENTIAL and return
*/
return (TRUE);
}
/*
* if the cred_handle length is 0
* set cred_handle argument to GSS_S_NO_CREDENTIAL
*/
else
/* call the gssapi routine */
&cred_handle);
/* return to caller */
return (TRUE);
}
{
struct gss_channel_bindings_struct
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/*
* copy the supplied context handle into the local context handle, so it
* can be supplied to the gss_init_sec_context call
*/
/*LINTED*/
if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
/* verify the verifier_cred_handle */
res->minor_status = 0;
return (TRUE);
}
}
if (context_handle != GSS_C_NO_CONTEXT) {
/* verify the verifier_context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
}
/* convert the target name from external to internal format */
} else {
return (GSS_S_FAILURE);
}
else {
}
&internal_name) != GSS_S_COMPLETE) {
if (name_type != GSS_C_NULL_OID)
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local GSSAPI
* variables.
*/
} else {
}
} else {
}
/* call the gssapi routine */
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
}
(void *)malloc(sizeof (gss_ctx_id_t));
return (GSS_S_FAILURE);
}
sizeof (gss_ctx_id_t));
(char *)output_token.value;
/*
* the actual mech type parameter
* is ready only upon GSS_S_COMPLETE
*/
return (GSS_S_FAILURE);
}
(char *)actual_mech_type->elements,
} else
} else {
if (context_handle != GSS_C_NO_CONTEXT) {
(void) gss_delete_sec_context(&minor_status,
&context_handle, NULL);
}
}
/*
* now release the space allocated by the underlying gssapi mechanism
* library for internal_name and for the name_type.
*/
if (name_type != GSS_C_NULL_OID)
/* return to caller */
return (TRUE);
}
{
struct gss_channel_bindings_struct
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/*
* copy the supplied context handle into the local context handle, so
* it can be supplied to the gss_accept_sec_context call
*/
if (context_handle != GSS_C_NO_CONTEXT)
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
/*LINTED*/
/* verify the verifier_cred_handle */
res->minor_status = 0;
return (TRUE);
}
} else {
}
} else {
}
/* call the gssapi routine */
/* convert the src name from internal to external format */
/*
* upon GSS_S_CONTINUE_NEEDED only the following
* parameters are ready: minor, ctxt, and output token
*/
(void *)malloc(sizeof (gss_ctx_id_t));
res->minor_status = 0;
return (TRUE);
}
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
}
sizeof (gss_ctx_id_t));
(char *)output_token.value;
!= GSS_S_COMPLETE) {
&context_handle, NULL);
&output_token);
return (TRUE);
}
(void *)external_name.value;
sizeof (gss_cred_id_t);
(void *)malloc(sizeof (gss_cred_id_t));
&context_handle, NULL);
res->minor_status = 0;
return (TRUE);
}
sizeof (gss_cred_id_t));
&context_handle, NULL);
res->minor_status = 0;
return (TRUE);
}
/* release the space allocated for internal_name */
} else { /* GSS_S_CONTINUE_NEEDED */
}
} else {
if (context_handle != GSS_C_NO_CONTEXT) {
(void) gss_delete_sec_context(&minor_status,
&context_handle, NULL);
}
}
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
return (FALSE);
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/* set the uid sent as the RPC argument */
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
/* call the gssapi routine */
&token_buffer);
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
/*
* copy the supplied context handle into the local context handle, so it
* can be supplied to the gss_delete_sec_context call
*/
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* call the gssapi routine */
&output_token);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result. If the delete succeeded, return a zero
* context handle.
*/
if (context_handle != GSS_C_NO_CONTEXT)
return (GSS_S_FAILURE);
(char *)output_token.value;
/*
* gss_delete_sec_context deletes the context if it
* succeeds so clear slot->ctx to avoid a dangling
* reference.
*/
}
} else {
(void *)malloc(sizeof (gss_ctx_id_t));
return (GSS_S_FAILURE);
}
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
/*
* Note that no verifier is returned in the .x
* protocol. So if the context changes, we won't
* be able to release it now. So it will have to
* be LRUed out.
*/
}
sizeof (gss_ctx_id_t));
}
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/*
* copy the supplied context handle into the local context handle, so it
* can be supplied to the gss_export_sec_context call
*/
/* verify the context_handle */
if (!context_verf_ok) {
/* the rest of "res" was cleared by a previous memset() */
return (TRUE);
}
/* call the gssapi routine */
&output_token);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result. If the delete succeeded, return a zero context
* handle.
*/
if (context_handle != GSS_C_NO_CONTEXT)
return (GSS_S_FAILURE);
(char *)output_token.value;
/*
* gss_export_sec_context deletes the context if it
* succeeds so set slot->ctx to avoid a dangling
* reference.
*/
}
} else {
(void *)malloc(sizeof (gss_ctx_id_t));
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
/*
* Note that no verifier is returned in the .x
* protocol. So if the context changes, we won't
* be able to release it now. So it will have to
* be LRUed out.
*/
}
sizeof (gss_ctx_id_t));
}
/* return to caller */
return (TRUE);
}
/*
* This routine doesn't appear to ever be called.
*/
{
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
} else {
}
/* call the gssapi routine */
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result. If the delete succeeded, return a zero context
* handle.
*/
(void *) malloc(sizeof (gss_ctx_id_t));
sizeof (gss_ctx_id_t));
} else {
}
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
/* set the uid sent as the RPC argument */
/* Semantics go here */
return (TRUE);
}
{
if (gssd_debug)
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
/* call the gssapi routine */
/*
* convert the output args from the parameter given in the call to
* the variable in the XDR result
*/
}
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
/* call the gssapi routine */
/* return to caller */
return (TRUE);
}
/* EXPORT DELETE START */
{
if (gssd_debug)
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
/* call the gssapi routine */
&res->conf_state,
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
(char *)output_message_buffer.value;
}
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
/* verify the context_handle */
/* verify the context_handle */
if (!context_verf_ok) {
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
/* call the gssapi routine */
&res->conf_state,
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
(char *)output_message_buffer.value;
}
/* return to caller */
return (TRUE);
}
/* EXPORT DELETE END */
{
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variables.
*/
else {
}
/* call the gssapi routine */
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
(char *)status_string.value;
}
return (TRUE);
}
/*ARGSUSED*/
void *argp;
{
if (gssd_debug)
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
int i, j;
return (GSS_S_FAILURE);
}
for (j = 0; j < (i -1); j++) {
}
return (GSS_S_FAILURE);
}
}
}
return (TRUE);
}
{
int i, j;
if (gssd_debug)
/* verify the verifier_cred_handle */
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/*LINTED*/
/* call the gssapi routine */
&res->cred_usage,
&mechanisms);
return (TRUE);
/* convert the returned name from internal to external format */
!= GSS_S_COMPLETE) {
if (mechanisms != GSS_C_NULL_OID_SET) {
for (i = 0; i < mechanisms->count; i++)
}
return (TRUE);
}
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
/*
* we have to allocate storage for name_type here, since the value
* returned from gss_display_name points to the underlying mechanism
* static storage. If we didn't allocate storage, the next time
* through this routine, the xdr_free() call at the beginning would
* try to free up that static storage.
*/
return (GSS_S_FAILURE);
}
if (mechanisms != GSS_C_NULL_OID_SET) {
return (GSS_S_FAILURE);
}
for (i = 0; i < mechanisms->count; i++) {
length);
for (j = 0; j < i; j++) {
}
return (GSS_S_FAILURE);
}
}
} else
/* release the space allocated for internal_name and mechanisms */
if (mechanisms != GSS_C_NULL_OID_SET) {
for (i = 0; i < mechanisms->count; i++)
}
/* return to caller */
return (TRUE);
}
{
if (gssd_debug)
/* verify the verifier_cred_handle */
res->minor_status = 0;
return (TRUE);
}
/*
* if the request isn't from root, null out the result pointer
* entries, so the next time through xdr_free won't try to
* free unmalloc'd memory and then return NULL
*/
return (FALSE);
}
/* set the uid sent as the RPC argument */
/*LINTED*/
/* call the gssapi routine */
else {
return (GSS_S_FAILURE);
}
}
/* return to caller */
return (TRUE);
}
{
int gidsLen;
if (gssd_debug)
/*
* check the request originator
*/
return (FALSE);
/* set the uid from the rpc request */
/*
* convert the principal name to gss internal format
* need not malloc the input parameters
*/
return (TRUE);
/* retrieve the mechanism type from the arguments */
/* call the gss extensions to map the principal name to unix creds */
}
return (TRUE);
} /* gsscred_name_to_unix_cred_svc_1 */
{
int gidsLen;
if (gssd_debug)
/*
* check the request originator
*/
return (FALSE);
/* set the uid from the rpc request */
/*
* extract the export name from arguments
* need not malloc the input parameters
*/
}
return (TRUE);
} /* gsscred_expname_to_unix_cred_1_svc */
{
int gidsLen;
if (gssd_debug)
/*
* check the request originator
*/
return (FALSE);
/* set the uid from the rpc request */
/*
* extract the uid from the arguments
*/
}
return (TRUE);
} /* gss_get_group_info_1_svc */
/*ARGSUSED*/
{
char *kmodName;
if (gssd_debug)
}
return (TRUE);
}
/*
* Returns 1 if caller is ok, else 0.
* If caller ok, the uid is returned in uidp.
*/
static int
{
struct authunix_parms *aup;
/* check client agent uid to ensure it is privileged */
goto weakauth;
}
if (gssd_debug)
if (uid != 0) {
gettext("checkfrom: caller (uid %d) not privileged"),
uid);
goto weakauth;
}
/*
* Request came from local privileged process.
* Proceed to get uid of client if needed by caller.
*/
if (uidp) {
goto weakauth;
}
/*LINTED*/
if (gssd_debug) {
}
}
return (1);
return (0);
}