/****************************************/
/* This is the chekftpusers module for  */
/* the lsat program. It check the 	*/
/* /etc/ftpusers file and sees what 	*/
/* entries are NOT there that are in	*/
/* /etc/passwd.				*/
/*					*/
/* see lsatmain.c for more details	*/
/****************************************/

#include "lsatheader.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>

int checkftpusers(filename, verbose)
const char *const filename;
int verbose;
{

    char *passptr;		/* ptr to passwd line   */
    char *ftpptr;		/* ptr to ftpusers line */
    /* note we use awk to get only the first entry in */
    /* the passwd list... we ass|u|me that a username */
    /* will be < 40 chars. :O   => line[40]	          */
    char line[40];	/* array for a line	*/
    char temparray[60][40]; /*temparray. */
    char tempstring[60][40];	/* string to hold ftpusername */
    int i=0;		/* counter variable	*/
    int j=0;		/* counter variable  */
    int k=0;		/* counter variable  */
    int inlist=0;		/* flag for strcmp checks */
    int fileval; 		/* return val */
    int linecount=0;	/* line counter */


    FILE *outfile;		/* output file pointer 	*/
    FILE *passfile;		/* file pointer to templist file */
    FILE *ftpfile;		/* file pointer to ftpusers file */


    /* init temparray */
    for (i=0; i<60; i++)
    {
        for (j=0; j<40; j++)
        {
            temparray[i][j]=0;
        }
    }


    /* "you may ask yourself, how do I work this?" */
    /*				Talking Heads  */
    /* This program will read the /etc/passwd file */
    /* and store the username in an array...       */
    /* It will then read the /etc/ftpusers file    */
    /* and see what entries are NOT in ftpusers.   */


    if (verbose == 1)
    {
        printf("Starting checkftpusers module...\n");
    }


    outfile=fopen(filename, "a");
    if (outfile == NULL)
    {
        perror("Can't open outfile!\n");
        perror("Check perms or something...\n");
        perror("Error was in module: checkftpusers.\n");
        return(-1);
    }

    /* print some header info to the outfile...  */
    fprintf(outfile, "\n");
    fprintf(outfile, "****************************************\n");
    fprintf(outfile, "Checking /etc/ftpusers:\n");
    fprintf(outfile, "\n");

    if (verbose == 1)
    {
        printf("Checking ftpusres file...\n");
    }

    /* check that /etc/ftpusers exists first */
    if ((system("cat /etc/ftpusers 1>/dev/null 2>/dev/null >/dev/null")) != 0)
    {
        /* ftpusers does not exist.             */
        /* this _could_ be ok for the user      */
        /* give a msg and leave the area.       */
        fprintf(outfile, "/etc/ftpusers does not exist.\n");
        fprintf(outfile, "This could be ok if you are not\n");
        fprintf(outfile, "running ftp or if your ftp daemon\n");
        fprintf(outfile, "does not use /etc/ftpuses.\n");
        fprintf(outfile, "Please triple check your configuration\n");
        fprintf(outfile, "and ensure you do not need /etc/ftpusers.\n\n");
        fprintf(outfile, "*****************************************\n");

        /* leave */
        return(0);
    }

    /* create a temp file for storage */
    if ((fileval = open("/tmp/sedlist.txt", O_RDWR | O_CREAT, 0600)) < 0)
    {
        perror("Could not make file w/perms 0600...\n");
        perror("Possible link attack while creating/opening file!\n");
        perror("Bailing in checkftpusers...\n");
        exit(-1);
    }

    /* ok, lets make one pass through the passwd   	*/
    /* note here we only pull the 1st field, which  */
    /* is the "account" name in /etc/passwd.    	*/

    if (system("cat /etc/passwd |awk -F\":\" 'length($1) > 0 {print $1}' 1>/dev/null 2>/dev/null >/tmp/sedlist.txt") < 0)
    {
        perror("Can't open /etc/passwd??\n");
        perror("I should be able to read this and\n");
        perror("it may be that you are not using shadow\n");
        perror("passwords. Check to see if you are.\n");
        perror("Giving up in checkftpusers...\n");
        return(-1);
    }

    /* open the newly created file */
    passfile=fopen("/tmp/sedlist.txt", "r");
    if (passfile == NULL)
    {
        perror("Can't open templist...\n");
        perror("Strange, we just created that file...\n");
        perror("Giving up in checkftpusers...\n");
        return(-1);
    }


    /* Note: IIRC, strtok can not be nested if you */
    /* are going to take another token on each one */
    /* i.e. in checkrpms.c it works since we only  */
    /* strtok once on the outside loop since we 	  */
    /* are guarenteed there is only one line in the*/
    /* file since that is how we created it. That  */
    /* is not the case here....			*/

    /* we therefore only grab one filed from the  	*/
    /* passwd file at a time and print that out.		*/
    /* here we are checking accounts on the system  */

    /* reset counter */
    i = 0;
    while (fgets(line, sizeof(line), passfile) != NULL)
    {
        passptr = strtok(line, ", \n");
        /* if not while. we guarentee not more than */
        /* one entry per line with the cat - awk    */
        if (passptr != NULL)
        {
            if (sscanf(passptr, "%s", temparray[i]) < 1)
            {
                perror("sscanf failed.\n");
                perror("Failure was in module: checkftpusers.\n");
                return(-1);
            }
            passptr = strtok(NULL, ", \n");
            if (passptr == NULL)
            {
                ;
            }
        } /* end if (passptr != NULL) */
        /* inc the counter */
        i++;
    } /* end while (fgets...) */


    /* close the passfile */
    fclose(passfile);
    /* rm the input file */
    if (system("rm -f /tmp/sedlist.txt") < 0)
    {
        perror("Can't rm tempfile??\n");
        perror("Strange, we made the file...\n");
        perror("Giving up in checkftpusers...\n");
        return(-1);
    }


    /* ok, we have all (we hope) entries from */
    /* /etc/passwd. Now read in /etc/ftpusers */
    /* and compare... I think just one at a   */
    /* time, 'non?				  */


    /* open /etc/ftpusers for read-only */
    ftpfile = fopen("/etc/ftpusers", "r");
    if (ftpfile == NULL)
    {
        perror("Can't open ftpusers!\n");
        perror("Check perms or checki f file exists.\n");
        perror("Recall this file should exist. :)\n");
        perror("Giving up in checkftpusers...\n");
        return(-1);
    }

    /* in the temparray. we just need   */
    /* to compare that to the entries.. */

    /* reset counter */
    j = 0;
    /* get a line from the ftpusers file */
    while (fgets(line, sizeof(line), ftpfile) != NULL)
    {
        ftpptr = strtok(line, ", \n");
        /* if not while. ftpusers = 1 entry per line */
        if (ftpptr != NULL)
        {
            if (sscanf(ftpptr, "%s", tempstring[linecount]) < 1)
            {
                perror("sscanf failed.\n");
                perror("Failure was in module: checkftpusers.\n");
                return(-1);
            }
            ftpptr = strtok(NULL, ", \n");
            if (ftpptr == NULL)
            {
                ;
            }
        } /* end if (ftpptr != NULL) */
        /* inc the linec ounter */
        linecount++;
    } /* end while (fgets...) */


    /* ok, now compare an entry in the userlist */
    /* we have against the entries in ftpusers  */
    for (j = 0; j < i; j++)
    {
        for (k=0; k < linecount; k++)
        {
            if ((strcmp(temparray[j], tempstring[k])) == 0)
            {
                /* match */
                /* set flag that it is in list */
                inlist = 1;

            }
        }
        /* flag was set on run? */
        /* no? then that entry was not in ftpusers list */
        if (inlist == 0)
        {
            fprintf(outfile, "%s\n", temparray[j]);
        }
        /* reset flag */
        inlist = 0;
    }


    /* print some footer information */
    fprintf(outfile, "\nAbove accounts are NOT in /etc/ftpusers.\n");
    fprintf(outfile, "Ensure that above accounts are in /etc/ftpusers\n");
    fprintf(outfile, "or that they _really_ do not need to be restricted.\n");
    fprintf(outfile, "****************************************\n");

    /* clean up... */
    fclose(outfile);
    fclose(ftpfile);

    if (verbose == 1)
    {
        printf("Finished in checkftpusers module.\n");
    }
    return(0);
}
