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 *));