]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/rpc/svc_auth_gss.c
Remove the rpcsec_gss code and rely on an external library instead.
[nfs-utils.git] / support / rpc / svc_auth_gss.c
diff --git a/support/rpc/svc_auth_gss.c b/support/rpc/svc_auth_gss.c
deleted file mode 100644 (file)
index 82b8d01..0000000
+++ /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 <dugsong@UMICH.EDU>.
-  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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <rpc/rpc.h>
-#include <gssapi/gssapi.h>
-
-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 "
-                                 "<mech %.*s, qop %d, svc %d>",
-                                 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 "
-                         "<mech {}, qop %d, svc %d>",
-                         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 = &num;
-       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);
-}