/*
 *  rpcauth_gss.c
 *
 *  RPC RPCSEC_GSS protection
 *
 *  Copyright (c) 2004 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Marius Aamodt Eriksen <marius@umich.edu>
 *
 *  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 <sys/param.h>
#include <sys/types.h>
#include <sys/ucred.h>
#include <sys/mbuf.h>
#include <sys/systm.h>

#include <nfsx/rpcv2.h>
#include <nfsx/xdr_subs.h>

#include <rpcx/rpcclnt.h>
#include <rpcx/rpcclnt-private.h>
#include <rpcx/rpcauth.h>
#include <rpcx/rpcauth_gss.h>
#include <rpcx/rpcm_subs.h>
#include <rpcx/rpc_dev.h>

static void *gss_create(int);
static int   gss_build_reqhdr(struct ucred *, struct mbuf **,
                 caddr_t *, struct mbuf *mbody);

struct rpcauth_desc auth_gss_desc = {
	.auth_create = gss_create,
	.auth_build_reqhdr = gss_build_reqhdr,
	.auth_pflavors = RPCAUTH_PFLAVOR_KERB5,
};

static void *
gss_create(int pflavor)
{
	return (&auth_gss_desc);
}

static int
gss_build_reqhdr(struct ucred *cred, struct mbuf **mbp,
    caddr_t *bposp, struct mbuf *mbody)
{
	size_t authsiz, verfsiz;
	u_int32_t mlen, grpsiz;
	register struct mbuf *mb, *mb2;
	caddr_t bpos;
	u_int32_t *tl;
	int i;

	printf("auth_gss building reqhdr\n");

	authsiz = (5 + cred->cr_ngroups) * RPCX_UNSIGNED;
	verfsiz = 0;

	mlen = rpcm_rndup(authsiz) + rpcm_rndup(verfsiz) + 4 * RPCX_UNSIGNED;

	mb = *mbp;
	bpos = *bposp;

	rpcm_build(tl, u_int32_t *, mlen);

	*bposp = bpos;
	*mbp = mb;

	*tl++ = txdr_unsigned(RPCAUTH_UNIX);
	*tl++ = txdr_unsigned(authsiz);

	*tl++ = 0;
	*tl++ = 0; 

	*tl++ = txdr_unsigned(cred->cr_uid);
	*tl++ = txdr_unsigned(cred->cr_groups[0]);
	grpsiz = cred->cr_ngroups;
	*tl++ = txdr_unsigned(grpsiz);
	/* XXX: groups[0] is already sent... */
	for (i = 0 ; i < grpsiz ; i++)
		*tl++ = txdr_unsigned(cred->cr_groups[i]);

	/* null verification header */
	*tl++ = txdr_unsigned(RPCAUTH_NULL);
	*tl++ = 0;

	{
		struct rpcauth_gss_request req;
		struct rpcauth_gss_reply rep;
		size_t siz;
		int error;

		req.req_uid = cred->cr_uid;
		error = rpcdev_call(RPCDEV_TYPE_RPCD, (caddr_t)&req,
		    sizeof(req), (caddr_t)&rep, &siz, 0);
		printf("finished upcall and ret = %d\n", error);
	}

	return (0);
}
