/*
 * Configurable Finger Daemon Utilities
 * by Ken Hollis
 */

#include "cfingerd.h"
#include "version.h"

void initialize_daemon(void)
{
    prog_config.config_bits1 = 0x0000;
    prog_config.config_bits2 = 0x0000;
    prog_config.local_config_bits1 = 0x0000;
    prog_config.local_config_bits2 = 0x0000;

    local_finger = FALSE;
    trusted = FALSE;
    rejected = FALSE;

    trusted_host_num = 0;
    rejected_host_num = 0;

    signal(SIGHUP, int_handler);
    signal(SIGINT, int_handler);
    signal(SIGQUIT, int_handler);
    signal(SIGILL, int_handler);
    signal(SIGTRAP, int_handler);
    signal(SIGABRT, int_handler);
    signal(SIGFPE, int_handler);
    signal(SIGKILL, int_handler);
    signal(SIGUSR1, int_handler);
    signal(SIGSEGV, int_handler);
    signal(SIGUSR2, int_handler);
    signal(SIGPIPE, int_handler);
    signal(SIGALRM, int_handler);
    signal(SIGTERM, int_handler);
    signal(SIGCHLD, int_handler);
    signal(SIGCONT, int_handler);
    signal(SIGTSTP, int_handler);
    signal(SIGTTIN, int_handler);
    signal(SIGTTOU, int_handler);
    signal(SIGIO, int_handler);
    signal(SIGXCPU, int_handler);
    signal(SIGXFSZ, int_handler);
    signal(SIGVTALRM, int_handler);
    signal(SIGPROF, int_handler);
    signal(SIGWINCH, int_handler);
}

BOOL is_trusted(char *domain)
{
    int i;

    for (i = 0; i < trusted_host_num; i++)
	if (prog_config.config_bits2 & SHOW_WILDCARD) {
	    if (strstr(domain, prog_config.trusted[i])) {
		return TRUE;
	    }
	} else {
	    if (!strcmp(domain, prog_config.trusted[i])) {
		return TRUE;
	    }
	}

    return FALSE;
}

BOOL is_rejected(char *domain)
{
    int i;

    for (i = 0; i < rejected_host_num; i++)
	if (prog_config.config_bits2 & SHOW_WILDCARD) {
	    if (strstr(domain, prog_config.rejected[i])) {
		return TRUE;
	    }
	} else {
	    if (!strcmp(domain, prog_config.rejected[i])) {
		return TRUE;
	    }
	}

    return FALSE;
}

int is_fake(char *user)
{
    int i;

    for (i = 0; i < fakeuser_num; i++)
	if (!strcmp(user, prog_config.fusers[i].user))
	    return i + 1;

    return 0;
}

int is_searchable(char *user)
{
    int i;

    for (i = 0; i < fakeuser_num; i++)
	if (prog_config.fusers[i].searchable)
	    return TRUE;

    return FALSE;
}

BOOL search_illegal(char *str)
{
    int i;

    if (str != NULL)
	for (i=0; i<(strlen(str)); i++)
	    if (!isalpha(str[i]) && !isdigit(str[i]) && (str[i] != '.') &&
		(str[i] != '_') && (str[i] != '-') && (str[i] != '`') &&
		(str[i] != '\"'))
		return TRUE;

    return FALSE;
}

void call_userscript(char *user, char *realuser)
{
    int i;
    BOOL legal = FALSE;

    i = is_fake(realuser);

    if (is_searchable(realuser)) {
	char *temp, *option1, *option2, *option3, *option4, *program, *p;

	temp = (char *) malloc(40);
	option1 = (char *) malloc(40);
	option2 = (char *) malloc(40);
	option3 = (char *) malloc(40);
	option4 = (char *) malloc(40);
	program = (char *) malloc(160);

	temp = ((p = strsep(&user, ".")) && *p) ? strdup(p) : NULL;

	option1 = ((p = strsep(&user, ".")) && *p) ? strdup(p) : NULL;

	if (option1 != NULL)
	    if (!search_illegal(option1))
		legal = TRUE;
	    else
		legal = FALSE;
	else
	    legal = TRUE;

	option2 = ((p = strsep(&user, ".")) && *p) ? strdup(p) : NULL;

	if ((legal) && (option2 != NULL))
	    if (!search_illegal(option2))
		legal = TRUE;
	    else
		legal = FALSE;

	option3 = ((p = strsep(&user, ".")) && *p) ? strdup(p) : NULL;

	if ((legal) && (option3 != NULL))
	    if (!search_illegal(option3))
		legal = TRUE;
	    else
		legal = FALSE;

	option4 = ((p = strsep(&user, ".")) && *p) ? strdup(p) : NULL;

	if ((legal) && (option4 != NULL))
	    if (!search_illegal(option4))
		legal = TRUE;
	    else
		legal = FALSE;

	if (legal) {
	    sprintf(program, "%s \"%s\" \"%s\" \"%s\" \"%s\"", 
		prog_config.fusers[i - 1].script,
		(option1 != NULL) ? option1 : "",
		(option2 != NULL) ? option2 : "",
		(option3 != NULL) ? option3 : "",
		(option4 != NULL) ? option4 : "");

	    system(program);
	} else {
	    printf("Illegal username entered: %s\n", realuser);
	    syslog(LOG_WARNING, "Illegal finger.  Options:");
	    syslog(LOG_WARNING, "OPT1: %s", option1);
	    syslog(LOG_WARNING, "OPT2: %s", option2);
	    syslog(LOG_WARNING, "OPT3: %s", option3);
	    syslog(LOG_WARNING, "OPT4: %s", option4);
	    fflush(stdout);
	}

	free(temp);
	free(option1);
	free(option2);
	free(option3);
	free(option4);
	free(program);
    } else {
	system(prog_config.fusers[i - 1].script);
    }
}

char *get_localhost(void)
{
    char *hostname = NULL, *domainname = NULL, *return_ptr = NULL;

    hostname = (char *) malloc(80);
    domainname = (char *) malloc(80);
    return_ptr = (char *) malloc(80);

    gethostname(hostname, (size_t) 80);
    getdomainname(domainname, (size_t) 80);

    sprintf(return_ptr, "%s.%s", hostname, domainname);
    return(return_ptr);
}

void display_file(char *disp_file)
{
    FILE *file;
    char buf[128];
    int bs;

    bs = sizeof(buf);
    strcpy(buf, disp_file);
    if (!(file = fopen(buf, "r"))) {
#ifdef	SYSLOG
	syslog(LOG_ERR, "%s: %s Not readable or non-existent!",
		disp_file, strerror(errno));
#endif
	printf("File: %s not readable/non-existent", prog_config.no_name_banner_file);
	exit(PROGRAM_SYSLOG);
    } else {
	while(fgets(buf, bs, file))
	    fputs(buf, stdout);
    }
    fclose(file);
}

BOOL no_finger(char *username)
{
    struct passwd *pw;
    char *use_file = NULL;
    FILE *file;

    if (strlen(username) > 0) {
	pw = (struct passwd *) getpwnam(username);

	if (pw == NULL) {
#ifdef	DEBUG
	    printf("Sorry, no such user exists.\n");
#endif
	    return FALSE;
	}

	if (errno == ENOMEM) {
	    printf("Internal error: No memory left to allocate passwd structure!\n");
#ifdef	SYSLOG
	    syslog(LOG_ERR, "Fatal - No memory left for passwd structure");
#endif
	    exit(PROGRAM_SYSLOG);
	}

	use_file = (char *) malloc(strlen(pw->pw_dir) +
				   strlen(prog_config.no_finger_file) + 1);
	sprintf(use_file, "%s/%s", pw->pw_dir, prog_config.no_finger_file);

	if ((file = fopen(use_file, "r")) == NULL) {
	    return FALSE;
	} else {
	    display_file(use_file);
	    return TRUE;
	}
    }

    return FALSE;
}

char *lowercase(const char *s)
{
    int i;
    char *t = NULL;

    t = (char *) malloc(strlen(s) + 1);

    if (t == NULL) {
#ifdef	SYSLOG
	syslog(LOG_ERR, "malloc error in lowercase");
#endif
	exit(PROGRAM_SYSLOG);
    }

    for (i = 0; i < strlen(s) + 1; i++) {
	t[i] = tolower(s[i]);
    }

#ifdef	DEBUG
    printf("%s\n",t);
#endif

    return(t);
}

void become_nobody(void)
{
    if (setgid(NOBODY_GID)) {
#ifdef	SYSLOG
	syslog(LOG_ERR, "Cannot change to GID %d", NOBODY_GID);
	syslog(LOG_ERR, "Reason: PERMISSION DENIED");
#endif
	exit(1);
    }

    if (setuid(NOBODY_UID)) {
#ifdef	SYSLOG
	syslog(LOG_ERR, "Cannot change to UID %d", NOBODY_UID);
	syslog(LOG_ERR, "Reason: PERMISSION DENIED");
#endif
	exit(1);
    }
}

void show_version_information(void)
{
    printf("\nThis site is running the Configurable Finger Daemon version\n");
    printf("%s, available from Ken Hollis (khollis@bitgate.chatlink.com)\n", FINGER_VERSION);
    printf("on either sunsite.unc.edu, or bitgate.chatlink.com.\n\n");
    printf("For more information, or if you have any questions about the\n");
    printf("software daemon, please write to Ken Hollis at the above address\n");
    printf("or write to your system administrator.\n\n");
}

BOOL check_for_user(char *username)
{
    struct passwd *pw;

    if (strlen(username) > 0) {
	pw = (struct passwd *) getpwnam(username);

	if (pw == NULL)
	    return FALSE;
	else
	    return TRUE;
    } else
	return FALSE;
}

void check_illegal(char *username)
{
    BOOL illegal = search_illegal(username);

    if (illegal) {
	syslog(LOG_ERR, "Illegal username: %s", username);
	closelog();
	exit(1);
    }
}
