/****************************************/
/* This is the checkpasswd module for   */
/* the lsatmain.c program. It checks    */
/* the /etc/passwd file for entries...  */
/* makes sure only root is setuid 0     */
/* checks for accounts that should be   */
/* terminated.                          */
/*					*/
/* see lsatmain.c for more details	*/
/****************************************/

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

int checkpasswd(filename, verbose, html)
const char *const filename;
int verbose;
int html;
{

    char *passptr;		/* ptr to passwd file   */
    /* 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[1000][40]; /*temparray. */
    int i=0;				/* counter variable	*/
    int j=0;				/* counter variable  */
    int theuid;
    int field;			/* field counter	*/
    int fileval; 		/* return val */
    FILE *tmpfile;		/* temp file pointer */
    const char * tmp_file = "/tmp/lsat2.lsat"; /* temp file for storage */

    const char * tempfile =NULL;
    const char * shellcode=NULL;
    const char * header   =NULL;

    /* NOT a comprehensive list yet.	*/
    /* just making sure this works...	*/
    char acctlist[13][10] = {"cyrus", "lp", "uucp", "nuucp", "smtp", "listen", "man", "news", "noacces", "nobody4", "nut", "sync", "vpopmail"};
    /* num of entries in above list */
    int acctlistnum = 13;

    FILE *passfile;		/* file pointer to templist file */

    if (verbose >= 0)
    {
        printf(" Running checkpasswd module...\n");
    }

    if (verbose > 0)
    {
        printf(" Checking passwd file...\n");
    }


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

    shellcode = "cat /etc/passwd |awk -F\":\" 'length($1) > 0 {print $1}' 1>/dev/null 2>/dev/null >/tmp/lsat1.lsat";
    tempfile = "/tmp/lsat1.lsat";
    if ((dostuff(tempfile, 0, shellcode, 0, html)) < 0)
    {
        perror(" Creation of list failed.");
        return(-1);
    }

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

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

    /* open the temp file for write */
    tmpfile = fopen(tmp_file, "a");
    if (tmpfile == NULL)
    {
	perror(" Can't open file we just made?");
        perror(" Error was in checkpasswd.");
        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  */

    if (verbose > 0)
    {
	printf(" Parsing passwd entries.\n");
    }
    while (fgets(line, sizeof(line), passfile) != NULL)
    {
        field = 0;
        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, "%39s", temparray[i]) < 1)
            {
                perror(" sscanf failed.\n");
                perror(" Failure was in module: checkpasswd.\n");
                return(-1);
            }
            i++;
	    if (i>1000)
	    {
		perror("Error in checkpasswd: Too much data.");
		return(-1);
	    }
            passptr = strtok(NULL, ", \n");
            if (passptr == NULL)
            {
                ;
            }
        } /* end while (passptr != NULL) */
    } /* end while (fgets...) */

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

    for (i = 0; i < 1000; i++)
    {
        for (j = 0; j < acctlistnum; j++)
        {
            if ((strcmp(temparray[i], acctlist[j])) == 0)
            {
                /* match */
                fprintf(tmpfile, "%s\n", temparray[i]);
            }
        }
    }

    /* close input file */
    fclose(passfile);
    /* rm the tempfile, dostuff will use other one */
    remove(tempfile);
    /* close the tmpfile */
    fclose(tmpfile);
    /* note dostuff below will rm tmpfile */

    header = "Please consider removing these system accounts.\nCheck to see if you need them for your system applications before removing.\nAlso, consult the securitylinks.txt file for more information.\n";
    if ((dostuff(tmp_file, filename, 0, header, html)) < 0)
    {
	/* something went wrong */
	perror(" Write to outfile failed.");
	return(-1);
    }


    /* check UID filed of passwd file... */
    if (verbose > 0)
    {
        printf(" Checking UIDs in passwd file.\n");
    }

    shellcode = "cat /etc/passwd |awk -F\":\" 'length($3) > 0 {print $3}' 1>/dev/null 2>/dev/null >/tmp/lsat1.lsat";
    tempfile = "/tmp/lsat1.lsat";
    if ((dostuff(tempfile, 0, shellcode, 0, html)) < 0)
    {
 	/* something went wrong */
	perror(" Creation of list failed.");
	return(-1);
    }

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

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

    /* open the tmp file for write */
    tmpfile = fopen(tmp_file, "a");
    if (tmpfile == NULL)
    {
        perror(" Can't open file we just made?");
        perror(" Error was in checkpasswd.");
        return(-1);
    }

    /* in here we grab one line at a time.		*/
    /* recall each line is a number. We need 	*/
    /* only make sure that all lines (!= 1)	*/
    /* are not == 0 (UID root)...					*/
    i = 0; /* reset counter, use it for line #*/
    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, "%d", &theuid) < 1)
            {
                perror(" sscanf failed.\n");
                perror(" Error was in module: checkpasswd.\n");
                return(-1);
            }
            if (i != 0)
            {
                if (theuid == 0)
                {
                    /* Note here: temparray should still be 	*/
                    /* filled with the system accounts.			*/
                    /* we printed out the UID number in the	*/
                    /* same order, so we should be ok... :)	*/
                    fprintf(tmpfile, "%s has UID 0!\n", temparray[i]);
                    fprintf(tmpfile, "Only root should have UID=0\n");
                }
            }
            passptr = strtok(NULL, ", \n");
            if (passptr == NULL)
            {
                ;
            }
        }
        /* inc the line count */
        i++;
    }

    /* clean up... */
    fclose(passfile);
    /* rm passfile since dostuff will be working with */
    /* the lsat2.lsat file */
    remove(tempfile);
    /* close the second temp file */
    fclose(tmpfile);

    header = "Remove any non root account with SUID=0";
    if ((dostuff(tmp_file, filename, 0, header, html)) < 0)
    {
	/* something went wrong */
	perror(" Write to outfile failed.");
	return(-1);
    }

    if (verbose > 0)
    {
        printf(" Finished in checkpasswd module.\n");
    }
    return(0);
}
