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
* 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 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 <sys/param.h>
#include <sys/syslog.h>
#include <mechglueP.h>
#include "gssd.h"
#include <gssapi/gssapi.h>
#include <rpc/rpc.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/resource.h>
#define SRVTAB ""
#define FDCACHE_PERCENTAGE .75 /* Percentage of total FD limit */
#define FDCACHE_DEFAULT 16 /* Default LRU cache size */
#define GSSD_FD_LIMIT 255 /* Increase number of fds allowed */
extern int gssd_debug; /* declared in gssd.c */
static OM_uint32 gssd_time_verf; /* verifies same gssd */
static OM_uint32 context_verf; /* context sequence numbers */
struct gssd_ctx_slot {
struct gssd_ctx_slot *lru_next;
struct gssd_ctx_slot *lru_prev;
bool_t inuse;
OM_uint32 create_time;
OM_uint32 verf;
gss_ctx_id_t ctx;
gss_ctx_id_t rpcctx;
};
struct gssd_ctx_slot *gssd_ctx_slot_tbl;
struct gssd_ctx_slot *gssd_lru_head;
static int max_contexts;
static int checkfrom(struct svc_req *, uid_t *);
extern void set_gssd_uid(uid_t);
extern int __rpc_get_local_uid(SVCXPRT *, uid_t *);
void
gssd_setup(char *arg)
{
int i;
struct rlimit rl;
hrtime_t high_res_time;
gssd_time_verf = (OM_uint32)time(NULL);
max_contexts = FDCACHE_DEFAULT;
/*
* 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();
context_verf = (OM_uint32)high_res_time;
/*
* Increase resource limit of FDs in case we get alot accept/init_
* 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.
*/
if ((getrlimit(RLIMIT_NOFILE, &rl)) == 0) {
rl.rlim_cur = (rl.rlim_max >= GSSD_FD_LIMIT) ?
GSSD_FD_LIMIT : rl.rlim_max;
if ((setrlimit(RLIMIT_NOFILE, &rl)) == 0)
max_contexts = rl.rlim_cur * FDCACHE_PERCENTAGE;
(void) enable_extended_FILE_stdio(-1, -1);
}
gssd_ctx_slot_tbl = (struct gssd_ctx_slot *)
malloc(sizeof (struct gssd_ctx_slot) * max_contexts);
if (gssd_ctx_slot_tbl == NULL) {
(void) fprintf(stderr,
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-1].lru_next = &gssd_ctx_slot_tbl[i];
gssd_ctx_slot_tbl[i].lru_prev = &gssd_ctx_slot_tbl[i-1];
gssd_ctx_slot_tbl[i].inuse = FALSE;
gssd_ctx_slot_tbl[i].verf = 0;
gssd_ctx_slot_tbl[i].create_time = 0;
gssd_ctx_slot_tbl[i].rpcctx = (gss_ctx_id_t)(i + 1);
}
gssd_ctx_slot_tbl[max_contexts - 1].lru_next = &gssd_ctx_slot_tbl[0];
gssd_ctx_slot_tbl[0].lru_prev = &gssd_ctx_slot_tbl[max_contexts - 1];
gssd_ctx_slot_tbl[0].inuse = FALSE;
gssd_ctx_slot_tbl[0].verf = 0;
gssd_ctx_slot_tbl[0].create_time = 0;
gssd_ctx_slot_tbl[0].rpcctx = (gss_ctx_id_t)1;
gssd_lru_head = &gssd_ctx_slot_tbl[0];
}
static OM_uint32 syslog_interval = 60;
static struct gssd_ctx_slot *
gssd_alloc_slot(gss_ctx_id_t ctx)
{
struct gssd_ctx_slot *lru;
OM_uint32 current_time;
static OM_uint32 last_syslog = 0;
static bool_t first_take = TRUE;
static int tooks;
OM_uint32 minor_status;
lru = gssd_lru_head;
gssd_lru_head = lru->lru_next;
current_time = (OM_uint32) time(NULL);
if (last_syslog == 0)
last_syslog = current_time; /* Save 1st alloc time */
if (lru->inuse) {
if (lru->ctx != GSS_C_NO_CONTEXT)
(void) gss_delete_sec_context(&minor_status,
&lru->ctx, NULL);
tooks++;
if (((current_time - last_syslog) > syslog_interval) ||
first_take) {
syslog(LOG_WARNING, gettext("re-used an existing "
"context slot of age %u seconds (%d slots re-"
"used during last %u seconds)"),
current_time - lru->create_time, tooks,
current_time - last_syslog);
last_syslog = current_time;
tooks = 0;
first_take = FALSE;
}
}
/*
* Assign the next context verifier to the context (avoiding zero).
*/
context_verf++;
if (context_verf == 0)
context_verf = 1;
lru->verf = context_verf;
lru->create_time = current_time;
lru->ctx = ctx;
lru->inuse = TRUE;
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 *
gssd_handle_to_slot(GSS_CTX_ID_T *h)
{
intptr_t i;
if (h->GSS_CTX_ID_T_len == 0) {
return (NULL);
}
if (h->GSS_CTX_ID_T_len != sizeof (i))
return (NULL);
i = (*(intptr_t *)(h->GSS_CTX_ID_T_val)) - 1;
if (i < 0 || i >= max_contexts)
return (NULL);
return (&gssd_ctx_slot_tbl[i]);
}
static void
gssd_rel_slot(struct gssd_ctx_slot *lru)
{
struct gssd_ctx_slot *prev, *next;
if (lru == NULL)
return;
lru->inuse = FALSE;
/*
* Remove entry from its current location in list
*/
prev = lru->lru_prev;
next = lru->lru_next;
prev->lru_next = next;
next->lru_prev = prev;
/*
* Since it is no longer in use, it is the least recently
* used.
*/
prev = gssd_lru_head->lru_prev;
next = gssd_lru_head;
prev->lru_next = lru;
lru->lru_prev = prev;
next->lru_prev = lru;
lru->lru_next = next;
gssd_lru_head = lru;
}
static void
gssd_convert_context_handle(GSS_CTX_ID_T *h,
gss_ctx_id_t *context_handle,
OM_uint32 verf,
bool_t *context_verf_ok,
struct gssd_ctx_slot **slotp)
{
struct gssd_ctx_slot *slot;
*context_verf_ok = FALSE;
*context_handle = (gss_ctx_id_t)1;
if (slotp != NULL)
*slotp = NULL;
if (h->GSS_CTX_ID_T_len == 0) {
*context_handle = GSS_C_NO_CONTEXT;
*context_verf_ok = TRUE;
return;
}
slot = gssd_handle_to_slot(h);
if (slot == NULL)
return;
if (verf != slot->verf)
return;
*context_verf_ok = TRUE;
*context_handle = slot->ctx;
if (slotp != NULL)
*slotp = slot;
}
bool_t
gss_acquire_cred_1_svc(argp, res, rqstp)
gss_acquire_cred_arg *argp;
gss_acquire_cred_res *res;
struct svc_req *rqstp;
{
OM_uint32 minor_status;
gss_name_t desired_name;
gss_OID_desc name_type_desc;
gss_OID name_type = &name_type_desc;
OM_uint32 time_req;
gss_OID_set_desc desired_mechs_desc;
gss_OID_set desired_mechs;
int cred_usage;
gss_cred_id_t output_cred_handle;
gss_OID_set actual_mechs;
gss_buffer_desc external_name;
uid_t uid;
int i, j;
if (gssd_debug)
fprintf(stderr, gettext("gss_acquire_cred\n"));
memset(res, 0, sizeof (*res));
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->output_cred_handle.GSS_CRED_ID_T_val = NULL;
res->actual_mechs.GSS_OID_SET_val = NULL;
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/* convert the desired name from external to internal format */
external_name.length = argp->desired_name.GSS_BUFFER_T_len;
external_name.value = (void *)malloc(external_name.length);
if (!external_name.value)
return (GSS_S_FAILURE);
memcpy(external_name.value, argp->desired_name.GSS_BUFFER_T_val,
external_name.length);
if (argp->name_type.GSS_OID_len == 0) {
name_type = GSS_C_NULL_OID;
} else {
name_type->length = argp->name_type.GSS_OID_len;
name_type->elements = (void *)malloc(name_type->length);
if (!name_type->elements) {
free(external_name.value);
return (GSS_S_FAILURE);
}
memcpy(name_type->elements, argp->name_type.GSS_OID_val,
name_type->length);
}
if (gss_import_name(&minor_status, &external_name, name_type,
&desired_name) != GSS_S_COMPLETE) {
res->status = (OM_uint32) GSS_S_FAILURE;
res->minor_status = minor_status;
free(external_name.value);
if (name_type != GSS_C_NULL_OID)
free(name_type->elements);
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local GSSAPI
* variables.
*/
cred_usage = argp->cred_usage;
time_req = argp->time_req;
if (argp->desired_mechs.GSS_OID_SET_len != 0) {
desired_mechs = &desired_mechs_desc;
desired_mechs->count =
(int)argp->desired_mechs.GSS_OID_SET_len;
desired_mechs->elements = (gss_OID)
malloc(sizeof (gss_OID_desc) * desired_mechs->count);
if (!desired_mechs->elements) {
free(external_name.value);
free(name_type->elements);
return (GSS_S_FAILURE);
}
for (i = 0; i < desired_mechs->count; i++) {
desired_mechs->elements[i].length =
(OM_uint32)argp->desired_mechs.
GSS_OID_SET_val[i].GSS_OID_len;
desired_mechs->elements[i].elements =
(void *)malloc(desired_mechs->elements[i].
length);
if (!desired_mechs->elements[i].elements) {
free(external_name.value);
free(name_type->elements);
for (j = 0; j < (i -1); j++) {
free
(desired_mechs->elements[j].elements);
}
free(desired_mechs->elements);
return (GSS_S_FAILURE);
}
memcpy(desired_mechs->elements[i].elements,
argp->desired_mechs.GSS_OID_SET_val[i].
GSS_OID_val,
desired_mechs->elements[i].length);
}
} else
desired_mechs = GSS_C_NULL_OID_SET;
/* call the gssapi routine */
res->status = (OM_uint32)gss_acquire_cred(&res->minor_status,
desired_name,
time_req,
desired_mechs,
cred_usage,
&output_cred_handle,
&actual_mechs,
&res->time_rec);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
res->output_cred_handle.GSS_CRED_ID_T_len = sizeof (gss_cred_id_t);
res->output_cred_handle.GSS_CRED_ID_T_val =
(void *)malloc(sizeof (gss_cred_id_t));
if (!res->output_cred_handle.GSS_CRED_ID_T_val) {
free(external_name.value);
free(name_type->elements);
for (i = 0; i < desired_mechs->count; i++) {
free(desired_mechs->elements[i].elements);
}
free(desired_mechs->elements);
return (GSS_S_FAILURE);
}
memcpy(res->output_cred_handle.GSS_CRED_ID_T_val, &output_cred_handle,
sizeof (gss_cred_id_t));
if (actual_mechs != GSS_C_NULL_OID_SET) {
res->actual_mechs.GSS_OID_SET_len =
(uint_t)actual_mechs->count;
res->actual_mechs.GSS_OID_SET_val = (GSS_OID *)
malloc(sizeof (GSS_OID) * actual_mechs->count);
if (!res->actual_mechs.GSS_OID_SET_val) {
free(external_name.value);
free(name_type->elements);
for (i = 0; i < desired_mechs->count; i++) {
free(desired_mechs->elements[i].elements);
}
free(desired_mechs->elements);
free(res->output_cred_handle.GSS_CRED_ID_T_val);
return (GSS_S_FAILURE);
}
for (i = 0; i < actual_mechs->count; i++) {
res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len =
(uint_t)actual_mechs->elements[i].length;
res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val =
(char *)malloc(actual_mechs->elements[i].
length);
if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) {
free(external_name.value);
free(name_type->elements);
free(desired_mechs->elements);
for (j = 0; j < desired_mechs->count; j++) {
free
(desired_mechs->elements[i].elements);
}
free(res->actual_mechs.GSS_OID_SET_val);
for (j = 0; j < (i - 1); j++) {
free
(res->actual_mechs.
GSS_OID_SET_val[j].GSS_OID_val);
}
return (GSS_S_FAILURE);
}
memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
actual_mechs->elements[i].elements,
actual_mechs->elements[i].length);
}
} else
res->actual_mechs.GSS_OID_SET_len = 0;
/*
* 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)
*/
if (res->status == GSS_S_COMPLETE) {
res->gssd_cred_verifier = (OM_uint32)time(NULL);
if (res->gssd_cred_verifier == gssd_time_verf) {
sleep(1);
gssd_time_verf = (OM_uint32)time(NULL);
}
res->gssd_cred_verifier = gssd_time_verf;
}
/*
* 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
*/
free(external_name.value);
if (name_type != GSS_C_NULL_OID)
free(name_type->elements);
gss_release_name(&minor_status, &desired_name);
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);
}
if (desired_mechs != GSS_C_NULL_OID_SET) {
for (i = 0; i < desired_mechs->count; i++)
free(desired_mechs->elements[i].elements);
free(desired_mechs->elements);
}
/* return to caller */
return (TRUE);
}
bool_t
gss_add_cred_1_svc(argp, res, rqstp)
gss_add_cred_arg *argp;
gss_add_cred_res *res;
struct svc_req *rqstp;
{
OM_uint32 minor_status;
gss_name_t desired_name;
gss_OID_desc name_type_desc;
gss_OID name_type = &name_type_desc;
gss_OID_desc desired_mech_type_desc;
gss_OID desired_mech_type = &desired_mech_type_desc;
int cred_usage;
gss_cred_id_t input_cred_handle;
gss_OID_set actual_mechs;
gss_buffer_desc external_name;
uid_t uid;
int i, j;
if (gssd_debug)
fprintf(stderr, gettext("gss_add_cred\n"));
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
res->minor_status = 0;
res->actual_mechs.GSS_OID_SET_len = 0;
res->actual_mechs.GSS_OID_SET_val = NULL;
res->initiator_time_rec = 0;
res->acceptor_time_rec = 0;
fprintf(stderr, gettext("gss_add_cred defective cred\n"));
return (TRUE);
}
memset(res, 0, sizeof (*res));
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/* convert the desired name from external to internal format */
external_name.length = argp->desired_name.GSS_BUFFER_T_len;
external_name.value = (void *)argp->desired_name.GSS_BUFFER_T_val;
name_type->length = argp->name_type.GSS_OID_len;
name_type->elements = (void *)argp->name_type.GSS_OID_val;
if (gss_import_name(&minor_status, &external_name, name_type,
&desired_name) != GSS_S_COMPLETE) {
if (gssd_debug)
fprintf(stderr,
gettext("gss_add_cred:import name"),
gettext(" failed status %d \n"),
res->status);
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = minor_status;
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local GSSAPI
* variables.
*/
cred_usage = argp->cred_usage;
if (argp->desired_mech_type.GSS_OID_len == 0)
desired_mech_type = GSS_C_NULL_OID;
else {
desired_mech_type->length =
(OM_uint32)argp->desired_mech_type.GSS_OID_len;
desired_mech_type->elements =
(void *)malloc(desired_mech_type->length);
if (!desired_mech_type->elements) {
return (GSS_S_FAILURE);
}
memcpy(desired_mech_type->elements,
argp->desired_mech_type.GSS_OID_val,
desired_mech_type->length);
}
input_cred_handle =
(argp->input_cred_handle.GSS_CRED_ID_T_len == 0 ?
GSS_C_NO_CREDENTIAL :
/*LINTED*/
*((gss_cred_id_t *)argp->input_cred_handle.
GSS_CRED_ID_T_val));
if (input_cred_handle != GSS_C_NO_CREDENTIAL)
/* verify the input_cred_handle */
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
res->minor_status = 0;
return (TRUE);
}
/* call the gssapi routine */
res->status = (OM_uint32)gss_add_cred(&res->minor_status,
input_cred_handle,
desired_name,
desired_mech_type,
cred_usage,
argp->initiator_time_req,
argp->acceptor_time_req,
NULL,
&actual_mechs,
&res->initiator_time_rec,
&res->acceptor_time_rec);
if ((res->status != GSS_S_COMPLETE) &&
(res->status != GSS_S_DUPLICATE_ELEMENT) &&
(gssd_debug))
fprintf(stderr, gettext("gss_add_cred failed status %d \n"),
res->status);
/*
* 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) {
res->actual_mechs.GSS_OID_SET_len =
(uint_t)actual_mechs->count;
res->actual_mechs.GSS_OID_SET_val = (GSS_OID *)
malloc(sizeof (GSS_OID) * actual_mechs->count);
if (!res->actual_mechs.GSS_OID_SET_val) {
free(desired_mech_type->elements);
free(desired_mech_type);
return (GSS_S_FAILURE);
}
for (i = 0; i < actual_mechs->count; i++) {
res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_len =
(uint_t)actual_mechs->elements[i].length;
res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val =
(char *)malloc(actual_mechs->elements[i].
length);
if (!res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val) {
free(desired_mech_type->elements);
free(desired_mech_type);
free(res->actual_mechs.GSS_OID_SET_val);
for (j = 0; j < (i - 1); j++) {
free
(res->actual_mechs.
GSS_OID_SET_val[j].GSS_OID_val);
}
return (GSS_S_FAILURE);
}
memcpy(res->actual_mechs.GSS_OID_SET_val[i].GSS_OID_val,
actual_mechs->elements[i].elements,
actual_mechs->elements[i].length);
}
} else
res->actual_mechs.GSS_OID_SET_len = 0;
/*
* now release the space allocated for
* desired_name and desired_mech_type
*/
gss_release_name(&minor_status, &desired_name);
free(desired_mech_type->elements);
gss_release_oid_set(&minor_status, &actual_mechs);
/*
* 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);
}
bool_t
gss_release_cred_1_svc(argp, res, rqstp)
gss_release_cred_arg *argp;
gss_release_cred_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_cred_id_t cred_handle;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_release_cred\n"));
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/*
* if the cred_handle verifier is not correct,
* set status to GSS_S_DEFECTIVE_CREDENTIAL and return
*/
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
return (TRUE);
}
/*
* if the cred_handle length is 0
* set cred_handle argument to GSS_S_NO_CREDENTIAL
*/
if (argp->cred_handle.GSS_CRED_ID_T_len == 0)
cred_handle = GSS_C_NO_CREDENTIAL;
else
cred_handle =
(gss_cred_id_t)argp->cred_handle.GSS_CRED_ID_T_val;
/* call the gssapi routine */
res->status = (OM_uint32)gss_release_cred(&res->minor_status,
&cred_handle);
/* return to caller */
return (TRUE);
}
bool_t
gss_init_sec_context_1_svc(argp, res, rqstp)
gss_init_sec_context_arg *argp;
gss_init_sec_context_res *res;
struct svc_req *rqstp;
{
OM_uint32 minor_status;
gss_ctx_id_t context_handle;
bool_t context_verf_ok;
gss_cred_id_t claimant_cred_handle;
gss_buffer_desc external_name;
gss_OID_desc name_type_desc;
gss_OID name_type = &name_type_desc;
gss_name_t internal_name;
gss_OID_desc mech_type_desc;
gss_OID mech_type = &mech_type_desc;
struct gss_channel_bindings_struct
input_chan_bindings;
gss_channel_bindings_t input_chan_bindings_ptr;
gss_buffer_desc input_token;
gss_buffer_desc output_token;
gss_buffer_t input_token_ptr;
gss_OID actual_mech_type;
struct gssd_ctx_slot *slot = NULL;
uid_t uid;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_init_sec_context\n"));
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->actual_mech_type.GSS_OID_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/*
* copy the supplied context handle into the local context handle, so it
* can be supplied to the gss_init_sec_context call
*/
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, &slot);
claimant_cred_handle =
(argp->claimant_cred_handle.GSS_CRED_ID_T_len == 0 ?
GSS_C_NO_CREDENTIAL :
/*LINTED*/
*((gss_cred_id_t *)argp->claimant_cred_handle.
GSS_CRED_ID_T_val));
if (claimant_cred_handle != GSS_C_NO_CREDENTIAL) {
/* verify the verifier_cred_handle */
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
res->actual_mech_type.GSS_OID_val = NULL;
res->context_handle.GSS_CTX_ID_T_len = 0;
res->output_token.GSS_BUFFER_T_len = 0;
res->actual_mech_type.GSS_OID_len = 0;
res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
res->minor_status = 0;
return (TRUE);
}
}
if (context_handle != GSS_C_NO_CONTEXT) {
/* verify the verifier_context_handle */
if (!context_verf_ok) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
res->actual_mech_type.GSS_OID_val = NULL;
res->context_handle.GSS_CTX_ID_T_len = 0;
res->output_token.GSS_BUFFER_T_len = 0;
res->actual_mech_type.GSS_OID_len = 0;
res->status = (OM_uint32)GSS_S_NO_CONTEXT;
res->minor_status = 0;
return (TRUE);
}
}
/* convert the target name from external to internal format */
external_name.length = argp->target_name.GSS_BUFFER_T_len;
external_name.value = (void *)argp->target_name.GSS_BUFFER_T_val;
if (argp->name_type.GSS_OID_len == 0) {
name_type = GSS_C_NULL_OID;
} else {
name_type->length = argp->name_type.GSS_OID_len;
name_type->elements = (void *)malloc(name_type->length);
if (!name_type->elements)
return (GSS_S_FAILURE);
memcpy(name_type->elements, argp->name_type.GSS_OID_val,
name_type->length);
}
if (argp->mech_type.GSS_OID_len == 0)
mech_type = GSS_C_NULL_OID;
else {
mech_type->length = (OM_uint32)argp->mech_type.GSS_OID_len;
mech_type->elements = (void *)argp->mech_type.GSS_OID_val;
}
if (gss_import_name(&minor_status, &external_name, name_type,
&internal_name) != GSS_S_COMPLETE) {
if (name_type != GSS_C_NULL_OID)
free(name_type->elements);
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = minor_status;
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local GSSAPI
* variables.
*/
if (argp->input_chan_bindings.present == YES) {
input_chan_bindings_ptr = &input_chan_bindings;
input_chan_bindings.initiator_addrtype =
(OM_uint32)argp->input_chan_bindings.
initiator_addrtype;
input_chan_bindings.initiator_address.length =
(uint_t)argp->input_chan_bindings.initiator_address.
GSS_BUFFER_T_len;
input_chan_bindings.initiator_address.value =
(void *)argp->input_chan_bindings.initiator_address.
GSS_BUFFER_T_val;
input_chan_bindings.acceptor_addrtype =
(OM_uint32)argp->input_chan_bindings.acceptor_addrtype;
input_chan_bindings.acceptor_address.length =
(uint_t)argp->input_chan_bindings.acceptor_address.
GSS_BUFFER_T_len;
input_chan_bindings.acceptor_address.value =
(void *)argp->input_chan_bindings.acceptor_address.
GSS_BUFFER_T_val;
input_chan_bindings.application_data.length =
(uint_t)argp->input_chan_bindings.application_data.
GSS_BUFFER_T_len;
input_chan_bindings.application_data.value =
(void *)argp->input_chan_bindings.application_data.
GSS_BUFFER_T_val;
} else {
input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS;
input_chan_bindings.initiator_addrtype = 0;
input_chan_bindings.initiator_address.length = 0;
input_chan_bindings.initiator_address.value = 0;
input_chan_bindings.acceptor_addrtype = 0;
input_chan_bindings.acceptor_address.length = 0;
input_chan_bindings.acceptor_address.value = 0;
input_chan_bindings.application_data.length = 0;
input_chan_bindings.application_data.value = 0;
}
if (argp->input_token.GSS_BUFFER_T_len == 0) {
input_token_ptr = GSS_C_NO_BUFFER;
} else {
input_token_ptr = &input_token;
input_token.length = (size_t)
argp->input_token.GSS_BUFFER_T_len;
input_token.value = (void *)argp->input_token.GSS_BUFFER_T_val;
}
/* call the gssapi routine */
res->status = (OM_uint32)gss_init_sec_context(&res->minor_status,
(gss_cred_id_t)argp->claimant_cred_handle.
GSS_CRED_ID_T_val,
&context_handle,
internal_name,
mech_type,
argp->req_flags,
argp->time_req,
input_chan_bindings_ptr,
input_token_ptr,
&actual_mech_type,
&output_token,
&res->ret_flags,
&res->time_rec);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
if (res->status == (OM_uint32)GSS_S_COMPLETE ||
res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
if (slot == NULL || slot->ctx != context_handle) {
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
slot = gssd_alloc_slot(context_handle);
}
res->gssd_context_verifier = slot->verf;
res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
res->context_handle.GSS_CTX_ID_T_val =
(void *)malloc(sizeof (gss_ctx_id_t));
if (!res->context_handle.GSS_CTX_ID_T_val) {
free(name_type->elements);
return (GSS_S_FAILURE);
}
memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
sizeof (gss_ctx_id_t));
res->output_token.GSS_BUFFER_T_len =
(uint_t)output_token.length;
res->output_token.GSS_BUFFER_T_val =
(char *)output_token.value;
/*
* the actual mech type parameter
* is ready only upon GSS_S_COMPLETE
*/
if (res->status == GSS_S_COMPLETE) {
res->actual_mech_type.GSS_OID_len =
(uint_t)actual_mech_type->length;
res->actual_mech_type.GSS_OID_val =
(void *)malloc(actual_mech_type->length);
if (!res->actual_mech_type.GSS_OID_val) {
free(name_type->elements);
free(res->context_handle.GSS_CTX_ID_T_val);
return (GSS_S_FAILURE);
}
memcpy(res->actual_mech_type.GSS_OID_val,
(char *)actual_mech_type->elements,
actual_mech_type->length);
} else
res->actual_mech_type.GSS_OID_len = 0;
} else {
if (context_handle != GSS_C_NO_CONTEXT) {
(void) gss_delete_sec_context(&minor_status,
&context_handle, NULL);
}
res->context_handle.GSS_CTX_ID_T_len = 0;
res->actual_mech_type.GSS_OID_len = 0;
res->output_token.GSS_BUFFER_T_len = 0;
}
/*
* now release the space allocated by the underlying gssapi mechanism
* library for internal_name and for the name_type.
*/
gss_release_name(&minor_status, &internal_name);
if (name_type != GSS_C_NULL_OID)
free(name_type->elements);
/* return to caller */
return (TRUE);
}
bool_t
gss_accept_sec_context_1_svc(argp, res, rqstp)
gss_accept_sec_context_arg *argp;
gss_accept_sec_context_res *res;
struct svc_req *rqstp;
{
uid_t uid;
OM_uint32 minor_status;
gss_ctx_id_t context_handle = NULL;
gss_cred_id_t verifier_cred_handle;
gss_buffer_desc external_name;
gss_name_t internal_name = NULL;
gss_buffer_desc input_token_buffer;
gss_buffer_t input_token_buffer_ptr;
struct gss_channel_bindings_struct
input_chan_bindings;
gss_channel_bindings_t input_chan_bindings_ptr;
gss_OID mech_type;
gss_buffer_desc output_token;
gss_cred_id_t delegated_cred_handle;
bool_t context_verf_ok;
struct gssd_ctx_slot *slot = NULL;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_accept_sec_context\n"));
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->src_name.GSS_BUFFER_T_val = NULL;
res->mech_type.GSS_OID_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/*
* copy the supplied context handle into the local context handle, so
* it can be supplied to the gss_accept_sec_context call
*/
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, &slot);
if (context_handle != GSS_C_NO_CONTEXT)
/* verify the context_handle */
if (!context_verf_ok) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->src_name.GSS_BUFFER_T_val = NULL;
res->mech_type.GSS_OID_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
res->src_name.GSS_BUFFER_T_len = 0;
res->context_handle.GSS_CTX_ID_T_len = 0;
res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
res->output_token.GSS_BUFFER_T_len = 0;
res->mech_type.GSS_OID_len = 0;
res->status = (OM_uint32)GSS_S_NO_CONTEXT;
res->minor_status = 0;
return (TRUE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
verifier_cred_handle =
(argp->verifier_cred_handle.GSS_CRED_ID_T_len == 0 ?
GSS_C_NO_CREDENTIAL :
/*LINTED*/
*((gss_cred_id_t *)argp->verifier_cred_handle.
GSS_CRED_ID_T_val));
if (verifier_cred_handle != GSS_C_NO_CREDENTIAL)
/* verify the verifier_cred_handle */
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->src_name.GSS_BUFFER_T_val = NULL;
res->mech_type.GSS_OID_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
res->delegated_cred_handle.GSS_CRED_ID_T_val = NULL;
res->src_name.GSS_BUFFER_T_len = 0;
res->context_handle.GSS_CTX_ID_T_len = 0;
res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
res->output_token.GSS_BUFFER_T_len = 0;
res->mech_type.GSS_OID_len = 0;
res->status = (OM_uint32)GSS_S_DEFECTIVE_CREDENTIAL;
res->minor_status = 0;
return (TRUE);
}
if (argp->input_token_buffer.GSS_BUFFER_T_len == 0) {
input_token_buffer_ptr = GSS_C_NO_BUFFER;
} else {
input_token_buffer_ptr = &input_token_buffer;
input_token_buffer.length = (size_t)argp->input_token_buffer.
GSS_BUFFER_T_len;
input_token_buffer.value = (void *)argp->input_token_buffer.
GSS_BUFFER_T_val;
}
if (argp->input_chan_bindings.present == YES) {
input_chan_bindings_ptr = &input_chan_bindings;
input_chan_bindings.initiator_addrtype =
(OM_uint32)argp->input_chan_bindings.
initiator_addrtype;
input_chan_bindings.initiator_address.length =
(uint_t)argp->input_chan_bindings.initiator_address.
GSS_BUFFER_T_len;
input_chan_bindings.initiator_address.value =
(void *)argp->input_chan_bindings.initiator_address.
GSS_BUFFER_T_val;
input_chan_bindings.acceptor_addrtype =
(OM_uint32)argp->input_chan_bindings.
acceptor_addrtype;
input_chan_bindings.acceptor_address.length =
(uint_t)argp->input_chan_bindings.acceptor_address.
GSS_BUFFER_T_len;
input_chan_bindings.acceptor_address.value =
(void *)argp->input_chan_bindings.acceptor_address.
GSS_BUFFER_T_val;
input_chan_bindings.application_data.length =
(uint_t)argp->input_chan_bindings.application_data.
GSS_BUFFER_T_len;
input_chan_bindings.application_data.value =
(void *)argp->input_chan_bindings.application_data.
GSS_BUFFER_T_val;
} else {
input_chan_bindings_ptr = GSS_C_NO_CHANNEL_BINDINGS;
input_chan_bindings.initiator_addrtype = 0;
input_chan_bindings.initiator_address.length = 0;
input_chan_bindings.initiator_address.value = 0;
input_chan_bindings.acceptor_addrtype = 0;
input_chan_bindings.acceptor_address.length = 0;
input_chan_bindings.acceptor_address.value = 0;
input_chan_bindings.application_data.length = 0;
input_chan_bindings.application_data.value = 0;
}
/* call the gssapi routine */
res->status = (OM_uint32)gss_accept_sec_context(&res->minor_status,
&context_handle,
verifier_cred_handle,
input_token_buffer_ptr,
input_chan_bindings_ptr,
&internal_name,
&mech_type,
&output_token,
&res->ret_flags,
&res->time_rec,
&delegated_cred_handle);
/* convert the src name from internal to external format */
if (res->status == (OM_uint32)GSS_S_COMPLETE ||
res->status == (OM_uint32)GSS_S_CONTINUE_NEEDED) {
/*
* upon GSS_S_CONTINUE_NEEDED only the following
* parameters are ready: minor, ctxt, and output token
*/
res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
res->context_handle.GSS_CTX_ID_T_val =
(void *)malloc(sizeof (gss_ctx_id_t));
if (!res->context_handle.GSS_CTX_ID_T_val) {
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = 0;
return (TRUE);
}
if (slot == NULL || slot->ctx != context_handle) {
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
slot = gssd_alloc_slot(context_handle);
}
memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
sizeof (gss_ctx_id_t));
res->gssd_context_verifier = slot->verf;
res->output_token.GSS_BUFFER_T_len =
(uint_t)output_token.length;
res->output_token.GSS_BUFFER_T_val =
(char *)output_token.value;
if (res->status == GSS_S_COMPLETE) {
if (gss_export_name(&minor_status, internal_name,
&external_name)
!= GSS_S_COMPLETE) {
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = minor_status;
gss_release_name(&minor_status, &internal_name);
gss_delete_sec_context(&minor_status,
&context_handle, NULL);
free(res->context_handle.GSS_CTX_ID_T_val);
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->context_handle.GSS_CTX_ID_T_len = 0;
gss_release_buffer(&minor_status,
&output_token);
res->output_token.GSS_BUFFER_T_len = 0;
res->output_token.GSS_BUFFER_T_val = NULL;
return (TRUE);
}
res->src_name.GSS_BUFFER_T_len =
(uint_t)external_name.length;
res->src_name.GSS_BUFFER_T_val =
(void *)external_name.value;
res->delegated_cred_handle.GSS_CRED_ID_T_len =
sizeof (gss_cred_id_t);
res->delegated_cred_handle.GSS_CRED_ID_T_val =
(void *)malloc(sizeof (gss_cred_id_t));
if (!res->delegated_cred_handle.GSS_CRED_ID_T_val) {
free(res->context_handle.GSS_CTX_ID_T_val);
gss_release_name(&minor_status, &internal_name);
gss_delete_sec_context(&minor_status,
&context_handle, NULL);
gss_release_buffer(&minor_status,
&external_name);
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = 0;
return (TRUE);
}
memcpy(res->delegated_cred_handle.GSS_CRED_ID_T_val,
&delegated_cred_handle,
sizeof (gss_cred_id_t));
res->mech_type.GSS_OID_len = (uint_t)mech_type->length;
res->mech_type.GSS_OID_val =
(void *)malloc(mech_type->length);
if (!res->mech_type.GSS_OID_val) {
free(res->context_handle.GSS_CTX_ID_T_val);
free(res->delegated_cred_handle.GSS_CRED_ID_T_val);
gss_release_name(&minor_status, &internal_name);
gss_delete_sec_context(&minor_status,
&context_handle, NULL);
gss_release_buffer(&minor_status, &external_name);
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = 0;
return (TRUE);
}
memcpy(res->mech_type.GSS_OID_val, mech_type->elements,
mech_type->length);
/* release the space allocated for internal_name */
gss_release_name(&minor_status, &internal_name);
} else { /* GSS_S_CONTINUE_NEEDED */
res->src_name.GSS_BUFFER_T_len = 0;
res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
res->mech_type.GSS_OID_len = 0;
}
} else {
if (context_handle != GSS_C_NO_CONTEXT) {
(void) gss_delete_sec_context(&minor_status,
&context_handle, NULL);
}
res->src_name.GSS_BUFFER_T_len = 0;
res->context_handle.GSS_CTX_ID_T_len = 0;
res->delegated_cred_handle.GSS_CRED_ID_T_len = 0;
res->output_token.GSS_BUFFER_T_len = 0;
res->mech_type.GSS_OID_len = 0;
}
/* return to caller */
return (TRUE);
}
bool_t
gss_process_context_token_1_svc(argp, res, rqstp)
gss_process_context_token_arg *argp;
gss_process_context_token_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_buffer_desc token_buffer;
gss_ctx_id_t context_handle;
bool_t context_verf_ok;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_process_context_token\n"));
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, NULL);
/* verify the context_handle */
if (!context_verf_ok) {
res->status = (OM_uint32) GSS_S_NO_CONTEXT;
res->minor_status = 0;
return (TRUE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len;
token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val;
/* call the gssapi routine */
res->status = (OM_uint32)gss_process_context_token(&res->minor_status,
context_handle,
&token_buffer);
/* return to caller */
return (TRUE);
}
bool_t
gss_delete_sec_context_1_svc(argp, res, rqstp)
gss_delete_sec_context_arg *argp;
gss_delete_sec_context_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_ctx_id_t context_handle;
gss_buffer_desc output_token;
bool_t context_verf_ok;
struct gssd_ctx_slot *slot = NULL;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_delete_sec_context\n"));
/*
* copy the supplied context handle into the local context handle, so it
* can be supplied to the gss_delete_sec_context call
*/
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, &slot);
/* verify the context_handle */
if (!context_verf_ok) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->context_handle.GSS_CTX_ID_T_len = 0;
res->output_token.GSS_BUFFER_T_val = NULL;
res->output_token.GSS_BUFFER_T_len = 0;
res->status = (OM_uint32)GSS_S_NO_CONTEXT;
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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->output_token.GSS_BUFFER_T_val = NULL;
return (FALSE);
}
/* call the gssapi routine */
res->status = (OM_uint32)gss_delete_sec_context(&res->minor_status,
&context_handle,
&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 (res->status == GSS_S_COMPLETE) {
if (context_handle != GSS_C_NO_CONTEXT)
return (GSS_S_FAILURE);
res->context_handle.GSS_CTX_ID_T_len = 0;
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->output_token.GSS_BUFFER_T_len =
(uint_t)output_token.length;
res->output_token.GSS_BUFFER_T_val =
(char *)output_token.value;
if (slot != NULL) {
/*
* gss_delete_sec_context deletes the context if it
* succeeds so clear slot->ctx to avoid a dangling
* reference.
*/
slot->ctx = GSS_C_NO_CONTEXT;
gssd_rel_slot(slot);
}
} else {
res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
res->context_handle.GSS_CTX_ID_T_val =
(void *)malloc(sizeof (gss_ctx_id_t));
if (!res->context_handle.GSS_CTX_ID_T_val) {
return (GSS_S_FAILURE);
}
if (slot == NULL || slot->ctx != context_handle) {
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
slot = gssd_alloc_slot(context_handle);
/*
* 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.
*/
}
memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
sizeof (gss_ctx_id_t));
res->output_token.GSS_BUFFER_T_len = 0;
res->output_token.GSS_BUFFER_T_val = NULL;
}
/* return to caller */
return (TRUE);
}
bool_t
gss_export_sec_context_1_svc(argp, res, rqstp)
gss_export_sec_context_arg *argp;
gss_export_sec_context_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_ctx_id_t context_handle;
gss_buffer_desc output_token;
bool_t context_verf_ok;
struct gssd_ctx_slot *slot = NULL;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, "gss_export_sec_context\n");
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->output_token.GSS_BUFFER_T_val = 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
*/
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, &slot);
/* verify the context_handle */
if (!context_verf_ok) {
res->status = (OM_uint32)GSS_S_NO_CONTEXT;
/* the rest of "res" was cleared by a previous memset() */
return (TRUE);
}
/* call the gssapi routine */
res->status = (OM_uint32)gss_export_sec_context(&res->minor_status,
&context_handle,
&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 (res->status == GSS_S_COMPLETE) {
if (context_handle != GSS_C_NO_CONTEXT)
return (GSS_S_FAILURE);
res->context_handle.GSS_CTX_ID_T_len = 0;
res->context_handle.GSS_CTX_ID_T_val = NULL;
res->output_token.GSS_BUFFER_T_len =
(uint_t)output_token.length;
res->output_token.GSS_BUFFER_T_val =
(char *)output_token.value;
if (slot != NULL) {
/*
* gss_export_sec_context deletes the context if it
* succeeds so set slot->ctx to avoid a dangling
* reference.
*/
slot->ctx = GSS_C_NO_CONTEXT;
gssd_rel_slot(slot);
}
} else {
res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
res->context_handle.GSS_CTX_ID_T_val =
(void *)malloc(sizeof (gss_ctx_id_t));
if (slot == NULL || slot->ctx != context_handle) {
/*
* Note that gssd_alloc_slot() will delete ctx's as long
* as we don't call gssd_rel_slot().
*/
slot = gssd_alloc_slot(context_handle);
/*
* 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.
*/
}
memcpy(res->context_handle.GSS_CTX_ID_T_val, &slot->rpcctx,
sizeof (gss_ctx_id_t));
res->output_token.GSS_BUFFER_T_len = 0;
res->output_token.GSS_BUFFER_T_val = NULL;
}
/* return to caller */
return (TRUE);
}
/*
* This routine doesn't appear to ever be called.
*/
bool_t
gss_import_sec_context_1_svc(argp, res, rqstp)
gss_import_sec_context_arg *argp;
gss_import_sec_context_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_ctx_id_t context_handle;
gss_buffer_desc input_token;
gss_buffer_t input_token_ptr;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, "gss_export_sec_context\n");
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->context_handle.GSS_CTX_ID_T_val = NULL;
return (FALSE);
}
if (argp->input_token.GSS_BUFFER_T_len == 0) {
input_token_ptr = GSS_C_NO_BUFFER;
} else {
input_token_ptr = &input_token;
input_token.length = (size_t)
argp->input_token.GSS_BUFFER_T_len;
input_token.value = (void *) argp->input_token.GSS_BUFFER_T_val;
}
/* call the gssapi routine */
res->status = (OM_uint32) gss_import_sec_context(&res->minor_status,
input_token_ptr,
&context_handle);
/*
* 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 (res->status == GSS_S_COMPLETE) {
res->context_handle.GSS_CTX_ID_T_len = sizeof (gss_ctx_id_t);
res->context_handle.GSS_CTX_ID_T_val =
(void *) malloc(sizeof (gss_ctx_id_t));
memcpy(res->context_handle.GSS_CTX_ID_T_val, &context_handle,
sizeof (gss_ctx_id_t));
} else {
res->context_handle.GSS_CTX_ID_T_len = 0;
res->context_handle.GSS_CTX_ID_T_val = NULL;
}
/* return to caller */
return (TRUE);
}
bool_t
gss_context_time_1_svc(argp, res, rqstp)
gss_context_time_arg *argp;
gss_context_time_res *res;
struct svc_req *rqstp;
{
uid_t uid;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_context_time\n"));
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/* Semantics go here */
return (TRUE);
}
bool_t
gss_sign_1_svc(argp, res, rqstp)
gss_sign_arg *argp;
gss_sign_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_buffer_desc message_buffer;
gss_buffer_desc msg_token;
gss_ctx_id_t context_handle;
bool_t context_verf_ok;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_sign\n"));
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, NULL);
/* verify the context_handle */
if (!context_verf_ok) {
res->msg_token.GSS_BUFFER_T_val = NULL;
res->msg_token.GSS_BUFFER_T_len = 0;
res->status = (OM_uint32) GSS_S_NO_CONTEXT;
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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->msg_token.GSS_BUFFER_T_val = NULL;
return (FALSE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len;
message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val;
/* call the gssapi routine */
res->status = (OM_uint32)gss_sign(&res->minor_status,
context_handle,
argp->qop_req,
(gss_buffer_t)&message_buffer,
(gss_buffer_t)&msg_token);
/*
* convert the output args from the parameter given in the call to
* the variable in the XDR result
*/
if (res->status == GSS_S_COMPLETE) {
res->msg_token.GSS_BUFFER_T_len = (uint_t)msg_token.length;
res->msg_token.GSS_BUFFER_T_val = (char *)msg_token.value;
}
/* return to caller */
return (TRUE);
}
bool_t
gss_verify_1_svc(argp, res, rqstp)
gss_verify_arg *argp;
gss_verify_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_buffer_desc message_buffer;
gss_buffer_desc token_buffer;
gss_ctx_id_t context_handle;
bool_t context_verf_ok;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_verify\n"));
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, NULL);
/* verify the context_handle */
if (!context_verf_ok) {
res->status = (OM_uint32) GSS_S_NO_CONTEXT;
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
*/
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
message_buffer.length = (size_t)argp->message_buffer.GSS_BUFFER_T_len;
message_buffer.value = (void *)argp->message_buffer.GSS_BUFFER_T_val;
token_buffer.length = (size_t)argp->token_buffer.GSS_BUFFER_T_len;
token_buffer.value = (void *)argp->token_buffer.GSS_BUFFER_T_val;
/* call the gssapi routine */
res->status = (OM_uint32)gss_verify(&res->minor_status,
context_handle,
&message_buffer,
&token_buffer,
&res->qop_state);
/* return to caller */
return (TRUE);
}
/* EXPORT DELETE START */
bool_t
gss_seal_1_svc(argp, res, rqstp)
gss_seal_arg *argp;
gss_seal_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_buffer_desc input_message_buffer;
gss_buffer_desc output_message_buffer;
gss_ctx_id_t context_handle;
bool_t context_verf_ok;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_seal\n"));
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, NULL);
/* verify the context_handle */
if (!context_verf_ok) {
res->output_message_buffer.GSS_BUFFER_T_val = NULL;
res->output_message_buffer.GSS_BUFFER_T_len = 0;
res->status = (OM_uint32) GSS_S_NO_CONTEXT;
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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->output_message_buffer.GSS_BUFFER_T_val = NULL;
return (FALSE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
input_message_buffer.length = (size_t)argp->input_message_buffer.
GSS_BUFFER_T_len;
input_message_buffer.value = (void *)argp->input_message_buffer.
GSS_BUFFER_T_val;
/* call the gssapi routine */
res->status = (OM_uint32)gss_seal(&res->minor_status,
context_handle,
argp->conf_req_flag,
argp->qop_req,
&input_message_buffer,
&res->conf_state,
&output_message_buffer);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
if (res->status == GSS_S_COMPLETE) {
res->output_message_buffer.GSS_BUFFER_T_len =
(uint_t)output_message_buffer.length;
res->output_message_buffer.GSS_BUFFER_T_val =
(char *)output_message_buffer.value;
}
/* return to caller */
return (TRUE);
}
bool_t
gss_unseal_1_svc(argp, res, rqstp)
gss_unseal_arg *argp;
gss_unseal_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_buffer_desc input_message_buffer;
gss_buffer_desc output_message_buffer;
gss_ctx_id_t context_handle;
bool_t context_verf_ok;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_unseal\n"));
/* verify the context_handle */
gssd_convert_context_handle(&argp->context_handle, &context_handle,
argp->gssd_context_verifier, &context_verf_ok, NULL);
/* verify the context_handle */
if (!context_verf_ok) {
res->output_message_buffer.GSS_BUFFER_T_val = NULL;
res->output_message_buffer.GSS_BUFFER_T_len = 0;
res->status = (OM_uint32)GSS_S_NO_CONTEXT;
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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->output_message_buffer.GSS_BUFFER_T_val = NULL;
return (FALSE);
}
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variable equivalents.
*/
input_message_buffer.length = (size_t)argp->input_message_buffer.
GSS_BUFFER_T_len;
input_message_buffer.value = (void *)argp->input_message_buffer.
GSS_BUFFER_T_val;
/* call the gssapi routine */
res->status = (OM_uint32)gss_unseal(&res->minor_status,
context_handle,
&input_message_buffer,
&output_message_buffer,
&res->conf_state,
&res->qop_state);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
if (res->status == GSS_S_COMPLETE) {
res->output_message_buffer.GSS_BUFFER_T_len =
(uint_t)output_message_buffer.length;
res->output_message_buffer.GSS_BUFFER_T_val =
(char *)output_message_buffer.value;
}
/* return to caller */
return (TRUE);
}
/* EXPORT DELETE END */
bool_t
gss_display_status_1_svc(argp, res, rqstp)
gss_display_status_arg *argp;
gss_display_status_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_OID mech_type;
gss_OID_desc mech_type_desc;
gss_buffer_desc status_string;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_display_status\n"));
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->status_string.GSS_BUFFER_T_val = NULL;
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
/*
* copy the XDR structured arguments into their corresponding local
* GSSAPI variables.
*/
if (argp->mech_type.GSS_OID_len == 0)
mech_type = GSS_C_NULL_OID;
else {
mech_type = &mech_type_desc;
mech_type_desc.length = (OM_uint32) argp->mech_type.GSS_OID_len;
mech_type_desc.elements = (void *) argp->mech_type.GSS_OID_val;
}
/* call the gssapi routine */
res->status = (OM_uint32) gss_display_status(&res->minor_status,
argp->status_value,
argp->status_type,
mech_type,
(OM_uint32 *)&res->message_context,
&status_string);
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
if (res->status == GSS_S_COMPLETE) {
res->status_string.GSS_BUFFER_T_len =
(uint_t)status_string.length;
res->status_string.GSS_BUFFER_T_val =
(char *)status_string.value;
}
return (TRUE);
}
/*ARGSUSED*/
bool_t
gss_indicate_mechs_1_svc(argp, res, rqstp)
void *argp;
gss_indicate_mechs_res *res;
struct svc_req *rqstp;
{
gss_OID_set oid_set;
uid_t uid;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_indicate_mechs\n"));
res->mech_set.GSS_OID_SET_val = NULL;
/*
* 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
*/
if (checkfrom(rqstp, &uid) == 0) {
return (FALSE);
}
res->status = gss_indicate_mechs(&res->minor_status, &oid_set);
if (res->status == GSS_S_COMPLETE) {
int i, j;
res->mech_set.GSS_OID_SET_len = oid_set->count;
res->mech_set.GSS_OID_SET_val = (void *)
malloc(oid_set->count * sizeof (GSS_OID));
if (!res->mech_set.GSS_OID_SET_val) {
return (GSS_S_FAILURE);
}
for (i = 0; i < oid_set->count; i++) {
res->mech_set.GSS_OID_SET_val[i].GSS_OID_len =
oid_set->elements[i].length;
res->mech_set.GSS_OID_SET_val[i].GSS_OID_val =
(char *)malloc(oid_set->elements[i].length);
if (!res->mech_set.GSS_OID_SET_val[i].GSS_OID_val) {
for (j = 0; j < (i -1); j++) {
free
(res->mech_set.GSS_OID_SET_val[i].GSS_OID_val);
}
free(res->mech_set.GSS_OID_SET_val);
return (GSS_S_FAILURE);
}
memcpy(res->mech_set.GSS_OID_SET_val[i].GSS_OID_val,
oid_set->elements[i].elements,
oid_set->elements[i].length);
}
}
return (TRUE);
}
bool_t
gss_inquire_cred_1_svc(argp, res, rqstp)
gss_inquire_cred_arg *argp;
gss_inquire_cred_res *res;
struct svc_req *rqstp;
{
uid_t uid;
OM_uint32 minor_status;
gss_cred_id_t cred_handle;
gss_buffer_desc external_name;
gss_OID name_type;
gss_name_t internal_name;
gss_OID_set mechanisms;
int i, j;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_inquire_cred\n"));
/* verify the verifier_cred_handle */
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->name.GSS_BUFFER_T_val = NULL;
res->name_type.GSS_OID_val = NULL;
res->mechanisms.GSS_OID_SET_val = NULL;
res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL;
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
*/
if (checkfrom(rqstp, &uid) == 0) {
res->name.GSS_BUFFER_T_val = NULL;
res->name_type.GSS_OID_val = NULL;
res->mechanisms.GSS_OID_SET_val = NULL;
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ?
GSS_C_NO_CREDENTIAL :
/*LINTED*/
*((gss_cred_id_t *)argp->cred_handle.
GSS_CRED_ID_T_val));
/* call the gssapi routine */
res->status = (OM_uint32)gss_inquire_cred(&res->minor_status,
cred_handle,
&internal_name,
&res->lifetime,
&res->cred_usage,
&mechanisms);
if (res->status != GSS_S_COMPLETE)
return (TRUE);
/* convert the returned name from internal to external format */
if (gss_display_name(&minor_status, internal_name,
&external_name, &name_type)
!= GSS_S_COMPLETE) {
res->status = (OM_uint32)GSS_S_FAILURE;
res->minor_status = minor_status;
gss_release_name(&minor_status, &internal_name);
if (mechanisms != GSS_C_NULL_OID_SET) {
for (i = 0; i < mechanisms->count; i++)
free(mechanisms->elements[i].elements);
free(mechanisms->elements);
free(mechanisms);
}
return (TRUE);
}
/*
* convert the output args from the parameter given in the call to the
* variable in the XDR result
*/
res->name.GSS_BUFFER_T_len = (uint_t)external_name.length;
res->name.GSS_BUFFER_T_val = (void *)external_name.value;
/*
* 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.
*/
res->name_type.GSS_OID_len = (uint_t)name_type->length;
res->name_type.GSS_OID_val = (void *)malloc(name_type->length);
if (!res->name_type.GSS_OID_val) {
return (GSS_S_FAILURE);
}
memcpy(res->name_type.GSS_OID_val, name_type->elements,
name_type->length);
if (mechanisms != GSS_C_NULL_OID_SET) {
res->mechanisms.GSS_OID_SET_len =
(uint_t)mechanisms->count;
res->mechanisms.GSS_OID_SET_val = (GSS_OID *)
malloc(sizeof (GSS_OID) * mechanisms->count);
if (!res->mechanisms.GSS_OID_SET_val) {
free(res->name_type.GSS_OID_val);
return (GSS_S_FAILURE);
}
for (i = 0; i < mechanisms->count; i++) {
res->mechanisms.GSS_OID_SET_val[i].GSS_OID_len =
(uint_t)mechanisms->elements[i].length;
res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val =
(char *)malloc(mechanisms->elements[i].
length);
if (!res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val) {
free(res->name_type.GSS_OID_val);
for (j = 0; j < i; j++) {
free(res->mechanisms.
GSS_OID_SET_val[i].GSS_OID_val);
}
free(res->mechanisms.GSS_OID_SET_val);
return (GSS_S_FAILURE);
}
memcpy(res->mechanisms.GSS_OID_SET_val[i].GSS_OID_val,
mechanisms->elements[i].elements,
mechanisms->elements[i].length);
}
} else
res->mechanisms.GSS_OID_SET_len = 0;
/* release the space allocated for internal_name and mechanisms */
gss_release_name(&minor_status, &internal_name);
if (mechanisms != GSS_C_NULL_OID_SET) {
for (i = 0; i < mechanisms->count; i++)
free(mechanisms->elements[i].elements);
free(mechanisms->elements);
free(mechanisms);
}
/* return to caller */
return (TRUE);
}
bool_t
gss_inquire_cred_by_mech_1_svc(argp, res, rqstp)
gss_inquire_cred_by_mech_arg *argp;
gss_inquire_cred_by_mech_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_cred_id_t cred_handle;
gss_OID_desc mech_type_desc;
gss_OID mech_type = &mech_type_desc;
memset(res, 0, sizeof (*res));
if (gssd_debug)
fprintf(stderr, gettext("gss_inquire_cred\n"));
/* verify the verifier_cred_handle */
if (argp->gssd_cred_verifier != gssd_time_verf) {
res->status = (OM_uint32) GSS_S_DEFECTIVE_CREDENTIAL;
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
*/
if (checkfrom(rqstp, &uid) == 0) {
return (FALSE);
}
/* set the uid sent as the RPC argument */
uid = argp->uid;
set_gssd_uid(uid);
cred_handle = (argp->cred_handle.GSS_CRED_ID_T_len == 0 ?
GSS_C_NO_CREDENTIAL :
/*LINTED*/
*((gss_cred_id_t *)argp->cred_handle.
GSS_CRED_ID_T_val));
/* call the gssapi routine */
if (argp->mech_type.GSS_OID_len == 0)
mech_type = GSS_C_NULL_OID;
else {
mech_type->length =
(OM_uint32)argp->mech_type.GSS_OID_len;
mech_type->elements =
(void *)malloc(mech_type->length);
if (!mech_type->elements) {
return (GSS_S_FAILURE);
}
memcpy(mech_type->elements,
argp->mech_type.GSS_OID_val,
mech_type->length);
}
res->status = (OM_uint32)gss_inquire_cred_by_mech(
&res->minor_status, cred_handle,
mech_type, NULL, NULL,
NULL, NULL);
/* return to caller */
return (TRUE);
}
bool_t
gsscred_name_to_unix_cred_1_svc(argsp, res, rqstp)
gsscred_name_to_unix_cred_arg *argsp;
gsscred_name_to_unix_cred_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_OID_desc oid;
gss_name_t gssName;
gss_buffer_desc gssBuf = GSS_C_EMPTY_BUFFER;
OM_uint32 minor;
int gidsLen;
gid_t *gids, gidOut;
if (gssd_debug)
fprintf(stderr, gettext("gsscred_name_to_unix_cred\n"));
memset(res, 0, sizeof (*res));
/*
* check the request originator
*/
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
/* set the uid from the rpc request */
uid = argsp->uid;
set_gssd_uid(uid);
/*
* convert the principal name to gss internal format
* need not malloc the input parameters
*/
gssBuf.length = argsp->pname.GSS_BUFFER_T_len;
gssBuf.value = (void*)argsp->pname.GSS_BUFFER_T_val;
oid.length = argsp->name_type.GSS_OID_len;
oid.elements = (void*)argsp->name_type.GSS_OID_val;
res->major = gss_import_name(&minor, &gssBuf, &oid, &gssName);
if (res->major != GSS_S_COMPLETE)
return (TRUE);
/* retrieve the mechanism type from the arguments */
oid.length = argsp->mech_type.GSS_OID_len;
oid.elements = (void*)argsp->mech_type.GSS_OID_val;
/* call the gss extensions to map the principal name to unix creds */
res->major = gsscred_name_to_unix_cred(gssName, &oid, &uid, &gidOut,
&gids, &gidsLen);
gss_release_name(&minor, &gssName);
if (res->major == GSS_S_COMPLETE) {
res->uid = uid;
res->gid = gidOut;
res->gids.GSSCRED_GIDS_val = gids;
res->gids.GSSCRED_GIDS_len = gidsLen;
}
return (TRUE);
} /* gsscred_name_to_unix_cred_svc_1 */
bool_t
gsscred_expname_to_unix_cred_1_svc(argsp, res, rqstp)
gsscred_expname_to_unix_cred_arg *argsp;
gsscred_expname_to_unix_cred_res *res;
struct svc_req *rqstp;
{
uid_t uid;
gss_buffer_desc expName = GSS_C_EMPTY_BUFFER;
int gidsLen;
gid_t *gids, gidOut;
if (gssd_debug)
fprintf(stderr, gettext("gsscred_expname_to_unix_cred\n"));
memset(res, 0, sizeof (*res));
/*
* check the request originator
*/
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
/* set the uid from the rpc request */
uid = argsp->uid;
set_gssd_uid(uid);
/*
* extract the export name from arguments
* need not malloc the input parameters
*/
expName.length = argsp->expname.GSS_BUFFER_T_len;
expName.value = (void*)argsp->expname.GSS_BUFFER_T_val;
res->major = gsscred_expname_to_unix_cred(&expName, &uid,
&gidOut, &gids, &gidsLen);
if (res->major == GSS_S_COMPLETE) {
res->uid = uid;
res->gid = gidOut;
res->gids.GSSCRED_GIDS_val = gids;
res->gids.GSSCRED_GIDS_len = gidsLen;
}
return (TRUE);
} /* gsscred_expname_to_unix_cred_1_svc */
bool_t
gss_get_group_info_1_svc(argsp, res, rqstp)
gss_get_group_info_arg *argsp;
gss_get_group_info_res *res;
struct svc_req *rqstp;
{
uid_t uid;
int gidsLen;
gid_t *gids, gidOut;
if (gssd_debug)
fprintf(stderr, gettext("gss_get_group_info\n"));
memset(res, 0, sizeof (*res));
/*
* check the request originator
*/
if (checkfrom(rqstp, &uid) == 0)
return (FALSE);
/* set the uid from the rpc request */
uid = argsp->uid;
set_gssd_uid(uid);
/*
* extract the uid from the arguments
*/
uid = argsp->puid;
res->major = gss_get_group_info(uid, &gidOut, &gids, &gidsLen);
if (res->major == GSS_S_COMPLETE) {
res->gid = gidOut;
res->gids.GSSCRED_GIDS_val = gids;
res->gids.GSSCRED_GIDS_len = gidsLen;
}
return (TRUE);
} /* gss_get_group_info_1_svc */
/*ARGSUSED*/
bool_t
gss_get_kmod_1_svc(argsp, res, rqstp)
gss_get_kmod_arg *argsp;
gss_get_kmod_res *res;
struct svc_req *rqstp;
{
gss_OID_desc oid;
char *kmodName;
if (gssd_debug)
fprintf(stderr, gettext("gss_get_kmod\n"));
res->module_follow = FALSE;
oid.length = argsp->mech_oid.GSS_OID_len;
oid.elements = (void *)argsp->mech_oid.GSS_OID_val;
kmodName = __gss_get_kmodName(&oid);
if (kmodName != NULL) {
res->module_follow = TRUE;
res->gss_get_kmod_res_u.modname = kmodName;
}
return (TRUE);
}
/*
* Returns 1 if caller is ok, else 0.
* If caller ok, the uid is returned in uidp.
*/
static int
checkfrom(rqstp, uidp)
struct svc_req *rqstp;
uid_t *uidp;
{
SVCXPRT *xprt = rqstp->rq_xprt;
struct authunix_parms *aup;
uid_t uid;
/* check client agent uid to ensure it is privileged */
if (__rpc_get_local_uid(xprt, &uid) < 0) {
syslog(LOG_ERR, gettext("__rpc_get_local_uid failed %s %s"),
xprt->xp_netid, xprt->xp_tp);
goto weakauth;
}
if (gssd_debug)
fprintf(stderr, gettext("checkfrom: local_uid %d\n"), uid);
if (uid != 0) {
syslog(LOG_ERR,
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) {
if (rqstp->rq_cred.oa_flavor != AUTH_SYS) {
syslog(LOG_ERR, gettext("checkfrom: not UNIX credentials"));
goto weakauth;
}
/*LINTED*/
aup = (struct authunix_parms *)rqstp->rq_clntcred;
*uidp = aup->aup_uid;
if (gssd_debug) {
fprintf(stderr,
gettext("checkfrom: caller's uid %d\n"), *uidp);
}
}
return (1);
weakauth:
svcerr_weakauth(xprt);
return (0);
}