diff --git a/src/svc.c b/src/svc.c index 08cd6c9..8afd15d 100644 --- a/src/svc.c +++ b/src/svc.c @@ -649,6 +649,7 @@ svc_getreq_common (fd) { if (SVC_RECV (xprt, &msg)) { + bool_t no_dispatch; /* now find the exported program and call it */ struct svc_callout *s; @@ -660,11 +661,14 @@ svc_getreq_common (fd) r.rq_proc = msg.rm_call.cb_proc; r.rq_cred = msg.rm_call.cb_cred; /* first authenticate the message */ - if ((why = _authenticate (&r, &msg)) != AUTH_OK) + why = _gss_authenticate(&r, &msg, &no_dispatch); + if (why != AUTH_OK) { svcerr_auth (xprt, why); goto call_done; } + if (no_dispatch) + goto call_done; /* now match message with a registered service */ prog_found = FALSE; low_vers = (rpcvers_t) - 1L; diff --git a/src/svc_auth.c b/src/svc_auth.c index e80d5f9..31241c9 100644 --- a/src/svc_auth.c +++ b/src/svc_auth.c @@ -82,9 +82,10 @@ static struct authsvc *Auths = NULL; * invalid. */ enum auth_stat -_authenticate(rqst, msg) +_gss_authenticate(rqst, msg, no_dispatch) struct svc_req *rqst; struct rpc_msg *msg; + bool_t *no_dispatch; { int cred_flavor; struct authsvc *asp; @@ -97,6 +98,7 @@ _authenticate(rqst, msg) rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor; rqst->rq_xprt->xp_verf.oa_length = 0; cred_flavor = rqst->rq_cred.oa_flavor; + *no_dispatch = FALSE; switch (cred_flavor) { case AUTH_NONE: dummy = _svcauth_none(rqst, msg); @@ -112,6 +114,11 @@ _authenticate(rqst, msg) dummy = _svcauth_des(rqst, msg); return (dummy); #endif +#ifdef HAVE_RPCSEC_GSS + case RPCSEC_GSS: + dummy = _svcauth_gss(rqst, msg, no_dispatch); + return (dummy); +#endif default: break; } @@ -132,6 +139,13 @@ _authenticate(rqst, msg) return (AUTH_REJECTEDCRED); } +enum auth_stat +_authenticate(struct svc_req *rqst, struct rpc_msg *msg) +{ + bool_t no_dispatch; + return _gss_authenticate(rqst, msg, &no_dispatch); +} + /* * Allow the rpc service to register new authentication types that it is * prepared to handle. When an authentication flavor is registered, @@ -161,6 +175,9 @@ svc_auth_reg(cred_flavor, handler) #ifdef DES_BUILTIN case AUTH_DES: #endif +#ifdef HAVE_RPCSEC_GSS + case RPCSEC_GSS: +#endif /* already registered */ return (1); diff --git a/src/svc_auth_gss.c b/src/svc_auth_gss.c index 3a3c980..7376107 100644 --- a/src/svc_auth_gss.c +++ b/src/svc_auth_gss.c @@ -116,6 +116,7 @@ svcauth_gss_import_name(char *service) gss_name_t name; gss_buffer_desc namebuf; OM_uint32 maj_stat, min_stat; + bool_t result; gss_log_debug("in svcauth_gss_import_name()"); @@ -130,11 +131,9 @@ svcauth_gss_import_name(char *service) maj_stat, min_stat); return (FALSE); } - if (svcauth_gss_set_svc_name(name) != TRUE) { - gss_release_name(&min_stat, &name); - return (FALSE); - } - return (TRUE); + result = svcauth_gss_set_svc_name(name); + gss_release_name(&min_stat, &name); + return result; } static bool_t @@ -211,6 +210,8 @@ svcauth_gss_accept_sec_context(struct svc_req *rqst, NULL, NULL); + xdr_free((xdrproc_t)xdr_rpc_gss_init_args, (caddr_t)&recv_tok); + if (gr->gr_major != GSS_S_COMPLETE && gr->gr_major != GSS_S_CONTINUE_NEEDED) { gss_log_status("svcauth_gss_accept_sec_context: accept_sec_context", @@ -279,8 +280,11 @@ svcauth_gss_accept_sec_context(struct svc_req *rqst, return (FALSE); rqst->rq_xprt->xp_verf.oa_flavor = RPCSEC_GSS; - rqst->rq_xprt->xp_verf.oa_base = checksum.value; + memcpy(rqst->rq_xprt->xp_verf.oa_base, checksum.value, + checksum.length); rqst->rq_xprt->xp_verf.oa_length = checksum.length; + + gss_release_buffer(&min_stat, &checksum); } return (TRUE); } @@ -363,10 +367,13 @@ svcauth_gss_nextverf(struct svc_req *rqst, u_int num) 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; + memcpy(rqst->rq_xprt->xp_verf.oa_base, checksum.value, checksum.length); rqst->rq_xprt->xp_verf.oa_length = (u_int)checksum.length; + gss_release_buffer(&min_stat, &checksum); + return (TRUE); } @@ -379,8 +386,10 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) struct rpc_gss_cred *gc; struct rpc_gss_init_res gr; int call_stat, offset; + enum auth_stat result = AUTH_OK; + OM_uint32 min_stat; - gss_log_debug("in svcauth_gss()"); + gss_log_debug("in _svcauth_gss()"); /* Initialize reply. */ rqst->rq_xprt->xp_verf = _null_auth; @@ -419,19 +428,25 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) XDR_DESTROY(&xdrs); /* Check version. */ - if (gc->gc_v != RPCSEC_GSS_VERSION) - return (AUTH_BADCRED); + if (gc->gc_v != RPCSEC_GSS_VERSION) { + result = AUTH_BADCRED; + goto out; + } /* 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); + gc->gc_svc != RPCSEC_GSS_SVC_PRIVACY) { + result = AUTH_BADCRED; + goto out; + } /* Check sequence number. */ if (gd->established) { - if (gc->gc_seq > MAXSEQ) - return (RPCSEC_GSS_CTXPROBLEM); + if (gc->gc_seq > MAXSEQ) { + result = RPCSEC_GSS_CTXPROBLEM; + goto out; + } if ((offset = gd->seqlast - gc->gc_seq) < 0) { gd->seqlast = gc->gc_seq; @@ -441,7 +456,8 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) } else if (offset >= gd->win || (gd->seqmask & (1 << offset))) { *no_dispatch = 1; - return (RPCSEC_GSS_CTXPROBLEM); + result = RPCSEC_GSS_CTXPROBLEM; + goto out; } gd->seq = gc->gc_seq; gd->seqmask |= (1 << offset); @@ -452,35 +468,52 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) rqst->rq_svcname = (char *)gd->ctx; } + rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base; + /* 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 (rqst->rq_proc != NULLPROC) { + result = AUTH_FAILED; + break; + } if (_svcauth_gss_name == NULL) { - if (!svcauth_gss_import_name("nfs")) - return (AUTH_FAILED); + if (!svcauth_gss_import_name("nfs")) { + result = AUTH_FAILED; + break; + } } - if (!svcauth_gss_acquire_cred()) - return (AUTH_FAILED); + if (!svcauth_gss_acquire_cred()) { + result = AUTH_FAILED; + break; + } - if (!svcauth_gss_accept_sec_context(rqst, &gr)) - return (AUTH_REJECTEDCRED); + if (!svcauth_gss_accept_sec_context(rqst, &gr)) { + result = AUTH_REJECTEDCRED; + break; + } - if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) - return (AUTH_FAILED); + if (!svcauth_gss_nextverf(rqst, htonl(gr.gr_win))) { + result = AUTH_FAILED; + break; + } *no_dispatch = TRUE; call_stat = svc_sendreply(rqst->rq_xprt, (xdrproc_t)xdr_rpc_gss_init_res, (caddr_t)&gr); - if (!call_stat) - return (AUTH_FAILED); + gss_release_buffer(&min_stat, &gr.gr_token); + free(gr.gr_ctx.value); + + if (!call_stat) { + result = AUTH_FAILED; + break; + } if (gr.gr_major == GSS_S_COMPLETE) gd->established = TRUE; @@ -488,25 +521,36 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) break; case RPCSEC_GSS_DATA: - if (!svcauth_gss_validate(gd, msg)) - return (RPCSEC_GSS_CREDPROBLEM); + if (!svcauth_gss_validate(gd, msg)) { + result = RPCSEC_GSS_CREDPROBLEM; + break; + } - if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) - return (AUTH_FAILED); + if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) { + result = AUTH_FAILED; + break; + } 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 (rqst->rq_proc != NULLPROC) { + result = AUTH_FAILED; /* XXX ? */ + break; + } + if (!svcauth_gss_validate(gd, msg)) { + result = RPCSEC_GSS_CREDPROBLEM; + break; + } - if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) - return (AUTH_FAILED); + if (!svcauth_gss_nextverf(rqst, htonl(gc->gc_seq))) { + result = AUTH_FAILED; + break; + } - if (!svcauth_gss_release_cred()) - return (AUTH_FAILED); + if (!svcauth_gss_release_cred()) { + result = AUTH_FAILED; + break; + } SVCAUTH_DESTROY(rqst->rq_xprt->xp_auth); rqst->rq_xprt->xp_auth = &svc_auth_none; @@ -514,10 +558,15 @@ _svcauth_gss(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch) break; default: - return (AUTH_REJECTEDCRED); + result = AUTH_REJECTEDCRED; break; } - return (AUTH_OK); +out: + xdr_free((xdrproc_t)xdr_rpc_gss_cred, (caddr_t)gc); + if (result != AUTH_OK) + gss_log_debug("_svcauth_gss() failed: %d", result); + + return result; } bool_t diff --git a/tirpc/rpc/auth.h b/tirpc/rpc/auth.h index 4ce11f0..7c8f813 100644 --- a/tirpc/rpc/auth.h +++ b/tirpc/rpc/auth.h @@ -399,6 +399,7 @@ struct rpc_msg; enum auth_stat _svcauth_none (struct svc_req *, struct rpc_msg *); enum auth_stat _svcauth_short (struct svc_req *, struct rpc_msg *); enum auth_stat _svcauth_unix (struct svc_req *, struct rpc_msg *); +enum auth_stat _svcauth_gss (struct svc_req *, struct rpc_msg *, bool_t *); __END_DECLS #define AUTH_NONE 0 /* no authentication */ diff --git a/tirpc/rpc/svc_auth.h b/tirpc/rpc/svc_auth.h index 14269d1..723c989 100644 --- a/tirpc/rpc/svc_auth.h +++ b/tirpc/rpc/svc_auth.h @@ -66,6 +66,8 @@ typedef struct SVCAUTH { * Server side authenticator */ __BEGIN_DECLS +extern enum auth_stat _gss_authenticate(struct svc_req *, struct rpc_msg *, + bool_t *); extern enum auth_stat _authenticate(struct svc_req *, struct rpc_msg *); extern int svc_auth_reg(int, enum auth_stat (*)(struct svc_req *, struct rpc_msg *));