Path: blob/main/crypto/krb5/src/lib/rpc/svc_auth_gssapi.c
39536 views
/*1* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.2*3* $Id$4*5*/67/*8* svc_auth_gssapi.c9* Handles the GSS-API flavor authentication parameters on the service10* side of RPC.11*/1213#include <stdio.h>14#include <errno.h>15#include <string.h>16#include <gssrpc/rpc.h>17#include <sys/stat.h>1819#include <gssapi/gssapi_generic.h>20#include <gssrpc/auth_gssapi.h>2122#ifdef GSS_BACKWARD_HACK23#include <gssapi/gssapi_krb5.h>24#endif2526#include "gssrpcint.h"2728#ifdef GSSAPI_KRB529/* This is here for the krb5_error_code typedef and the30* KRB5KRB_AP_ERR_NOT_US #define.*/31#include <krb5.h>32#endif3334#include <sys/file.h>35#include <fcntl.h>36#include <time.h>3738#define INITIATION_TIMEOUT 60*15 /* seconds until partially created */39/* context is destroed */40#define INDEF_EXPIRE 60*60*24 /* seconds until an context with no */41/* expiration time is expired */4243#ifdef __CODECENTER__44#define DEBUG_GSSAPI 145#endif4647#ifdef DEBUG_GSSAPI48int svc_debug_gssapi = DEBUG_GSSAPI;49void gssrpcint_printf(const char *format, ...)50{51va_list ap;52va_start(ap, format);53#if 154vprintf(format, ap);55#else56{57static FILE *f;58if (f == NULL)59f = fopen("/dev/pts/4", "a");60if (f) {61vfprintf(f, format, ap);62fflush(f);63}64}65#endif66va_end(ap);67}68#define L_PRINTF(l,args) if (svc_debug_gssapi >= l) gssrpcint_printf args69#define PRINTF(args) L_PRINTF(99, args)70#define AUTH_GSSAPI_DISPLAY_STATUS(args) \71if (svc_debug_gssapi) auth_gssapi_display_status args72#else73#define PRINTF(args)74#define L_PRINTF(l, args)75#define AUTH_GSSAPI_DISPLAY_STATUS(args)76#endif7778typedef struct _svc_auth_gssapi_data {79bool_t established;8081gss_ctx_id_t context;82gss_name_t client_name, server_name;83gss_cred_id_t server_creds;8485uint32_t expiration;86uint32_t seq_num;87uint32_t key;8889SVCAUTH svcauth;9091/* kludge to free verifiers on next call */92gss_buffer_desc prev_verf;93} svc_auth_gssapi_data;9495#define SVCAUTH_PRIVATE(auth) \96((svc_auth_gssapi_data *)(auth)->svc_ah_private)9798static bool_t svc_auth_gssapi_wrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);99static bool_t svc_auth_gssapi_unwrap(SVCAUTH *, XDR *, xdrproc_t, caddr_t);100static bool_t svc_auth_gssapi_destroy(SVCAUTH *);101102static svc_auth_gssapi_data *create_client(void);103static svc_auth_gssapi_data *get_client104(gss_buffer_t client_handle);105static void destroy_client106(svc_auth_gssapi_data *client_data);107static void clean_client(void), cleanup(void);108static void client_expire109(svc_auth_gssapi_data *client_data, uint32_t exp);110static void dump_db (char *msg);111112struct svc_auth_ops svc_auth_gssapi_ops = {113svc_auth_gssapi_wrap,114svc_auth_gssapi_unwrap,115svc_auth_gssapi_destroy116};117118/*119* Globals! Eeek! Run for the hills!120*/121static gss_cred_id_t *server_creds_list = NULL;122static gss_name_t *server_name_list = NULL;123static int server_creds_count = 0;124125static auth_gssapi_log_badauth_func log_badauth = NULL;126static caddr_t log_badauth_data = NULL;127static auth_gssapi_log_badauth2_func log_badauth2 = NULL;128static caddr_t log_badauth2_data = NULL;129static auth_gssapi_log_badverf_func log_badverf = NULL;130static caddr_t log_badverf_data = NULL;131static auth_gssapi_log_miscerr_func log_miscerr = NULL;132static caddr_t log_miscerr_data = NULL;133134#define LOG_MISCERR(arg) if (log_miscerr) \135(*log_miscerr)(rqst, msg, arg, log_miscerr_data)136137typedef struct _client_list {138svc_auth_gssapi_data *client;139struct _client_list *next;140} client_list;141142static client_list *clients = NULL;143144145/* Invoke log_badauth callbacks for an authentication failure. */146static void147badauth(OM_uint32 maj, OM_uint32 minor, SVCXPRT *xprt)148{149if (log_badauth != NULL)150(*log_badauth)(maj, minor, &xprt->xp_raddr, log_badauth_data);151if (log_badauth2 != NULL)152(*log_badauth2)(maj, minor, xprt, log_badauth2_data);153}154155enum auth_stat gssrpc__svcauth_gssapi(156struct svc_req *rqst,157struct rpc_msg *msg,158bool_t *no_dispatch)159{160XDR xdrs;161auth_gssapi_creds creds;162auth_gssapi_init_arg call_arg;163auth_gssapi_init_res call_res;164gss_buffer_desc output_token, in_buf, out_buf;165gss_cred_id_t server_creds;166struct gss_channel_bindings_struct bindings, *bindp;167OM_uint32 gssstat, minor_stat, time_rec;168struct opaque_auth *cred, *verf;169svc_auth_gssapi_data *client_data;170int i;171enum auth_stat ret;172OM_uint32 ret_flags;173uint32_t seq_num;174175PRINTF(("svcauth_gssapi: starting\n"));176177/* clean up expired entries */178clean_client();179180/* use AUTH_NONE until there is a client_handle */181rqst->rq_xprt->xp_auth = &svc_auth_none;182183memset(&call_res, 0, sizeof(call_res));184creds.client_handle.length = 0;185creds.client_handle.value = NULL;186187cred = &msg->rm_call.cb_cred;188verf = &msg->rm_call.cb_verf;189190if (cred->oa_length == 0) {191PRINTF(("svcauth_gssapi: empty creds, failing\n"));192LOG_MISCERR("empty client credentials");193ret = AUTH_BADCRED;194goto error;195}196197PRINTF(("svcauth_gssapi: decoding credentials\n"));198xdrmem_create(&xdrs, cred->oa_base, cred->oa_length, XDR_DECODE);199memset(&creds, 0, sizeof(creds));200if (! xdr_authgssapi_creds(&xdrs, &creds)) {201PRINTF(("svcauth_gssapi: failed decoding creds\n"));202LOG_MISCERR("protocol error in client credentials");203xdr_free((xdrproc_t)xdr_authgssapi_creds, &creds);204XDR_DESTROY(&xdrs);205ret = AUTH_BADCRED;206goto error;207}208XDR_DESTROY(&xdrs);209210PRINTF(("svcauth_gssapi: got credentials, version %d, client_handle len %d\n",211creds.version, (int) creds.client_handle.length));212213if (creds.version != 2) {214PRINTF(("svcauth_gssapi: bad credential version\n"));215LOG_MISCERR("unsupported client credentials version");216ret = AUTH_BADCRED;217goto error;218}219220#ifdef DEBUG_GSSAPI221if (svc_debug_gssapi) {222if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_EXIT) {223PRINTF(("svcauth_gssapi: GSSAPI_EXIT, cleaning up\n"));224svc_sendreply(rqst->rq_xprt, xdr_void, NULL);225xdr_free((xdrproc_t)xdr_authgssapi_creds, &creds);226cleanup();227exit(0);228}229}230#endif231232/*233* If this is an auth_msg and proc is GSSAPI_INIT, then create a234* client handle for this client. Otherwise, look up the235* existing handle.236*/237if (creds.auth_msg && rqst->rq_proc == AUTH_GSSAPI_INIT) {238if (creds.client_handle.length != 0) {239PRINTF(("svcauth_gssapi: non-empty handle on GSSAPI_INIT\n"));240LOG_MISCERR("protocol error in client handle");241ret = AUTH_FAILED;242goto error;243}244245PRINTF(("svcauth_gssapi: GSSAPI_INIT, creating client.\n"));246247client_data = create_client();248if (client_data == NULL) {249PRINTF(("svcauth_gssapi: create_client failed\n"));250LOG_MISCERR("internal error creating client record");251ret = AUTH_FAILED;252goto error;253}254} else {255if (creds.client_handle.length == 0) {256PRINTF(("svcauth_gssapi: expected non-empty creds\n"));257LOG_MISCERR("protocol error in client credentials");258ret = AUTH_FAILED;259goto error;260}261262PRINTF(("svcauth_gssapi: incoming client_handle %d, len %d\n",263*((uint32_t *) creds.client_handle.value),264(int) creds.client_handle.length));265266client_data = get_client(&creds.client_handle);267if (client_data == NULL) {268PRINTF(("svcauth_gssapi: client_handle lookup failed\n"));269LOG_MISCERR("invalid client handle received");270ret = AUTH_BADCRED;271goto error;272}273PRINTF(("svcauth_gssapi: client_handle lookup succeeded\n"));274}275276/* any response we send will use client_handle, so set it now */277call_res.client_handle.length = sizeof(client_data->key);278call_res.client_handle.value = (char *) &client_data->key;279280/* mark this call as using AUTH_GSSAPI via client_data's SVCAUTH */281rqst->rq_xprt->xp_auth = &client_data->svcauth;282283if (client_data->established == FALSE) {284PRINTF(("svcauth_gssapi: context is not established\n"));285286if (creds.auth_msg == FALSE) {287PRINTF(("svcauth_gssapi: expected auth_msg TRUE\n"));288LOG_MISCERR("protocol error on incomplete connection");289ret = AUTH_REJECTEDCRED;290goto error;291}292293/*294* If the context is not established, then only GSSAPI_INIT295* and _CONTINUE requests are valid.296*/297if (rqst->rq_proc != AUTH_GSSAPI_INIT && rqst->rq_proc !=298AUTH_GSSAPI_CONTINUE_INIT) {299PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",300rqst->rq_proc));301LOG_MISCERR("protocol error on incomplete connection");302ret = AUTH_FAILED;303goto error;304}305306/* call is for us, deserialize arguments */307memset(&call_arg, 0, sizeof(call_arg));308if (! svc_getargs(rqst->rq_xprt, (xdrproc_t)xdr_authgssapi_init_arg,309&call_arg)) {310PRINTF(("svcauth_gssapi: cannot decode args\n"));311LOG_MISCERR("protocol error in procedure arguments");312ret = AUTH_BADCRED;313goto error;314}315316/*317* Process the call arg version number.318*319* Set the krb5_gss backwards-compatibility mode based on client320* version. This controls whether the AP_REP message is321* encrypted with the session key (version 2+, correct) or the322* session subkey (version 1, incorrect). This function can323* never fail, so we don't bother checking its return value.324*/325switch (call_arg.version) {326case 1:327case 2:328LOG_MISCERR("Warning: Accepted old RPC protocol request");329call_res.version = 1;330break;331case 3:332case 4:333/* 3 and 4 are essentially the same, don't bother warning */334call_res.version = call_arg.version;335break;336default:337PRINTF(("svcauth_gssapi: bad GSSAPI_INIT version\n"));338LOG_MISCERR("unsupported GSSAPI_INIT version");339ret = AUTH_BADCRED;340goto error;341}342343#ifdef GSS_BACKWARD_HACK344krb5_gss_set_backward_mode(&minor_stat, call_arg.version == 1);345#endif346347if (call_arg.version >= 3) {348memset(&bindings, 0, sizeof(bindings));349bindings.application_data.length = 0;350bindings.initiator_addrtype = GSS_C_AF_INET;351bindings.initiator_address.length = 4;352bindings.initiator_address.value =353&svc_getcaller(rqst->rq_xprt)->sin_addr.s_addr;354355if (rqst->rq_xprt->xp_laddrlen > 0) {356bindings.acceptor_addrtype = GSS_C_AF_INET;357bindings.acceptor_address.length = 4;358bindings.acceptor_address.value =359&rqst->rq_xprt->xp_laddr.sin_addr.s_addr;360} else {361LOG_MISCERR("cannot get local address");362ret = AUTH_FAILED;363goto error;364}365366367bindp = &bindings;368} else {369bindp = GSS_C_NO_CHANNEL_BINDINGS;370}371372/*373* If the client's server_creds is already set, use it.374* Otherwise, try each credential in server_creds_list until375* one of them succeeds, then set the client server_creds376* to that. If all fail, the client's server_creds isn't377* set (which is fine, because the client will be gc'ed378* anyway).379*380* If accept_sec_context returns something other than381* success and GSS_S_FAILURE, then assume different382* credentials won't help and stop looping.383*384* Note that there are really two cases here: (1) the client385* has a server_creds already, and (2) it does not. They386* are both written in the same loop so that there is only387* one textual call to gss_accept_sec_context; in fact, in388* case (1), the loop is executed exactly once.389*/390for (i = 0; i < server_creds_count; i++) {391if (client_data->server_creds != NULL) {392PRINTF(("svcauth_gssapi: using's clients server_creds\n"));393server_creds = client_data->server_creds;394} else {395PRINTF(("svcauth_gssapi: trying creds %d\n", i));396server_creds = server_creds_list[i];397}398399/* Free previous output_token from loop */400if(i != 0) gss_release_buffer(&minor_stat, &output_token);401402call_res.gss_major =403gss_accept_sec_context(&call_res.gss_minor,404&client_data->context,405server_creds,406&call_arg.token,407bindp,408&client_data->client_name,409NULL,410&output_token,411&ret_flags,412&time_rec,413NULL);414415if (server_creds == client_data->server_creds)416break;417418PRINTF(("accept_sec_context returned 0x%x 0x%x not-us=%#x\n",419call_res.gss_major, call_res.gss_minor,420(int) KRB5KRB_AP_ERR_NOT_US));421if (call_res.gss_major == GSS_S_COMPLETE ||422call_res.gss_major == GSS_S_CONTINUE_NEEDED) {423/* server_creds was right, set it! */424PRINTF(("svcauth_gssapi: creds are correct, storing\n"));425client_data->server_creds = server_creds;426client_data->server_name = server_name_list[i];427break;428} else if (call_res.gss_major != GSS_S_FAILURE429#ifdef GSSAPI_KRB5430/*431* hard-coded because there is no other way432* to prevent all GSS_S_FAILURES from433* returning a "wrong principal in request"434* error435*/436|| ((krb5_error_code) call_res.gss_minor !=437(krb5_error_code) KRB5KRB_AP_ERR_NOT_US)438#endif439) {440break;441}442}443444gssstat = call_res.gss_major;445minor_stat = call_res.gss_minor;446447/* done with call args */448xdr_free((xdrproc_t)xdr_authgssapi_init_arg, &call_arg);449450PRINTF(("svcauth_gssapi: accept_sec_context returned %#x %#x\n",451call_res.gss_major, call_res.gss_minor));452if (call_res.gss_major != GSS_S_COMPLETE &&453call_res.gss_major != GSS_S_CONTINUE_NEEDED) {454AUTH_GSSAPI_DISPLAY_STATUS(("accepting context",455call_res.gss_major,456call_res.gss_minor));457458badauth(call_res.gss_major, call_res.gss_minor, rqst->rq_xprt);459460gss_release_buffer(&minor_stat, &output_token);461svc_sendreply(rqst->rq_xprt, (xdrproc_t)xdr_authgssapi_init_res,462(caddr_t) &call_res);463*no_dispatch = TRUE;464ret = AUTH_OK;465goto error;466}467468if (output_token.length != 0) {469PRINTF(("svcauth_gssapi: got new output token\n"));470GSS_COPY_BUFFER(call_res.token, output_token);471}472473if (gssstat == GSS_S_COMPLETE) {474client_data->seq_num = rand();475client_expire(client_data,476(time_rec == GSS_C_INDEFINITE ?477INDEF_EXPIRE : time_rec) + time(0));478479PRINTF(("svcauth_gssapi: context established, isn %d\n",480client_data->seq_num));481482if (auth_gssapi_seal_seq(client_data->context,483client_data->seq_num,484&call_res.signed_isn) ==485FALSE) {486ret = AUTH_FAILED;487LOG_MISCERR("internal error sealing sequence number");488gss_release_buffer(&minor_stat, &output_token);489goto error;490}491}492493PRINTF(("svcauth_gssapi: sending reply\n"));494svc_sendreply(rqst->rq_xprt, (xdrproc_t)xdr_authgssapi_init_res,495(caddr_t) &call_res);496*no_dispatch = TRUE;497498/*499* If appropriate, set established to TRUE *after* sending500* response (otherwise, the client will receive the final501* token encrypted)502*/503if (gssstat == GSS_S_COMPLETE) {504gss_release_buffer(&minor_stat, &call_res.signed_isn);505client_data->established = TRUE;506}507gss_release_buffer(&minor_stat, &output_token);508} else {509PRINTF(("svcauth_gssapi: context is established\n"));510511/* check the verifier */512PRINTF(("svcauth_gssapi: checking verifier, len %d\n",513verf->oa_length));514515in_buf.length = verf->oa_length;516in_buf.value = verf->oa_base;517518if (auth_gssapi_unseal_seq(client_data->context, &in_buf,519&seq_num) == FALSE) {520ret = AUTH_BADVERF;521LOG_MISCERR("internal error unsealing sequence number");522goto error;523}524525if (seq_num != client_data->seq_num + 1) {526PRINTF(("svcauth_gssapi: expected isn %d, got %d\n",527client_data->seq_num + 1, seq_num));528if (log_badverf != NULL)529(*log_badverf)(client_data->client_name,530client_data->server_name,531rqst, msg, log_badverf_data);532533ret = AUTH_REJECTEDVERF;534goto error;535}536client_data->seq_num++;537538PRINTF(("svcauth_gssapi: seq_num %d okay\n", seq_num));539540/* free previous response verifier, if any */541if (client_data->prev_verf.length != 0) {542gss_release_buffer(&minor_stat, &client_data->prev_verf);543client_data->prev_verf.length = 0;544}545546/* prepare response verifier */547seq_num = client_data->seq_num + 1;548if (auth_gssapi_seal_seq(client_data->context, seq_num,549&out_buf) == FALSE) {550ret = AUTH_FAILED;551LOG_MISCERR("internal error sealing sequence number");552goto error;553}554555client_data->seq_num++;556557PRINTF(("svcauth_gssapi; response seq_num %d\n", seq_num));558559rqst->rq_xprt->xp_verf.oa_flavor = AUTH_GSSAPI;560rqst->rq_xprt->xp_verf.oa_base = out_buf.value;561rqst->rq_xprt->xp_verf.oa_length = out_buf.length;562563/* save verifier so it can be freed next time */564client_data->prev_verf.value = out_buf.value;565client_data->prev_verf.length = out_buf.length;566567/*568* Message is authentic. If auth_msg if true, process the569* call; otherwise, return AUTH_OK so it will be dispatched570* to the application server.571*/572573if (creds.auth_msg == TRUE) {574/*575* If process_token fails, then the token probably came576* from an attacker. No response (error or otherwise)577* should be returned to the client, since it won't be578* accepting one.579*/580581switch (rqst->rq_proc) {582case AUTH_GSSAPI_MSG:583PRINTF(("svcauth_gssapi: GSSAPI_MSG, getting args\n"));584memset(&call_arg, 0, sizeof(call_arg));585if (! svc_getargs(rqst->rq_xprt,586(xdrproc_t)xdr_authgssapi_init_arg,587&call_arg)) {588PRINTF(("svcauth_gssapi: cannot decode args\n"));589LOG_MISCERR("protocol error in call arguments");590xdr_free((xdrproc_t)xdr_authgssapi_init_arg,591&call_arg);592ret = AUTH_BADCRED;593goto error;594}595596PRINTF(("svcauth_gssapi: processing token\n"));597gssstat = gss_process_context_token(&minor_stat,598client_data->context,599&call_arg.token);600601/* done with call args */602xdr_free((xdrproc_t)xdr_authgssapi_init_arg, &call_arg);603604if (gssstat != GSS_S_COMPLETE) {605AUTH_GSSAPI_DISPLAY_STATUS(("processing token",606gssstat, minor_stat));607ret = AUTH_FAILED;608goto error;609}610611svc_sendreply(rqst->rq_xprt, xdr_void, NULL);612*no_dispatch = TRUE;613break;614615case AUTH_GSSAPI_DESTROY:616PRINTF(("svcauth_gssapi: GSSAPI_DESTROY\n"));617618PRINTF(("svcauth_gssapi: sending reply\n"));619svc_sendreply(rqst->rq_xprt, xdr_void, NULL);620*no_dispatch = TRUE;621622destroy_client(client_data);623rqst->rq_xprt->xp_auth = NULL;624break;625626default:627PRINTF(("svcauth_gssapi: unacceptable procedure %d\n",628rqst->rq_proc));629LOG_MISCERR("invalid call procedure number");630ret = AUTH_FAILED;631goto error;632}633} else {634/* set credentials for app server; comment in svc.c */635/* seems to imply this is incorrect, but I don't see */636/* any problem with it... */637rqst->rq_clntcred = (char *)client_data->client_name;638rqst->rq_svccred = (char *)client_data->context;639}640}641642if (creds.client_handle.length != 0) {643PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",644(int) creds.client_handle.length));645xdr_free((xdrproc_t)xdr_authgssapi_creds, &creds);646}647648PRINTF(("\n"));649return AUTH_OK;650651error:652if (creds.client_handle.length != 0) {653PRINTF(("svcauth_gssapi: freeing client_handle len %d\n",654(int) creds.client_handle.length));655xdr_free((xdrproc_t)xdr_authgssapi_creds, &creds);656}657658PRINTF(("\n"));659return ret;660}661662static void cleanup(void)663{664client_list *c, *c2;665666PRINTF(("cleanup_and_exit: starting\n"));667668c = clients;669while (c) {670c2 = c;671c = c->next;672destroy_client(c2->client);673free(c2);674}675676exit(0);677}678679/*680* Function: create_client681*682* Purpose: Creates an new client_data structure and stores it in the683* database.684*685* Returns: the new client_data structure, or NULL on failure.686*687* Effects:688*689* A new client_data is created and stored in the hash table and690* b-tree. A new key that is unique in the current database is691* chosen; this key should be used as the client's client_handle.692*/693static svc_auth_gssapi_data *create_client(void)694{695client_list *c;696svc_auth_gssapi_data *client_data;697static int client_key = 1;698699PRINTF(("svcauth_gssapi: empty creds, creating\n"));700701client_data = (svc_auth_gssapi_data *) malloc(sizeof(*client_data));702if (client_data == NULL)703return NULL;704memset(client_data, 0, sizeof(*client_data));705L_PRINTF(2, ("create_client: new client_data = %p\n",706(void *) client_data));707708/* set up client data structure */709client_data->established = 0;710client_data->context = GSS_C_NO_CONTEXT;711client_data->expiration = time(0) + INITIATION_TIMEOUT;712713/* set up psycho-recursive SVCAUTH hack */714client_data->svcauth.svc_ah_ops = &svc_auth_gssapi_ops;715client_data->svcauth.svc_ah_private = (caddr_t) client_data;716717client_data->key = client_key++;718719c = (client_list *) malloc(sizeof(client_list));720if (c == NULL)721return NULL;722c->client = client_data;723c->next = NULL;724725726if (clients == NULL)727clients = c;728else {729c->next = clients;730clients = c;731}732733PRINTF(("svcauth_gssapi: new handle %d\n", client_data->key));734L_PRINTF(2, ("create_client: done\n"));735736return client_data;737}738739/*740* Function: client_expire741*742* Purpose: change the expiration time of a client in the database743*744* Arguments:745*746* client_data (r) the client_data to expire747* exp (r) the new expiration time748*749* Effects:750*751* client_data->expiration = exp752*753* This function used to remove client_data from the database, change754* its expiration time, and re-add it, which was necessary because the755* database was sorted by expiration time so a simple modification756* would break the rep invariant. Now the database is an unsorted757* linked list, so it doesn't matter.758*/759static void client_expire(760svc_auth_gssapi_data *client_data,761uint32_t exp)762{763client_data->expiration = exp;764}765766/*767* Function get_client768*769* Purpose: retrieve a client_data structure from the database based770* on its client handle (key)771*772* Arguments:773*774* client_handle (r) the handle (key) to retrieve775*776* Effects:777*778* Searches the list and returns the client_data whose key field779* matches the contents of client_handle, or returns NULL if none was780* found.781*/782static svc_auth_gssapi_data *get_client(gss_buffer_t client_handle)783{784client_list *c;785uint32_t handle;786787memcpy(&handle, client_handle->value, 4);788789L_PRINTF(2, ("get_client: looking for client %d\n", handle));790791c = clients;792while (c) {793if (c->client->key == handle)794return c->client;795c = c->next;796}797798L_PRINTF(2, ("get_client: client_handle lookup failed\n"));799return NULL;800}801802/*803* Function: destroy_client804*805* Purpose: destroys a client entry and removes it from the database806*807* Arguments:808*809* client_data (r) the client to be destroyed810*811* Effects:812*813* client_data->context is deleted with gss_delete_sec_context.814* client_data's entry in the database is destroyed. client_data is815* freed.816*/817static void destroy_client(svc_auth_gssapi_data *client_data)818{819OM_uint32 gssstat, minor_stat;820gss_buffer_desc out_buf;821client_list *c, *c2;822823PRINTF(("destroy_client: destroying client_data\n"));824L_PRINTF(2, ("destroy_client: client_data = %p\n", (void *) client_data));825826#ifdef DEBUG_GSSAPI827if (svc_debug_gssapi >= 3)828dump_db("before frees");829#endif830831/* destroy client struct even if error occurs */832833gssstat = gss_delete_sec_context(&minor_stat, &client_data->context,834&out_buf);835if (gssstat != GSS_S_COMPLETE)836AUTH_GSSAPI_DISPLAY_STATUS(("deleting context", gssstat,837minor_stat));838839gss_release_buffer(&minor_stat, &out_buf);840gss_release_name(&minor_stat, &client_data->client_name);841if (client_data->prev_verf.length != 0)842gss_release_buffer(&minor_stat, &client_data->prev_verf);843844if (clients == NULL) {845PRINTF(("destroy_client: called on empty database\n"));846abort();847} else if (clients->client == client_data) {848c = clients;849clients = clients->next;850free(c);851} else {852c2 = clients;853c = clients->next;854while (c) {855if (c->client == client_data) {856c2->next = c->next;857free(c);858goto done;859} else {860c2 = c;861c = c->next;862}863}864PRINTF(("destroy_client: client_handle delete failed\n"));865abort();866}867868done:869870L_PRINTF(2, ("destroy_client: client %d destroyed\n", client_data->key));871872free(client_data);873}874875static void dump_db(char *msg)876{877svc_auth_gssapi_data *client_data;878client_list *c;879880L_PRINTF(3, ("dump_db: %s:\n", msg));881882c = clients;883while (c) {884client_data = c->client;885L_PRINTF(3, ("\tclient_data = %p, exp = %d\n",886(void *) client_data, client_data->expiration));887c = c->next;888}889890L_PRINTF(3, ("\n"));891}892893static void clean_client(void)894{895svc_auth_gssapi_data *client_data;896client_list *c;897898PRINTF(("clean_client: starting\n"));899900c = clients;901while (c) {902client_data = c->client;903904L_PRINTF(2, ("clean_client: client_data = %p\n",905(void *) client_data));906907if (client_data->expiration < time(0)) {908PRINTF(("clean_client: client %d expired\n",909client_data->key));910destroy_client(client_data);911c = clients; /* start over, just to be safe */912} else {913c = c->next;914}915}916917PRINTF(("clean_client: done\n"));918}919920/*921* Function: svcauth_gssapi_set_names922*923* Purpose: Sets the list of service names for which incoming924* authentication requests should be honored.925*926* See functional specifications.927*/928bool_t svcauth_gssapi_set_names(929auth_gssapi_name *names,930int num)931{932OM_uint32 gssstat, minor_stat;933gss_buffer_desc in_buf;934int i;935936if (num == 0)937for (; names[num].name != NULL; num++)938;939940server_creds_list = NULL;941server_name_list = NULL;942943server_creds_list = (gss_cred_id_t *) malloc(num*sizeof(gss_cred_id_t));944if (server_creds_list == NULL)945goto fail;946server_name_list = (gss_name_t *) malloc(num*sizeof(gss_name_t));947if (server_name_list == NULL)948goto fail;949950for (i = 0; i < num; i++) {951server_name_list[i] = 0;952server_creds_list[i] = 0;953}954955server_creds_count = num;956957for (i = 0; i < num; i++) {958in_buf.value = names[i].name;959in_buf.length = strlen(in_buf.value) + 1;960961PRINTF(("svcauth_gssapi_set_names: importing %s\n", names[i].name));962963gssstat = gss_import_name(&minor_stat, &in_buf, names[i].type,964&server_name_list[i]);965966if (gssstat != GSS_S_COMPLETE) {967AUTH_GSSAPI_DISPLAY_STATUS(("importing name", gssstat,968minor_stat));969goto fail;970}971972gssstat = gss_acquire_cred(&minor_stat, server_name_list[i], 0,973GSS_C_NULL_OID_SET, GSS_C_ACCEPT,974&server_creds_list[i], NULL, NULL);975if (gssstat != GSS_S_COMPLETE) {976AUTH_GSSAPI_DISPLAY_STATUS(("acquiring credentials",977gssstat, minor_stat));978goto fail;979}980}981982return TRUE;983984fail:985svcauth_gssapi_unset_names();986987return FALSE;988}989990/* Function: svcauth_gssapi_unset_names991*992* Purpose: releases the names and credentials allocated by993* svcauth_gssapi_set_names994*/995996void svcauth_gssapi_unset_names(void)997{998int i;999OM_uint32 minor_stat;10001001if (server_creds_list) {1002for (i = 0; i < server_creds_count; i++)1003if (server_creds_list[i])1004gss_release_cred(&minor_stat, &server_creds_list[i]);1005free(server_creds_list);1006server_creds_list = NULL;1007}10081009if (server_name_list) {1010for (i = 0; i < server_creds_count; i++)1011if (server_name_list[i])1012gss_release_name(&minor_stat, &server_name_list[i]);1013free(server_name_list);1014server_name_list = NULL;1015}1016server_creds_count = 0;1017}101810191020/*1021* Function: svcauth_gssapi_set_log_badauth_func1022*1023* Purpose: sets the logging function called when an invalid RPC call1024* arrives1025*1026* See functional specifications.1027*/1028void svcauth_gssapi_set_log_badauth_func(1029auth_gssapi_log_badauth_func func,1030caddr_t data)1031{1032log_badauth = func;1033log_badauth_data = data;1034}10351036void1037svcauth_gssapi_set_log_badauth2_func(auth_gssapi_log_badauth2_func func,1038caddr_t data)1039{1040log_badauth2 = func;1041log_badauth2_data = data;1042}10431044/*1045* Function: svcauth_gssapi_set_log_badverf_func1046*1047* Purpose: sets the logging function called when an invalid RPC call1048* arrives1049*1050* See functional specifications.1051*/1052void svcauth_gssapi_set_log_badverf_func(1053auth_gssapi_log_badverf_func func,1054caddr_t data)1055{1056log_badverf = func;1057log_badverf_data = data;1058}10591060/*1061* Function: svcauth_gssapi_set_log_miscerr_func1062*1063* Purpose: sets the logging function called when a miscellaneous1064* AUTH_GSSAPI error occurs1065*1066* See functional specifications.1067*/1068void svcauth_gssapi_set_log_miscerr_func(1069auth_gssapi_log_miscerr_func func,1070caddr_t data)1071{1072log_miscerr = func;1073log_miscerr_data = data;1074}10751076/*1077* Encrypt the serialized arguments from xdr_func applied to xdr_ptr1078* and write the result to xdrs.1079*/1080static bool_t svc_auth_gssapi_wrap(1081SVCAUTH *auth,1082XDR *out_xdrs,1083xdrproc_t xdr_func,1084caddr_t xdr_ptr)1085{1086OM_uint32 gssstat, minor_stat;10871088if (! SVCAUTH_PRIVATE(auth)->established) {1089PRINTF(("svc_gssapi_wrap: not established, noop\n"));1090return (*xdr_func)(out_xdrs, xdr_ptr);1091} else if (! auth_gssapi_wrap_data(&gssstat, &minor_stat,1092SVCAUTH_PRIVATE(auth)->context,1093SVCAUTH_PRIVATE(auth)->seq_num,1094out_xdrs, xdr_func, xdr_ptr)) {1095if (gssstat != GSS_S_COMPLETE)1096AUTH_GSSAPI_DISPLAY_STATUS(("encrypting function arguments",1097gssstat, minor_stat));1098return FALSE;1099} else1100return TRUE;1101}11021103static bool_t svc_auth_gssapi_unwrap(1104SVCAUTH *auth,1105XDR *in_xdrs,1106xdrproc_t xdr_func,1107caddr_t xdr_ptr)1108{1109svc_auth_gssapi_data *client_data = SVCAUTH_PRIVATE(auth);1110OM_uint32 gssstat, minor_stat;11111112if (! client_data->established) {1113PRINTF(("svc_gssapi_unwrap: not established, noop\n"));1114return (*xdr_func)(in_xdrs, (auth_gssapi_init_arg *)(void *) xdr_ptr);1115} else if (! auth_gssapi_unwrap_data(&gssstat, &minor_stat,1116client_data->context,1117client_data->seq_num-1,1118in_xdrs, xdr_func, xdr_ptr)) {1119if (gssstat != GSS_S_COMPLETE)1120AUTH_GSSAPI_DISPLAY_STATUS(("decrypting function arguments",1121gssstat, minor_stat));1122return FALSE;1123} else1124return TRUE;1125}11261127static bool_t svc_auth_gssapi_destroy(SVCAUTH *auth)1128{1129svc_auth_gssapi_data *client_data = SVCAUTH_PRIVATE(auth);11301131destroy_client(client_data);1132return TRUE;1133}113411351136