#ifdef _KERNEL
#include <sys/param.h>
#include <sys/types.h>
#include <sys/debug.h>
#include <sys/systm.h>
#include <rpc/types.h>
#include <netinet/in.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include <rpc/rpc_msg.h>
#include <sys/tiuser.h>
#include <sys/tihdr.h>
#include <sys/t_kuser.h>
#include <sys/cmn_err.h>
#include <rpc/auth_des.h>
#include <rpc/auth_sys.h>
#include <rpc/rpcsec_gss.h>
#include <rpc/svc_auth.h>
#include <rpc/svc.h>
#else
#include <rpc/rpc.h>
#endif
enum auth_stat _svcauth_null(struct svc_req *, struct rpc_msg *);
static int
svc_authany_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xfunc, caddr_t xwhere)
{
return (*xfunc)(xdrs, xwhere);
}
struct svc_auth_ops svc_authany_ops = {
svc_authany_wrap,
svc_authany_wrap
};
enum auth_stat
sec_svc_msg(struct svc_req *rqst, struct rpc_msg *msg, bool_t *no_dispatch)
{
int cred_flavor;
rqst->rq_cred = msg->rm_call.cb_cred;
rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
rqst->rq_xprt->xp_verf.oa_length = 0;
rqst->rq_xprt->xp_auth.svc_ah_ops = svc_authany_ops;
rqst->rq_xprt->xp_auth.svc_ah_private = NULL;
*no_dispatch = FALSE;
cred_flavor = rqst->rq_cred.oa_flavor;
switch (cred_flavor) {
case AUTH_NULL:
rqst->rq_xprt->xp_cookie = (void *) AUTH_NULL;
return (_svcauth_null(rqst, msg));
case AUTH_UNIX:
rqst->rq_xprt->xp_cookie = (void *) AUTH_UNIX;
return (_svcauth_unix(rqst, msg));
case AUTH_SHORT:
rqst->rq_xprt->xp_cookie = (void *) AUTH_SHORT;
return (_svcauth_short(rqst, msg));
case AUTH_DES:
rqst->rq_xprt->xp_cookie = (void *) AUTH_DES;
return (_svcauth_des(rqst, msg));
case RPCSEC_GSS:
return (__svcrpcsec_gss(rqst, msg, no_dispatch));
}
return (AUTH_REJECTEDCRED);
}
int
sec_svc_getcred(struct svc_req *req, cred_t *cr, caddr_t *principal,
int *secmod)
{
struct authunix_parms *aup;
struct authdes_cred *adc;
int flavor, stat;
rpc_gss_rawcred_t *rcred;
rpc_gss_ucred_t *ucred;
void *cookie;
stat = 1;
flavor = req->rq_cred.oa_flavor;
*principal = NULL;
switch (flavor) {
case AUTH_UNIX:
*secmod = AUTH_UNIX;
aup = (struct authunix_parms *)req->rq_clntcred;
if (crsetugid(cr, aup->aup_uid, aup->aup_gid) != 0)
(void) crsetugid(cr, UID_NOBODY, GID_NOBODY);
if (crsetgroups(cr, aup->aup_len, aup->aup_gids) != 0)
(void) crsetgroups(cr, 0, NULL);
break;
case AUTH_NONE:
*secmod = AUTH_NONE;
break;
case AUTH_DES:
*secmod = AUTH_DES;
adc = (struct authdes_cred *)req->rq_clntcred;
stat = kauthdes_getucred(adc, cr);
*principal = adc->adc_fullname.name;
break;
case RPCSEC_GSS:
stat = rpc_gss_getcred(req, &rcred, &ucred, &cookie);
*secmod = (int)(uintptr_t)cookie;
if (ucred != NULL) {
if (crsetugid(cr, ucred->uid, ucred->gid) != 0 ||
crsetgroups(cr, ucred->gidlen, ucred->gidlist) != 0)
stat = 0;
} else {
(void) crsetugid(cr, UID_NOBODY, GID_NOBODY);
(void) crsetgroups(cr, 0, NULL);
}
*principal = (caddr_t)rcred->client_principal;
break;
default:
stat = 0;
break;
}
return (stat);
}
enum auth_stat
_svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
{
return (AUTH_OK);
}
int
sec_svc_loadrootnames(int flavor, int count, caddr_t **proots, model_t model)
{
caddr_t *roots, *oroots, root;
char netname[MAXNETNAMELEN+1];
struct rpc_gss_principal gsstmp, *gssname;
uint_t i, j;
size_t len, allocsz, oallocsz;
#ifdef lint
model = model;
#endif
allocsz = count * sizeof (caddr_t);
oallocsz = count * SIZEOF_PTR(model);
switch (flavor) {
case AUTH_DES:
roots = kmem_zalloc(allocsz, KM_SLEEP);
oroots = kmem_alloc(oallocsz, KM_SLEEP);
if (copyin(*proots, oroots, oallocsz))
goto done;
for (i = 0; i < count; i++) {
#ifdef _SYSCALL32_IMPL
if (model != DATAMODEL_NATIVE) {
caddr32_t *tmp;
tmp = (caddr32_t *)oroots;
root = (caddr_t)(uintptr_t)tmp[i];
} else
#endif
root = oroots[i];
if (copyinstr(root, netname, sizeof (netname), &len)) {
for (j = 0; j < i; j++) {
if (roots[j] != NULL)
kmem_free(roots[j],
strlen(roots[j]) + 1);
}
goto done;
}
roots[i] = kmem_alloc(len, KM_SLEEP);
bcopy(netname, roots[i], len);
}
kmem_free(oroots, oallocsz);
*proots = roots;
return (1);
case RPCSEC_GSS:
roots = kmem_alloc(allocsz, KM_SLEEP);
oroots = kmem_alloc(oallocsz, KM_SLEEP);
if (copyin(*proots, oroots, oallocsz))
goto done;
for (i = 0; i < count; i++) {
#ifdef _SYSCALL32_IMPL
if (model != DATAMODEL_NATIVE) {
caddr32_t *tmp;
tmp = (caddr32_t *)oroots;
root = (caddr_t)(uintptr_t)tmp[i];
} else
#endif
root = oroots[i];
if (copyin(root, &gsstmp, sizeof (gsstmp))) {
kmem_free(oroots, oallocsz);
goto gssfreeup;
}
len = sizeof (gsstmp.len) + gsstmp.len;
gssname = kmem_alloc(len, KM_SLEEP);
if (copyin(root, gssname, len)) {
kmem_free(gssname, len);
kmem_free(oroots, oallocsz);
goto gssfreeup;
}
roots[i] = (caddr_t)gssname;
}
kmem_free(oroots, oallocsz);
*proots = roots;
return (1);
default:
return (0);
}
gssfreeup:
for (j = 0; j < i; j++) {
if (roots[j] != NULL) {
gssname = (rpc_gss_principal_t)roots[j];
kmem_free(roots[j], gssname->len +
sizeof (gssname->len));
}
}
done:
kmem_free(roots, allocsz);
return (0);
}
void
sec_svc_freerootnames(int flavor, int count, caddr_t *proots)
{
int i;
rpc_gss_principal_t gssname;
switch (flavor) {
case AUTH_DES:
for (i = 0; i < count; i++)
if (proots[i] != NULL)
kmem_free(proots[i], strlen(proots[i]) + 1);
break;
case RPCSEC_GSS:
for (i = 0; i < count; i++) {
if (proots[i] == NULL)
continue;
gssname = (rpc_gss_principal_t)proots[i];
kmem_free(proots[i], gssname->len + sizeof (int));
}
break;
}
kmem_free(proots, count * sizeof (caddr_t));
}
bool_t
sec_svc_inrootlist(int flavor, caddr_t rootname, int count, caddr_t *roots)
{
int i, tmp_len;
rpc_gss_principal_t gssp, tmp_gssp;
size_t namelen;
switch (flavor) {
case AUTH_DES:
namelen = strlen(rootname) + 1;
for (i = 0; i < count; i++)
if (bcmp(rootname, roots[i], namelen) == 0)
return (TRUE);
break;
case RPCSEC_GSS:
gssp = (rpc_gss_principal_t)rootname;
namelen = gssp->len;
for (i = 0; i < count; i++) {
tmp_gssp = (rpc_gss_principal_t)roots[i];
tmp_len = tmp_gssp->len;
if ((namelen == tmp_len) &&
(bcmp(&gssp->name[0],
&tmp_gssp->name[0], namelen) == 0))
return (TRUE);
}
break;
}
return (FALSE);
}
bool_t
sec_svc_control(uint_t cmd, void *argp)
{
bool_t result = FALSE;
switch (cmd) {
case RPC_SVC_SET_GSS_CALLBACK:
result = rpc_gss_set_callback((rpc_gss_callback_t *)argp);
break;
default:
cmn_err(CE_WARN, "sec_svc_control: bad command (%d)", cmd);
result = FALSE;
break;
}
return (result);
}