/* 
 * Copyright (C) 1999-2004 Joachim Wieland <joe@mcknight.de>
 * 
 * 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 of the License, 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.,
 * 59 Temple Place - Suite 330, Boston, MA 02111, USA.
 */

#include <syslog.h>
#include <stdarg.h>
#include <pwd.h>
#include <grp.h>
#include <sys/types.h>
#include "jftpgw.h"

extern struct serverinfo srvinfo;

struct hostent_list* hostcache;
struct uidstruct runasuser;
struct connliststruct* connected_clients = (struct connliststruct*) 0;

struct slist_t* passcmd_white_list, *passcmd_black_list;

int register_pid(pid_t pid,
		 unsigned long int from_ip,
		 unsigned long int proxy_ip,
		 unsigned int proxy_port,
		 time_t start_time) {

	struct connliststruct *cls, *tmp;

	cls = (struct connliststruct*) malloc(sizeof(struct connliststruct));
	enough_mem(cls);

	cls->next = (struct connliststruct*) 0;
	cls->pid = pid;
	cls->from_ip = from_ip;
	cls->proxy_ip = proxy_ip;
	cls->proxy_port = proxy_port;
	cls->start_time = start_time;
	jlog(9, "Adding pid %d", cls->pid);

	if (! connected_clients) {
		/* first entry */
		connected_clients = cls;
	} else {
		tmp = connected_clients;
		while (tmp->next) {
			tmp = tmp->next;
		}
		tmp->next = cls;
	}

	if (kill(pid, 0) < 0) {
		/* the child might have already terminated */
		unregister_pid(pid);
	}

	return 0;
}


int unregister_pid(pid_t pid) {

	struct connliststruct* cls, *prev = 0;

	cls = connected_clients;

	if (! cls) {
		/* empty! Error! */
		return 1;
	}

	while (cls) {
		jlog(8, "checking %d against %d", cls->pid, pid);
		if (cls->pid == pid) {
			/* found */
			/* delete it */
			/* case 1: prev is set */
			if (prev) {
				prev->next = cls->next;
			}

			/* case 2: prev not set */
			  else {
				/* first element */
				if (! cls->next) {
					/* only one element */
					connected_clients =
						(struct connliststruct*) 0;
				} else {
					/* nothing special, it's just the
					 * first element */
					connected_clients = cls->next;
				}
			}
			config_counter_decrease(cls->from_ip,
						cls->proxy_ip,
						cls->proxy_port,
						cls->start_time);
			/* remove that element */
			free(cls);
			return 0;
		}
		prev = cls;
		cls = cls->next;
	}
	/* not found */
	return 1;
}


int set_conffilename(const char* arg) {
	const int increment = 1;
	int pathsize = 1;
	char* ret;
	char* path;
	char* fname;

	if (!arg || strlen(arg) > PATH_MAX) {
		free(srvinfo.conffilename);
		srvinfo.conffilename = (char*) 0;
		return -1;
	}

	path = (char*) malloc(pathsize);
	enough_mem(path);
	free(srvinfo.conffilename);
	while ( ! (ret = getcwd(path, pathsize)) ) {
		pathsize += increment;
		if (pathsize > PATH_MAX) {
			srvinfo.conffilename = (char*) 0;
			free(path);
			return -1;
		}
		path = (char*) realloc(path, pathsize);
	}

	fname = (char*) malloc(PATH_MAX + 1);
	srvinfo.conffilename = rel2abs(arg, path, fname, PATH_MAX);
	if ( ! srvinfo.conffilename ) {
		free(path); free(fname);
		return -1;
	} else {
		/* reduce allocated memory */
		srvinfo.conffilename = realloc(fname, strlen(fname) + 1);
		enough_mem(srvinfo.conffilename);
		free(path);
	}
	jlog(9, "Conffile set to %s", srvinfo.conffilename);
	return 0;
}

void free_cmdlogentst(struct cmdlogent_t* cls) {
	if (!cls) {
		return;
	}
	free_cmdlogentst(cls->next);
	if (cls->logf_name) {
		free(cls->logf_name);
	}
	if (cls->specs) {
		free(cls->specs);
	}
	if (cls->logf) {
		fclose(cls->logf);
		cls->logf = (FILE*) 0;
	}
	if (cls->style) {
		free(cls->style);
	}
	free(cls);
}

void reset_loginfo(struct loginfo_st* ls) {
	if (!ls) {
		jlog(1, "loginfo_st* ls was NULL, this should NEVER happen!");
		return;
	}
	if (ls->logf_name) {
		free(ls->logf_name);
		ls->logf_name = (char*) 0;
	}
	if (ls->logf) {
		fclose(ls->logf);
		ls->logf = (FILE*) 0;
	}
	if (ls->syslog) {
		closelog();
	}
	free_cmdlogentst(ls->cmdlogfiles);
	free_cmdlogentst(ls->cmdlogdirs);
	ls->cmdlogfiles = (struct cmdlogent_t*) 0;
	ls->cmdlogdirs = (struct cmdlogent_t*) 0;
}


int getservermode() {
	int servmode = ASCLIENT;
	const char* opt = config_get_option("defaultmode");

	/* opt should be set in every case */
	if (opt) {
		if (0 == strcasecmp(opt, "passive")) {
			servmode = PASSIVE;
		}
		if (0 == strcasecmp(opt, "active")) {
			servmode = ACTIVE;
		}
		if (0 == strcasecmp(opt, "asclient")) {
			servmode = ASCLIENT;
		}
	}
	return servmode;
}



int save_runasuser_uid(void) {
	const char* option;
	struct passwd* pws;
	struct group* gs;

	option = config_get_option("runasuser");
	if (option) {
		if (runasuser.username) { free(runasuser.username); }
		runasuser.username = strdup(option);
		enough_mem(runasuser.username);
		runasuser.username = trim(runasuser.username);
		pws = getpwnam(runasuser.username);
		if (!pws) {
			jlog(3, "getpwnam(2) could not look up user %s",
				runasuser.username);
			perror("Could not look up the user name");
			return -1;
		}
		runasuser.uid = pws->pw_uid;
	} else {
		runasuser.uid = getuid();
	}

	option = config_get_option("runasgroup");
	if (option) {
		if (runasuser.groupname) { free(runasuser.groupname); }
		runasuser.groupname = strdup(option);
		enough_mem(runasuser.groupname);
		runasuser.groupname = trim(runasuser.groupname);
		gs = getgrnam(runasuser.groupname);
		if (!gs) {
			jlog(3, "getpwnam(2) could not look up group %s",
							runasuser.groupname);
			perror("Could not look up the group name");
			return -1;
		}
		runasuser.gid = gs->gr_gid;
	} else {
		runasuser.gid = getgid();
	}
	return 0;
}

struct slist_t* passcmd_create_list(const char* list_str) {
	if ( ! list_str ) {
		return (struct slist_t*) 0;
	}
	return config_split_line(list_str, WHITESPACES);
}

int passcmd_check(const char* cmd) {

	if (strcmp(config_get_option("passcmds"), "*") == 0) {
		/* this is a dummy and means "checking disabled". The "*"
		 * is the standard value if there is no such option in the
		 * configuration */
		return 1;
	}

	if ( !passcmd_white_list ) {
		passcmd_white_list
			= passcmd_create_list(config_get_option("passcmds"));
	}
	if ( !passcmd_black_list ) {
		passcmd_black_list
			= passcmd_create_list(config_get_option("dontpasscmds"));
	}

	if (slist_case_contains(passcmd_white_list, cmd)
			&&
	   !slist_case_contains(passcmd_black_list, cmd)) {

		return 1;
	}
	return 0;
}



syntax highlighted by Code2HTML, v. 0.9.1