/************************************************/
/* This checks inetd.conf for baddies...	*/
/* This function checks inetd.conf or xinetd.d  */
/* for unwanted services. It outputs the list   */
/* of all servies running (all are unwanted, 	*/
/* right?) to the outfile.			*/
/* If inetd.conf exists or if xinetd.d is 	*/
/* present it also returns a 1 to main to tell  */
/* main to run a check of /etc/hosts.deny.	*/
/*						*/
/* See lsatmain.c for more details...		*/
/************************************************/

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

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

    char *ptr;
    char line[128];        /* temp line for reading   */
    char tempstring[128];    /* tempstring for inet     */
    char xinetdstring[50][128]; /* tempstring for xinetd entries */
    char myno[1][3]={"no"}; /* heh, no */
    int inetd  = 0;		/* do we use inetd?        */
    int xinetd = 0;		/* do we use xinetd? 	   */
    int linecount, field;   /* some vars...		   */
    int emptyflag=1;	/* is inet an empty file?  */
    int fileval=0;		/* return val   */
    FILE *infile;  		/* tempfile file pointer   */
    FILE *tmpfile;              /* file ptr for tempfile   */

    const char * tmp_file = "/tmp/lsat2.lsat"; /* temp file */

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


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

    // really check if /etc/inetd.conf or /etc/xinetd.conf exist
    // instead of guessing

    if (distribution != 3)
    // we are not on Solaris...
    {
        // check for /etc/inetd.conf
        if (system("test -e /etc/inetd.conf")==0)
        {
	    inetd=1;
        }
    
        // check for /etc/xinetd.d/
        if (system("test -e /etc/xinetd.d")==0)
        {
	    xinetd=1;
        }
    }
   
    if (distribution == 3)
    // we are on Solaris, test -e does not work under sh
    {
        // check for /etc/inetd.conf
        if (system("test -f /etc/inetd.conf")==0)
	{
	     inetd=1;
        }

        // check for /etc/xinetd.d/
        if (system("test -f /etc/xinetd.d")==0)
        {
	    xinetd=1;
 	}
    }


    // now we start to check
    if (inetd == 1)
    {
        if (verbose > 0)
        {
            printf(" Checking entries in /etc/inetd.conf\n");
        }

        /* note: grep returns
        *  0 on match
        *  1 on no match
        *  2 on system/file/read/other failure
        *  HOWEVER, -v inverts the sense of 0,1.
        */

        header = "inetd.conf entries:\n";
        tempfile = "/tmp/lsat1.lsat";

        /* use different shellcodes as linux grep is */
	/* mo-betta than standard Solaris grep  :)   */
        if (distribution != 3)
	{
	    /* find all lines that do not _start_ with a "#" */
	    shellcode = "grep -Ev ^\\[:space:\\]*\\# /etc/inetd.conf >/tmp/lsat1.lsat";
	}
        if (distribution == 3)
        {
	    /* find all lines that do not _start_ with a "#" */
	    /* Note, either I suck with grep, or Solaris grep*/
            /* is drain bramaged... have to just check for # */

            shellcode = "grep -v \\# /etc/inetd.conf >/tmp/lsat1.lsat";
        }
        if ((dostuff(tempfile, 0, shellcode, header, html)) < 0)
        {
	    /* something went wrong */
	    perror(" Creation of list failed.");
	    return(-1);
        }

        /* now instead of reading the whole file and 	*/
        /* say looking for baddie servies, I consider	*/
        /* that all in there are evil. Merely tell the  */
        /* user what we have found that is open.        */
        /* perhaps also tell them to close them. :)     */
        /* note that if the file is empty, thats great. */
        /* it _should_ mean that they have commented    */
        /* out everything in /etc/inetd.conf		*/

        infile = fopen("/tmp/lsat1.lsat", "r");
        if (infile == NULL)
        {
            perror(" Error opening tmp file.\n");
            return(-1);
        }

        /* create another tmp file for entries... */
        if ((fileval = open(tmp_file, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0)
	{
            perror(" Could not create temporary file...\n");
            perror(" Possible link attack while creating/opening file!\n");
            exit(-1);
        }
        /* open it for append */
        tmpfile = fopen(tmp_file, "a");
        if (tmpfile == NULL)
	{
	    perror(" Error opening tmp file.\n");
	    return(-1);
        }

	/* init linecount */
	linecount = 0;
	/* init emptyflag */
	emptyflag = 0;

        while (fgets(line, sizeof(line), infile) != NULL)
        {
            field=0;
            ptr = strtok(line, ", \"\n");
            if (ptr == NULL)
            {
                if (linecount == 0)
                {
                    /* 1st line was empty, must have been */
                    /* an empty file. This _should_ be a  */
                    /* "good thing"....		      */
                    /* set flag, then break.	      */
                    emptyflag = 1;
                }
            }
            linecount++;
            while (ptr != NULL)
            {
                if (sscanf(ptr, "%127s", tempstring) < 1)
                {
                    perror(" sscanf bit the dust");
                    perror(" Dust biting was in checkinetd.\n");
                    return(-1);
                }
                /* note: we just need the 1st field... */
                if (field == 0)
                {
                    fprintf(tmpfile, "%s \n", tempstring);
                }
                ptr = strtok(NULL, ", \"\n");
                if (ptr == NULL)
                {
                    ;
                }
                field++;
            }
        } /* end while(fgets...) */

    	/* close files in use */
    	fclose(infile);
    	/* close the tmp file, do not rm it */
    	fclose(tmpfile);
    	/* rm tempfile since dostuff will be called */
    	/* with the new tmpfile we created	*/
    	remove(tempfile);


    	/* call dostuff to append the new tmpfile */
    	/* to the outfile.			*/
    	if (emptyflag == 1)
    	{
		/* no baddies in inetd.conf */
        	header = "No non-essential items found in inetd.conf. Good.\n";
    	}
    	if (emptyflag == 0)
	{
	        /* found some lines not commented out... */
            	header = "Please comment out all of these from inetd.conf.\n";
	}
    	if ((dostuff(tmp_file, filename, 0, header, html)) < 0)
	{
	    /* something went wrong */
	    perror(" Creation of list failed.");
	    return(-1);
	}
    } /* end of if(inetexists==1) */


    /* end of RedHat 5.x, 6.x check portion */
    /* note that in the above dostuff it should	*/
    /* have removed the tempfile, so we will    */
    /* reuse it below for xinetd.d entries...   */


    /* if we are on RedHat 7.x we use xinetd.d/ files */
    if (xinetd == 1)
    {

        if (verbose > 0)
        {
            printf(" Checking entries in /etc/xinetd.d/\n");
        }

        /* init the linecount here   */
        linecount = 0;


        /* assume RedHat 7.x box */
        /* read through the files in /etc/xinetd.c and	*/
        /* check for ones that are not disabled.	*/
        tempfile = "/tmp/lsat3.lsat";
        shellcode = "grep disable /etc/xinetd.d/* >/tmp/lsat3.lsat";
        header = "xinetd.d entries:\n";
        if ((dostuff(tempfile, 0, shellcode, header, html)) < 0)
        {
	    /* something went wrong */
	    perror(" Creation of list failed.");
	    return(-1);
	}


        /* create another tmp file for entries... */
        if ((fileval = open(tmp_file, O_RDWR | O_CREAT | O_EXCL, 0600)) < 0)
        {
            perror(" Could not create temporary file...\n");
            perror(" Possible link attack while creating/opening file!\n");
            exit(-1);
        }

        /* tmp file for entries from loop below */
        tmpfile = fopen(tmp_file, "a");
        if (tmpfile == NULL)
        {
            perror(" Error opening tmp file.");
            return(-1);
        }



        /* an entry should look like: 		*/
        /* /etc/xinetd.d/telnet: disable no 	*/
        /* so we will strtok on : and only take */
        /* the 1st element returned.		*/
 	
	/* open the file created w/dostuff	*/
	infile = fopen(tempfile, "r");
        if (infile == NULL)
        {
	     perror(" Error opening tempfile.");
             return(-1);
        }	

	/* init linecount */
	linecount = 0;
	/* init emptyflag */
	emptyflag = 1;

        while (fgets(line, sizeof(line), infile) != NULL)
        {
            field=0;
            ptr = strtok(line, ", :\n");
            linecount++;
            while (ptr != NULL)
            {
                if ((sscanf(ptr, "%127s", xinetdstring[field])) < 1)
                {
                    perror(" sscanf bit the dust");
                    perror(" Dust biting was in checkinetd.\n");
                    return(-1);
                }
                /* print out the line if it is  */
                /* the first field		*/
                if ((field == 2) && (linecount != 0))
                {
                    if ((strcmp(myno[0], xinetdstring[3])) == 0)
		    {
			/* if we get here, must have had a disable = no */
			emptyflag = 0;
                    	fprintf(tmpfile, "%s\t%s", xinetdstring[0], xinetdstring[3]);
                    }
                }
                field++;
		if (field>50)
		{
		    perror(" Error in checkinetd: Too much data.\n");
		    return(-1);
		}
                ptr = strtok(NULL, ", :\n");
                if (ptr == NULL)
                {
                    ;
                }
            } /* end while (ptr != NULL) */
        } /* end while (fgets...) */
        
 	/* close the tmp file, do not rm it */
	fclose(tmpfile);
        /* close the infile, rm it. */
        fclose(infile);
        remove(tempfile);

        /* print some footer information */
        if (emptyflag == 1)
        {
            /* there were no disabled = no  lines */
            header = "No enabled xinetd.d services. Good.\n";
        }
        if (emptyflag == 0)
        {
            /* there are services in xinetd.d open */
            header = "It is strongly recommended that you set\ndisable = yes in the files in /etc/xinetd.d/\n";
        }
        if ((dostuff(tmp_file, filename, 0, header, html)) < 0)
	{
	    /* something went wrong */
	    perror(" Creation of list failed.");
	    return(-1);
	}
        /* clean up... */
    } /* end of RedHat 7.x check portion */

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

    /* instead of just returning 0 here */
    /* we return (inetd or xinetd)... 	    */
    /* 0 for no existance, 1 if either exists  */
    return(inetd || xinetd);
}
