/************************************************/
/* 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(release, kernel, filename, verbose)
char release[50];
char kernel[50];
const char *const filename;
int verbose;
{

    char *ptr;
    char line[128];        /* temp line for reading   */
    char tempstring[128];    /* tempstring for inet     */
    char Sunos[4]="Sun";    /* for comparison	   */
    char Linux[4]="Lin";    /* for comparison	   */
    char *sunptr=Sunos;     /* char pointer		   */
    char *lptr=Linux;	/* char pointer 	   */
    int inetd = 0;		/* do we use inetd?        */
    int xinetd = 0;		/* do we use xinetd? 	   */
    int linecount, field;   /* some vars...		   */
    int emptyflag=0;	/* is inet an empty file?  */
    int inetexists=0;	/* does inet exist?	   */
    int fileval=0;		/* return val   */
    FILE *infile;  		/* tempfile file pointer   */
    FILE *outfile; 		/* output file pointer     */
    FILE *inetfile;    		/* file pointer for checks */

    if (verbose == 1)
    {
        printf("In checkinetd module...\n");
    }


    /* open the output file for append. */
    outfile = fopen(filename, "a");
    if (outfile == NULL)
    {
        perror("Error opening outfile.\n");
        perror("Check perms perhaps?\n");
        return(-1);
    }

    /* ok, we also check here if we are on a Solaris */
    /* machine. It (AFAIK) still uses inetd.conf up  */
    /* to SunOS 5.8...				 */

    if (strstr(release, sunptr) != NULL)
    {
        inetd = 1;
    }
    /* check the release we are on */
    /* 4/4/2002 See changes in lsatmain.c on this... */
    /* assume kern 2.2.x/2.0.x uses /etc/inetd.conf  */
    if ((kernel[2]=='2') || (kernel[2]=='0'))
    {
        if (strstr(release, lptr) != NULL)
        {
            inetd = 1;
        }
    }
    else
    {
        /* we _should_ be on an xinetd type system */
        xinetd = 1;
    }


    if (inetd == 1) /* we are on a /etc/inetd.conf based system */
    {

        /* check to see if inetd.conf exists at all    */
        if ((inetfile=fopen("/etc/inetd.conf", "r"))!=NULL)
        {
            inetexists=1;
        }
        else
        {
            /* it does not exist */
            inetexists=0;
        }
        fclose(inetfile);
        if (inetexists == 1)
        {

            if (verbose == 1)
            {
                printf("Checking entries in /etc/inetd.conf\n");
            }


            /* print some header info... */
            fprintf(outfile, "****************************************\n");
            fprintf(outfile, "inetd.conf items not commented out:\n\n");

            /* create a temp file for storage */
	    if ((fileval = open("/tmp/greplist.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 checkinetd...\n");
        	exit(-1);
    	    }
            /* 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.
            */
            if (system("grep -v \\# /etc/inetd.conf >> /tmp/greplist.txt") == 2)
            {
                perror("Problem executing grep in checkinetd\n");
                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/greplist.txt", "r");
            if (infile == NULL)
            {
                perror("Error opening tmp file.\n");
                return(-1);
            }
            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, "%s", &tempstring) < 1)
                    {
                        perror("sccanf bit the dust");
                        perror("Dust biting was in checkinetd.\n");
                        return(-1);
                    }
                    /* note: we just need the 1st field... */
                    if (field == 0)
                    {
                        fprintf(outfile, "%s \n", tempstring);
                    }
                    ptr = strtok(NULL, ", \"\n");
                    if (ptr == NULL)
                    {
                        ;
                    }
                    field++;
                }
            } /* end while(fgets...) */
        } /* end if(inetexists == 1) */
        else
        {
            /* inetd.conf did not exist */
            inetexists=0;
        }
        /* close files in use, but not outfile  */
        fclose(infile);
        if ((system("rm -f /tmp/greplist.txt")) < 0)
        {
            /* rhut-rho... problems.. */
            perror("Can't rm tempfile...\n");
            perror("Permissions problem??\n");
            return(-1);
        }

        /* print some footer information */
        if (emptyflag == 1)
        {
            /* there were no non-commented inetd.conf lines */
            fprintf(outfile, "\nNo non-essential items found in inetd.conf. Good.\n");
            fprintf(outfile, "****************************************\n");
        }
        if (emptyflag == 0)
        {
            /* there were services in inetd.conf left open */
            fprintf(outfile, "\nIt is strongly recommended that you comment out\n");
            fprintf(outfile, "all of the above from your /etc/inetd.conf file.\n");
            fprintf(outfile, "At the very least run tcpwrappers and edit your\n");
            fprintf(outfile, "/etc/hosts.allow and /etc/hosts.deny files.\n");
            fprintf(outfile, "\n");
            fprintf(outfile, "****************************************\n");
        }
    } /* end of RedHat 5.x, 6.x check portion */

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

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

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

        /* Note that the outfile should already be open */
        /* print some header info... */
        fprintf(outfile, "****************************************\n");
        fprintf(outfile, "xinetd.d items not disabled:\n\n");

        /* create a temp file for storage */
        if ((fileval = open("/tmp/xinetd.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 checkinetd...\n");
            exit(-1);
        }


        /* assume RedHat 7.x box */
        /* read through the files in /etc/xinetd.c and	*/
        /* check for ones that are not disabled.	*/
        if (system("grep disable /etc/xinetd.d/* |grep no >> /tmp/xinetd.txt") < 0)
        {
            perror("Problem executing ls??\n");
            perror("Error was in module: checkinet.\n");
            return(-1);
        }

        /* open the file we just created */
        infile = fopen("/tmp/xinetd.txt", "r");
        if (infile == NULL)
        {
            perror("Error opening tmp file.\n");
            perror("Check perms or something...\n");
            perror("Error was in checkinet.\n");
            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.		*/
        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, "%s", &tempstring)) < 1)
                {
                    perror("sccanf bit the dust");
                    perror("Dust biting was in checkinetd.\n");
                    return(-1);
                }
                /* print out the line if it is  */
                /* the first field		*/
                if ((field == 0) && (linecount != 0))
                {
                    fprintf(outfile, "%s\n", tempstring);
                }
                field++;
                ptr = strtok(NULL, ", :\n");
                if (ptr == NULL)
                {
                    ;
                }
            } /* end while (ptr != NULL) */
        } /* end while (fgets...) */

        /* print some footer information */
        if (emptyflag == 1)
        {
            /* there were no disabled = no  lines */
            fprintf(outfile, "\nNo enabled xinetd.d services. Good.\n");
            fprintf(outfile, "****************************************\n");
        }
        if (emptyflag == 0)
        {
            /* there are services in xinetd.d open */
            fprintf(outfile, "\nIt is strongly recommended that you set\n");
            fprintf(outfile, "disable = yes in the files in /etc/xinetd.d/\n");
            fprintf(outfile, "Be sure to read them and be sure you need to \n");
            fprintf(outfile, "enable those services. Also, double check your\n");
            fprintf(outfile, "/etc/hosts.allow and /etc/hosts.deny files\n");
            fprintf(outfile, "and make sure you are denying everyone and explicitly\n");
            fprintf(outfile, "allowing only the hosts you want.\n");
            fprintf(outfile, "Search http://www.cert.org for details on setup of hosts files.\n");
            fprintf(outfile, "\n");
            fprintf(outfile, "****************************************\n");
        }
        /* clean up... */
        fclose(infile);
        if ((system("rm -f /tmp/xinetd.txt")) < 0)
        {
            /* rhut-rho... problems.. */
            perror("Can't rm tempfile...\n");
            perror("Permissions problem??\n");
            perror("Error was in module: checkinet.\n");
            return(-1);
        }
    } /* end of RedHat 7.x check portion */

    /* now we close the outfile... */
    fclose(outfile);

    if (verbose == 1)
    {
        printf("Finished module checkinetd.\n");
    }

    /* instead of just returning 0 here */
    /* we return inetextists... 	    */
    /* 0 for no existance, 1 if exists  */
    return(inetexists);
}
