/*
 * CFINGERD
 * Username search routines
 *
 * 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 1, 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.
 */

#include "cfingerd.h"
#include "proto.h"
#include "privs.h"

typedef struct {
    char username[80];
    char realname[80];
} SEARCHLIST;

/*
 * SHOW_SEARCH
 *
 * This routine searches for the specified uname, or any matches in the
 * specified uname, and lists the matches that were made.
 */
#define MAX_SEARCHES	500
void show_search(char *uname)
{
    char *searchname=NULL;
    int num_searches = 0, fnd = 0;
    SEARCHLIST searches[MAX_SEARCHES];
    FILE *file;
    char *cp;
    char *xp, y;

    show_top();

    cp=uname;
    if ((xp = index (cp, '.')) != NULL) {
	++xp;
	if ((searchname = (char *)malloc (strlen(xp)+1)) != NULL) {
	    memset (searchname, 0, strlen(xp)+1);
	    strcpy (searchname, xp);
	}
    }

    if (searchname == NULL) {
	printf("\n                    You must supply a name to search for!\n");
	SEND_RAW_RETURN;
	show_bottom();
	exit(PROGRAM_OKAY);
    }

    for (cp=searchname,xp=searchname,y=0;*cp;cp++) {
	if (y != *cp)
	    *(xp++) = *cp;
	y = *cp;
    }
    *xp = '\0';
	
    if (strlen((char *) searchname) == 0) {
	printf("\n                    You must supply a name to search for!\n");
	SEND_RAW_RETURN;
	show_bottom();
	free (searchname);
	exit(PROGRAM_OKAY);
    }

    if ((searchname[0] == '*') && searchname[1] == '\0') {
	printf("\n                    You must supply a name to search for!\n");
	SEND_RAW_RETURN;
	show_bottom();
	log(LOG_USER, "Security breach: finger * from %s", ident_user);
	syslog(LOG_WARNING, "Security breach: finger * from %s", ident_user);
	free (searchname);
	exit(PROGRAM_OKAY);
    }

    for (cp=searchname; *cp; cp++)
      if (isupper(*cp))
	*cp = tolower(*cp);

    log(LOG_USER, "Search: ", searchname);

    NOBODY_PRIVS;

    file = fopen("/etc/passwd", "r");
    if (file) {
	while(!feof(file)) {
	    /* FIXME: Proper handling for passwd lines */
	    char crap[80], un[80], rn[300], crappp[300], homedir[80], uid[10], gid[10];
	    char Un[80], Rn[80];
	    char fn[100];
	    int Uid, Gid;

	    fnd = FALSE;

	    memset(crap, 0, 80);
	    memset(un, 0, 80);
	    memset(rn, 0, 80);
	    memset(crappp, 0, 80);

	    fgets(crappp, 300, file);

	    sscanf(crappp, "%[^:\r\n]:\r\n%[^:\r\n]:\r\n%[^:\r\n]:\r\n%[^:\r\n]:\r\n%[^:\r\n]:\r\n%[^:\r\n]:\r\n%[^\r\n]\r\n",
		un, crap, uid, gid, rn, homedir, crap);

	    snprintf (Un, sizeof(Un), "%s", un);
	    snprintf (Rn, sizeof(Rn), "%s", rn);
	    Uid = atoi(uid);
	    Gid = atoi(gid);

	    for (cp=rn; *cp; cp++)
		if (isupper(*cp))
		    *cp = tolower (*cp);

	    for (cp=un; *cp; cp++)
		if (isupper(*cp))
		    *cp = tolower (*cp);

	    /* Check for trusted/untrusted hosts here */
	    /* For the sake of gcos password fields */
	    if ((cp = strchr(Rn,',')))
		*cp = '\0';

	    if (strstr((char *) rn, (char *) searchname))
		fnd = TRUE;
	    else if (wildmat((char *) rn, (char *) searchname))
		fnd = TRUE;
	    else if (wildmat((char *) un, (char *) searchname))
		fnd = TRUE;
	    else {
		for (cp=Rn; *cp; cp++)
		    if (isupper(*cp))
			*cp = tolower (*cp);
		if (wildmat((char *) Rn, (char *) searchname))
		    fnd = TRUE;
	    }

	    if (fnd) {
		if ((prog_config.no_finger_file != NULL) 
		    && (strlen(homedir)+strlen(prog_config.no_finger_file)+1 < sizeof(fn)))
		    sprintf(fn, "%s/%s", homedir, prog_config.no_finger_file);
		else
		    if (strlen(homedir)+10 < sizeof(fn))
			sprintf(fn, "%s/.nofinger", homedir);
		    else
			fn[0] = '\0';


		USER_PRIVS(Uid, Gid);
		if (exist(fn)) fnd = FALSE;
		NOBODY_PRIVS;

	    }
		
	    if (fnd && (num_searches < MAX_SEARCHES)) {
		memset(searches[num_searches].realname, 0, 80);
		memset(searches[num_searches].username, 0, 80);

		strncpy(searches[num_searches].realname, Rn, sizeof(searches[num_searches].realname));
		strncpy(searches[num_searches].username, Un, sizeof(searches[num_searches].username));
		num_searches++;
	    }
	}
    } else {
	printf("\n                   Could not open the local password file!\n\n");
	show_bottom();
	free (searchname);
	exit(PROGRAM_OKAY);
    }

    if (num_searches > 0) {
	int i;

	printf("\n %d match%sfound regarding your search criteria:\n\n",
	    num_searches, (num_searches > 1) ? "es " : " ");
	printf(" Username:      Realname:\n");
	printf(" -------------- --------------------------------------------------------------\n");
	for(i = 0; i < num_searches; i++) {
	    printf(" %-14.14s %-61.61s\n", searches[i].username,
		(searches[i].realname[0] != 0) ?
			searches[i].realname : "No realname field available");
	}

	fflush(stdout);
    } else {
	printf("\n               No matches found regarding your search criteria.\n");
	fflush(stdout);
    }

    SEND_RAW_RETURN;

    show_bottom();

    free (searchname);
}

/*
 * Local variables:
 *  c-indent-level: 4
 *  c-basic-offset: 4
 *  tab-width: 8
 * End:
 */
