/* Copyright (C) 1999 Beau Kuiper

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include "ftpd.h"

int checknamelist(CONFIGFILECACHE *cf, int section, char *username)
{
	int occur;
	char *setting;
	
	occur = 1;
	while ((setting = getconfigdata(cf, section,
				        "nameacl", occur)))
	{
		char *name = strchr(setting, ':');
		
		if (name)
		{
			name++;
			if (my_fnmatch(name, username, 0) == 0)
				return((*setting == 'A') || (*setting == 'a'));
		}
		occur++;
	}
	return(FALSE);
}

IPACLLIST *ipacllist_new(CONFIGFILECACHE *cf, int section, char *name)
{
	int occur;
	char *setting;
	IPACLLIST *new = mallocwrapper(sizeof(IPACLLIST));
	
	occur = 1;
	new->count = 0;
	new->list = NULL;
	
	while ((setting = getconfigdata(cf, section, name,
			  occur)))
	{
		char *settingt = strdupwrapper(setting);
		char *netmask, *ipaddr;
		
		strtrimspace(settingt);
		ipaddr = strchr(settingt, ':');
	
		if (ipaddr)
		{
			ipaddr++;
			netmask = strchr(ipaddr, '/');
			reallocwrapper(sizeof(IPACL) * (new->count + 1),
				       (void *)&(new->list));
			new->list[new->count].accept = (*settingt == 'A') ||
						       (*settingt == 'a');

			if ((*ipaddr == '(') && (ipaddr[strlen(ipaddr)-1] == ')'))
			{
				/* hostname-pattern type IPACL */
				memmove(settingt, ipaddr + 1, strlen(ipaddr));
				settingt[strlen(settingt)-1] = 0;
				new->list[new->count].fnstr = settingt;
				new->list[new->count].type = 0;
			}
			else if (!netmask)
			{
				/* IP-pattern type IPACL */
				memmove(settingt, ipaddr, strlen(ipaddr)+1);
				new->list[new->count].fnstr = settingt; 
				new->list[new->count].type = 1;
			}
			else
			{
				*netmask = 0;
				netmask++;
				getnetworkint(ipaddr, &(new->list[new->count].ipaddr));
				getnetworkint(netmask, &(new->list[new->count].netmask));
				new->list[new->count].fnstr = NULL;
				freewrapper(settingt);
				new->list[new->count].type = 2;
			}
			new->count++;
		}
		else
		{
			log_addentry(MYLOG_INFO, NULL, "Error decoding ipacl directive, data missing ':'. Skipping entry.");
			freewrapper(settingt);
		}

		occur++;
	}
	return(new);
}

void ipacllist_destroy(IPACLLIST *list)
{
	int count;
	
	if (list->count > 0)
	{
		for (count = 0; count < list->count; count++)
	 		freeifnotnull(list->list[count].fnstr);
		freewrapper(list->list);
	}

	freewrapper(list);
}

int user_allowed(IPACLLIST *list, int ip, char *hostname)
{
	int pos = 0;
	int mip, mip2;
	char *ipstr = (char *)getipstr(ip);
	
	for (pos = 0; pos < list->count; pos++)
	{
		switch(list->list[pos].type)
		{
			case 0:
				if (my_fnmatch(list->list[pos].fnstr, hostname, 0) == 0)
					return(list->list[pos].accept);
				break;
			case 1:
				if (my_fnmatch(list->list[pos].fnstr, ipstr, 0) == 0)
					return(list->list[pos].accept);
				break;
			case 2:
				mip = ip & list->list[pos].netmask;
				mip2 = list->list[pos].ipaddr & list->list[pos].netmask;
				if (mip == mip2)
					return(list->list[pos].accept);
				break;
		}
	}
	return(FALSE);
}
