X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=support%2Frpc%2Fsvc_auth_gss.c;fp=support%2Frpc%2Fsvc_auth_gss.c;h=0000000000000000000000000000000000000000;hb=a1b7c0da9e73a607f4bc70ffe3b44b00f5d39938;hp=82b8d01af48ed5556b3140bcb24a5e931ff37f2e;hpb=1d0397894463e507e9f5d92442ac3b09e29310a3;p=nfs-utils.git diff --git a/support/rpc/svc_auth_gss.c b/support/rpc/svc_auth_gss.c deleted file mode 100644 index 82b8d01..0000000 --- a/support/rpc/svc_auth_gss.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - svc_auth_gss.c - - Copyright (c) 2000 The Regents of the University of Michigan. - All rights reserved. - - Copyright (c) 2000 Dug Song . - All rights reserved, all wrongs reversed. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - 3. Neither the name of the University nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - */ - -#include -#include -#include -#include -#include - -extern SVCAUTH svc_auth_none; - -/* - * from mit-krb5-1.2.1 mechglue/mglueP.h: - * Array of context IDs typed by mechanism OID - */ -typedef struct gss_union_ctx_id_t { - gss_OID mech_type; - gss_ctx_id_t internal_ctx_id; -} gss_union_ctx_id_desc, *gss_union_ctx_id_t; - - - -static bool_t svcauth_gss_destroy(); -static bool_t svcauth_gss_wrap(); -static bool_t svcauth_gss_unwrap(); - -struct svc_auth_ops svc_auth_gss_ops = { - svcauth_gss_wrap, - svcauth_gss_unwrap, - svcauth_gss_destroy -}; - -struct svc_rpc_gss_data { - bool_t established; /* context established */ - gss_ctx_id_t ctx; /* context id */ - struct rpc_gss_sec sec; /* security triple */ - gss_buffer_desc cname; /* GSS client name */ - u_int seq; /* sequence number */ - u_int win; /* sequence window */ - u_int seqlast; /* last sequence number */ - u_int32_t seqmask; /* bitmask of seqnums */ - gss_name_t client_name; /* unparsed name string */ -}; - -#define SVCAUTH_PRIVATE(auth) \ - ((struct svc_rpc_gss_data *)(auth)->svc_ah_private) - -/* Global server credentials. */ -gss_cred_id_t _svcauth_gss_creds; -static gss_name_t _svcauth_gss_name = NULL; - -bool_t -svcauth_gss_set_svc_name(gss_name_t name) -{ - OM_uint32 maj_stat, min_stat; - - log_debug("in svcauth_gss_set_svc_name()"); - - if (_svcauth_gss_name != NULL) { - maj_stat = gss_release_name(&min_stat, &_svcauth_gss_name); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_release_name", maj_stat, min_stat); - return (FALSE); - } - _svcauth_gss_name = NULL; - } - maj_stat = gss_duplicate_name(&min_stat, name, &_svcauth_gss_name); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_duplicate_name", maj_stat, min_stat); - return (FALSE); - } - - return (TRUE); -} - -static bool_t -svcauth_gss_import_name(char *service) -{ - gss_name_t name; - gss_buffer_desc namebuf; - OM_uint32 maj_stat, min_stat; - - log_debug("in svcauth_gss_import_name()"); - - namebuf.value = service; - namebuf.length = strlen(service); - - maj_stat = gss_import_name(&min_stat, &namebuf, - GSS_C_NT_HOSTBASED_SERVICE, &name); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_import_name", maj_stat, min_stat); - return (FALSE); - } - if (svcauth_gss_set_svc_name(name) != TRUE) { - gss_release_name(&min_stat, &name); - return (FALSE); - } - return (TRUE); -} - -static bool_t -svcauth_gss_acquire_cred(void) -{ - OM_uint32 maj_stat, min_stat; - - log_debug("in svcauth_gss_acquire_cred()"); - - maj_stat = gss_acquire_cred(&min_stat, _svcauth_gss_name, 0, - GSS_C_NULL_OID_SET, GSS_C_ACCEPT, - &_svcauth_gss_creds, NULL, NULL); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_acquire_cred", maj_stat, min_stat); - return (FALSE); - } - return (TRUE); -} - -static bool_t -svcauth_gss_release_cred(void) -{ - OM_uint32 maj_stat, min_stat; - - log_debug("in svcauth_gss_release_cred()"); - - maj_stat = gss_release_cred(&min_stat, &_svcauth_gss_creds); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_release_cred", maj_stat, min_stat); - return (FALSE); - } - - _svcauth_gss_creds = NULL; - - return (TRUE); -} - -static bool_t -svcauth_gss_accept_sec_context(struct svc_req *rqst, - struct rpc_gss_init_res *gr) -{ - struct svc_rpc_gss_data *gd; - struct rpc_gss_cred *gc; - gss_buffer_desc recv_tok, seqbuf, checksum; - gss_OID mech; - OM_uint32 maj_stat = 0, min_stat = 0, ret_flags, seq; - - log_debug("in svcauth_gss_accept_context()"); - - gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); - gc = (struct rpc_gss_cred *)rqst->rq_clntcred; - memset(gr, 0, sizeof(*gr)); - - /* Deserialize arguments. */ - memset(&recv_tok, 0, sizeof(recv_tok)); - - if (!svc_getargs(rqst->rq_xprt, xdr_rpc_gss_init_args, - (caddr_t)&recv_tok)) - return (FALSE); - - gr->gr_major = gss_accept_sec_context(&gr->gr_minor, - &gd->ctx, - _svcauth_gss_creds, - &recv_tok, - GSS_C_NO_CHANNEL_BINDINGS, - &gd->client_name, - &mech, - &gr->gr_token, - &ret_flags, - NULL, - NULL); - - if (gr->gr_major != GSS_S_COMPLETE && - gr->gr_major != GSS_S_CONTINUE_NEEDED) { - log_status("accept_sec_context", gr->gr_major, gr->gr_minor); - gd->ctx = GSS_C_NO_CONTEXT; - gss_release_buffer(&min_stat, &gr->gr_token); - return (FALSE); - } - /* ANDROS: krb5 mechglue returns ctx of size 8 - two pointers, - * one to the mechanism oid, one to the internal_ctx_id */ - if ((gr->gr_ctx.value = mem_alloc(sizeof(gss_union_ctx_id_desc))) == NULL) { - fprintf(stderr, "svcauth_gss_accept_context: out of memory\n"); - return (FALSE); - } - memcpy(gr->gr_ctx.value, gd->ctx, sizeof(gss_union_ctx_id_desc)); - gr->gr_ctx.length = sizeof(gss_union_ctx_id_desc); - - /* ANDROS: change for debugging linux kernel version... - gr->gr_win = sizeof(gd->seqmask) * 8; - */ - gr->gr_win = 0x00000005; - - /* Save client info. */ - gd->sec.mech = mech; - gd->sec.qop = GSS_C_QOP_DEFAULT; - gd->sec.svc = gc->gc_svc; - gd->seq = gc->gc_seq; - gd->win = gr->gr_win; - - if (gr->gr_major == GSS_S_COMPLETE) { - maj_stat = gss_display_name(&min_stat, gd->client_name, - &gd->cname, &gd->sec.mech); - if (maj_stat != GSS_S_COMPLETE) { - log_status("display_name", maj_stat, min_stat); - return (FALSE); - } -#ifdef DEBUG -#ifdef HAVE_KRB5 - { - gss_buffer_desc mechname; - - gss_oid_to_str(&min_stat, mech, &mechname); - - log_debug("accepted context for %.*s with " - "", - gd->cname.length, (char *)gd->cname.value, - mechname.length, (char *)mechname.value, - gd->sec.qop, gd->sec.svc); - - gss_release_buffer(&min_stat, &mechname); - } -#elif HAVE_HEIMDAL - log_debug("accepted context for %.*s with " - "", - gd->cname.length, (char *)gd->cname.value, - gd->sec.qop, gd->sec.svc); -#endif -#endif /* DEBUG */ - seq = htonl(gr->gr_win); - seqbuf.value = &seq; - seqbuf.length = sizeof(seq); - - maj_stat = gss_sign(&min_stat, gd->ctx, GSS_C_QOP_DEFAULT, - &seqbuf, &checksum); - - if (maj_stat != GSS_S_COMPLETE) - return (FALSE); - - rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; - rqst->rq_xprt->xp_verf.oa_base = checksum.value; - rqst->rq_xprt->xp_verf.oa_length = checksum.length; - } - return (TRUE); -} - -static bool_t -svcauth_gss_validate(struct svc_rpc_gss_data *gd, struct rpc_msg *msg) -{ - struct opaque_auth *oa; - gss_buffer_desc rpcbuf, checksum; - OM_uint32 maj_stat, min_stat, qop_state; - u_char rpchdr[128]; - int32_t *buf; - - log_debug("in svcauth_gss_validate()"); - - memset(rpchdr, 0, sizeof(rpchdr)); - - /* XXX - Reconstruct RPC header for signing (from xdr_callmsg). */ - buf = (int32_t *)rpchdr; - IXDR_PUT_LONG(buf, msg->rm_xid); - IXDR_PUT_ENUM(buf, msg->rm_direction); - IXDR_PUT_LONG(buf, msg->rm_call.cb_rpcvers); - IXDR_PUT_LONG(buf, msg->rm_call.cb_prog); - IXDR_PUT_LONG(buf, msg->rm_call.cb_vers); - IXDR_PUT_LONG(buf, msg->rm_call.cb_proc); - oa = &msg->rm_call.cb_cred; - IXDR_PUT_ENUM(buf, oa->oa_flavor); - IXDR_PUT_LONG(buf, oa->oa_length); - if (oa->oa_length) { - memcpy((caddr_t)buf, oa->oa_base, oa->oa_length); - buf += RNDUP(oa->oa_length) / sizeof(int32_t); - } - rpcbuf.value = rpchdr; - rpcbuf.length = (u_char *)buf - rpchdr; - - checksum.value = msg->rm_call.cb_verf.oa_base; - checksum.length = msg->rm_call.cb_verf.oa_length; - - maj_stat = gss_verify_mic(&min_stat, gd->ctx, &rpcbuf, &checksum, - &qop_state); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_verify_mic", maj_stat, min_stat); - return (FALSE); - } - return (TRUE); -} - -bool_t -svcauth_gss_nextverf(struct svc_req *rqst, u_int num) -{ - struct svc_rpc_gss_data *gd; - gss_buffer_desc signbuf, checksum; - OM_uint32 maj_stat, min_stat; - - log_debug("in svcauth_gss_nextverf()"); - - if (rqst->rq_xprt->xp_auth == NULL) - return (FALSE); - - gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); - - signbuf.value = # - signbuf.length = sizeof(num); - - maj_stat = gss_get_mic(&min_stat, gd->ctx, gd->sec.qop, - &signbuf, &checksum); - - if (maj_stat != GSS_S_COMPLETE) { - log_status("gss_get_mic", maj_stat, min_stat); - return (FALSE); - } - rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; - rqst->rq_xprt->xp_verf.oa_base = (caddr_t)checksum.value; - rqst->rq_xprt->xp_verf.oa_length = (u_int)checksum.length; - - return (TRUE); -} - -enum auth_stat -_svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) -{ - XDR xdrs; - SVCAUTH *auth; - struct svc_rpc_gss_data *gd; - struct rpc_gss_cred *gc; - struct rpc_gss_init_res gr; - int call_stat, offset; - - log_debug("in svcauth_gss()"); - - /* Initialize reply. */ - rqst->rq_xprt->xp_verf = _null_auth; - - /* Allocate and set up server auth handle. */ - if (rqst->rq_xprt->xp_auth == NULL || - rqst->rq_xprt->xp_auth == &svc_auth_none) { - if ((auth = calloc(sizeof(*auth), 1)) == NULL) { - fprintf(stderr, "svcauth_gss: out_of_memory\n"); - return (AUTH_FAILED); - } - if ((gd = calloc(sizeof(*gd), 1)) == NULL) { - fprintf(stderr, "svcauth_gss: out_of_memory\n"); - return (AUTH_FAILED); - } - auth->svc_ah_ops = &svc_auth_gss_ops; - auth->svc_ah_private = (caddr_t)gd; - rqst->rq_xprt->xp_auth = auth; - } - else gd = SVCAUTH_PRIVATE(rqst->rq_xprt->xp_auth); - - /* Deserialize client credentials. */ - if (rqst->rq_cred.oa_length <= 0) - return (AUTH_BADCRED); - - gc = (struct rpc_gss_cred *)rqst->rq_clntcred; - memset(gc, 0, sizeof(*gc)); - - xdrmem_create(&xdrs, rqst->rq_cred.oa_base, - rqst->rq_cred.oa_length, XDR_DECODE); - - if (!xdr_rpc_gss_cred(&xdrs, gc)) { - XDR_DESTROY(&xdrs); - return (AUTH_BADCRED); - } - XDR_DESTROY(&xdrs); - - /* Check version. */ - if (gc->gc_v != RPCSEC_GSS_VERSION) - return (AUTH_BADCRED); - - /* Check RPCSEC_GSS service. */ - if (gc->gc_svc != RPCSEC_GSS_SVC_NONE && - gc->gc_svc != RPCSEC_GSS_SVC_INTEGRITY && - gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY) - return (AUTH_BADCRED); - - /* Check sequence number. */ - if (gd->established) { - if (gc->gc_seq > MAXSEQ) - return (RPCSEC_GSS_CTXPROBLEM); - - if ((offset = gd->seqlast - gc->gc_seq) < 0) { - gd->seqlast = gc->gc_seq; - offset = 0 - offset; - gd->seqmask <<= offset; - offset = 0; - } - else if (offset >= gd->win || (gd->seqmask & (1 << offset))) { - *no_dispatch = 1; - return (RPCSEC_GSS_CTXPROBLEM); - } - gd->seq = gc->gc_seq; - gd->seqmask |= (1 << offset); - } - - if (gd->established) { - rqst->rq_clntname = (char *)gd->client_name; - rqst->rq_svcname = (char *)gd->ctx; - } - - /* Handle RPCSEC_GSS control procedure. */ - switch (gc->gc_proc) { - - case RPCSEC_GSS_INIT: - case RPCSEC_GSS_CONTINUE_INIT: - if (rqst->rq_proc != NULLPROC) - return (AUTH_FAILED); /* XXX ? */ - - if (_svcauth_gss_name == NULL) { - if (!svcauth_gss_import_name("nfs")) - return (AUTH_FAILED); - } - - if (!svcauth_gss_acquire_cred()) - return (AUTH_FAILED); - - if (!svcauth_gss_accept_sec_context(rqst, &gr)) - return (AUTH_REJECTEDCRED); - - if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) - return (AUTH_FAILED); - - *no_dispatch = TRUE; - - call_stat = svc_sendreply(rqst->rq_xprt, xdr_rpc_gss_init_res, - (caddr_t)&gr); - - if (!call_stat) - return (AUTH_FAILED); - - if (gr.gr_major == GSS_S_COMPLETE) - gd->established = TRUE; - - break; - - case RPCSEC_GSS_DATA: - if (!svcauth_gss_validate(gd, msg)) - return (RPCSEC_GSS_CREDPROBLEM); - - if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) - return (AUTH_FAILED); - break; - - case RPCSEC_GSS_DESTROY: - if (rqst->rq_proc != NULLPROC) - return (AUTH_FAILED); /* XXX ? */ - - if (!svcauth_gss_validate(gd, msg)) - return (RPCSEC_GSS_CREDPROBLEM); - - if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) - return (AUTH_FAILED); - - if (!svcauth_gss_release_cred()) - return (AUTH_FAILED); - - SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth); - rqst->rq_xprt->xp_auth = &svc_auth_none; - - break; - - default: - return (AUTH_REJECTEDCRED); - break; - } - return (AUTH_OK); -} - -bool_t -svcauth_gss_destroy(SVCAUTH *auth) -{ - struct svc_rpc_gss_data *gd; - OM_uint32 min_stat; - - log_debug("in svcauth_gss_destroy()"); - - gd = SVCAUTH_PRIVATE(auth); - - gss_delete_sec_context(&min_stat, &gd->ctx, GSS_C_NO_BUFFER); - gss_release_buffer(&min_stat, &gd->cname); - - if (gd->client_name) - gss_release_name(&min_stat, &gd->client_name); - - mem_free(gd, sizeof(*gd)); - mem_free(auth, sizeof(*auth)); - - return (TRUE); -} - -bool_t -svcauth_gss_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) -{ - struct svc_rpc_gss_data *gd; - - log_debug("in svcauth_gss_wrap()"); - - gd = SVCAUTH_PRIVATE(auth); - - if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { - return ((*xdr_func)(xdrs, xdr_ptr)); - } - return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, - gd->ctx, gd->sec.qop, - gd->sec.svc, gd->seq)); -} - -bool_t -svcauth_gss_unwrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr) -{ - struct svc_rpc_gss_data *gd; - - log_debug("in svcauth_gss_unwrap()"); - - gd = SVCAUTH_PRIVATE(auth); - - if (!gd->established || gd->sec.svc == RPCSEC_GSS_SVC_NONE) { - return ((*xdr_func)(xdrs, xdr_ptr)); - } - return (xdr_rpc_gss_data(xdrs, xdr_func, xdr_ptr, - gd->ctx, gd->sec.qop, - gd->sec.svc, gd->seq)); -} - -char * -svcauth_gss_get_principal(SVCAUTH *auth) -{ - struct svc_rpc_gss_data *gd; - char *pname; - - gd = SVCAUTH_PRIVATE(auth); - - if (gd->cname.length == 0) - return (NULL); - - if ((pname = malloc(gd->cname.length + 1)) == NULL) - return (NULL); - - memcpy(pname, gd->cname.value, gd->cname.length); - pname[gd->cname.length] = '\0'; - - return (pname); -}