/*
 * Copyright 1993, 1994 by Ulrich Khn. All rights reserved.
 *
 * THIS PROGRAM COMES WITH ABSOLUTELY NO WARRANTY, NOT
 * EVEN THE IMPLIED WARRANTIES OF MERCHANTIBILITY OR
 * FITNESS FOR A PARTICULAR PURPOSE. USE AT YOUR OWN
 * RISK.
 */

/*
 * File : auth_nfs.c
 *        access checking for the nfs daemon
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <types.h>
#include <ctype.h>
#include <stat.h>
#include <netdb.h>
#include <arpa/inet.h>
#include "../xfs/nfs.h"
#include "util.h"
#include "auth.h"
#include "fh.h"
#include "svc.h"


/*
 * Walk through the list and check if the requesting client is listed there.
 * If so, put it to the front of the list for faster access next time.
 */
int
search_clientlist(client_info **plist, SVCXPRT *xprt)
{
	client_info *cl, ** pcl;

	for (pcl = plist, cl = *plist;  cl;  pcl = &cl->next, cl = cl->next)
	{
		if (cl->addr.s_addr == xprt->xp_raddr.sin_addr.s_addr)
			break;
	}
	if (!cl)
		return -1;

	/* Put it to the front of the list */
	*pcl = cl->next;
	cl->next = *plist;
	*plist = cl;
	return 0;
}


/*
 * Do the per-request access check for a given nfs handle. Look for the
 * file system tree this one lies on, and check if the requesting client
 * is allowed to access it. Return the possible access permissions like
 * root or read-mostly access.
 */
accesslist *
auth_nfs(svc_fh *fh, SVCXPRT *xprt, int *auth_kind)
{
	accesslist *ac, **pac;

	/* Search the right member in the list */
	if (fh == NULL)
		return NULL;
	for (pac = &authlist, ac = authlist;  ac;  pac = &ac->next, ac = ac->next)
	{
		if ((ac->dev == fh->dev) && (ac->inode == fh->root_inode))
			break;
	}
	if (!ac)
		return NULL;

	/* Put it to the front of the list, so later accesses are faster */
	*pac = ac->next;
	ac->next = authlist;
	authlist = ac;

	/* Check if the client is allowed to access this directory */
	*auth_kind = AUTH_NO;
	if (search_clientlist(&ac->access, xprt) == 0)
		*auth_kind |= AUTH_NORMAL;
	if (search_clientlist(&ac->rw_access, xprt) == 0)
		*auth_kind |= AUTH_RW;
	if (search_clientlist(&ac->root_access, xprt) == 0)
		*auth_kind |= AUTH_ROOT;
	return ac;
}
