Milán Major

netscape-revival

1 branch
Code

security/cmd/ssld/ssld_conf.c

/*
** Copyright (c) 1995.  Netscape Communications Corporation.  All rights
** reserved.  This use of this Secure Sockets Layer Reference
** Implementation (the "Software") is governed by the terms of the SSL
** Reference Implementation License Agreement.  Please read the
** accompanying "License" file for a description of the rights granted.
** Any other third party materials you use with this Software may be
** subject to additional license restrictions from the licensors of such
** third party software and/or additional export restrictions.  The SSL
** Implementation License Agreement grants you no rights to any such
** third party material.
*/

/*
** Functions for parsing configuration file 'ssld.conf' for ssld.
**
** This should be included in the Makefile for ssld
**
** Last updated: 12/01/95	By: dkarlton
*/

#include "ssld.h"
#include <ctype.h>
#include <netdb.h>

static char **EmitWord(char **av, int nav, char *start, int len)
{
    char *s = (char*) malloc(len+1);
    memcpy(s, start, len);
    s[len] = 0;

    if (av) {
	av = (char**) realloc(av, (nav + 2) * sizeof(char*));
	av[nav] = s;
	av[nav+1] = 0;
    } else {
	av = (char**) malloc(2 * sizeof(char*));
	av[0] = s;
	av[1] = 0;
    }
    return av;
}

char **BreakLine(int *navp, char *cp)
{
    char **av;
    char c, *s;
    int nav;

    av = 0;
    s = cp;
    nav = 0;
    for (; (c = *cp) != 0; cp++) {
	if (c == '\n') {
	    /* Stop and don't increment cp */
	    break;
	}
	if ((c == ' ') || (c == '\t')) {
	    if (cp - s >= 1) {
		/* Emit word into av */
		av = EmitWord(av, nav, s, cp - s);
		nav++;
	    }
	    s = cp + 1;
	}
    }
    if (cp - s >= 1) {
	/* Emit word into av */
	av = EmitWord(av, nav, s, cp - s);
	nav++;
    }
    *navp = nav;
    return av;
}

void
dumpACL(Service *s)
{
    ACLNode *acl;

    acl = s->acl;
    if ( acl ) {
	DebugPrint("using Access Control List for port %d:", s->port);
    
	while ( acl ) {
	    DebugPrint("\t%s", acl->name);
	    acl = acl->next;
	}
    } else {
	DebugPrint("not using any Access Control List for port %d", s->port);
    }
    return;
}

/*
** Read in ssld configuration file, returning a list of Service objects
** that the daemon will service. Leaks memory, but who cares.
*/
Service *ReadConfFile(char *file)
{
    FILE *fp, *aclfp;
    Service *list, *s;
    Service **next;
    char line[2000], *cp, **av;
    int num, nav, port, client, auth, acl;
    struct servent *sp;
    struct hostent *hp;
    ACLNode *node, *aclhead;
    int linelen;
    
    fp = fopen(file, "r");
    if (!fp) return 0;

    num = 0;
    list = 0;
    next = &list;
    for (;;) {
	num++;
	cp = fgets(line, sizeof(line), fp);
	if (!cp) break;
	if (line[0] == '#') continue;
	if (strcmp(line, "\n") == 0) continue;

	/* Parse line */
	av = BreakLine(&nav, line);
	if (av == 0) continue;
	if (nav < 7) {
	    Notice("%s:%d: syntax error", file, num);
	    continue;
	}

	/* Process port field */
	if (isdigit(av[0][0])) {
	    port = htons(atoi(av[0]));
	} else {
	    sp = getservbyname(av[0], "tcp");
	    if (!sp) {
		Notice("%s:%d: no service named \"%s\"", file, num, av[0]);
		continue;
	    }
	    port = sp->s_port;
	}

	/* Process mode field */
	if (strcasecmp(av[1], "client") == 0) {
	    client = 1;
	    auth = 0;
	} else if (strcasecmp(av[1], "auth-client") == 0) {
	    client = 1;
	    auth = 1;
	} else if (strcasecmp(av[1], "server") == 0) {
	    client = 0;
	    auth = 0;
	} else if (strcasecmp(av[1], "auth-server") == 0) {
	    client = 0;
	    auth = 1;
	} else {
	    Notice("%s:%d: no mode called \"%s\"", file, num, av[1]);
	    continue;
	}

	/* Process acl field */
	/* WARNING - acl reading reuses the line buffer,
	 *   we had better be done with it by now.
	 */
	aclhead = 0;
	if (!client) {
	    if (strcmp(av[2], "-") == 0) {
		acl = 0;
	    } else {
		acl = 1;
		aclfp = fopen(av[2], "r");
		if (!aclfp) return 0;
		
		for (;;) {
		    /* read a name from the file */
		    cp = fgets(line, sizeof(line), aclfp);
		    if (!cp) {
			/* done */
			break;
		    }
		    
		    if ( ( line[0] == '#' ) || ( line[0] == 0 ) ||
			( line[0] == '\n' ) ) {
			/* comment or blank line */
			continue;
		    }

		    linelen = strlen(line);

		    if ( line[linelen-1] == '\n' ) {
			line[linelen-1] = 0;
		    }

		    node = (ACLNode *)calloc(1, sizeof(ACLNode));
		    if ( !node ) {
			return 0;
		    }
		    
		    node->name = (char *)calloc(1, linelen + 1);
		    if ( !node->name ) {
			return 0;
		    }
		    
		    strcpy(node->name, line);
		
		    node->next = aclhead;
		    aclhead = node;
		}
	    }
	}

	DebugPrint("config file %s:%d: ", file, num);

	DebugPrint("\tport=%d client=%d auth=%d key=%s cert=%s action=%s",
	      port, client, auth, av[3], av[4], av[5]);

	/* Process action field */
	s = (Service*) calloc(1, sizeof(Service));
	s->port = port;
	s->client = client;
	s->auth = auth;
	s->listen = -1;
	s->acl = aclhead;
	s->keyname = av[3];
	s->certname = av[4];

	dumpACL(s);
	
	if (strcasecmp(av[5], "forward") == 0) {
	    cp = strchr(av[6], ':');
	    if (!cp) {
		Notice("%s:%d: no port on forward address", file, num);
		continue;
	    }
	    *cp++ = 0;
	    hp = gethostbyname(av[6]);
	    if (!hp) {
		Notice("%s:%d: no host found called \"%s\"", file, num, av[6]);
		continue;
	    }
	    if (isdigit(*cp)) {
		port = htons(atoi(cp));
	    } else {
		sp = getservbyname(cp, "tcp");
		if (!sp) {
		    Notice("%s:%d: no service named \"%s\"", file, num, av[0]);
		    continue;
		}
		port = sp->s_port;
	    }
	    s->action = FORWARDER;
	    s->forward.sin_family = AF_INET;
	    s->forward.sin_port = port;
	    s->forward.sin_addr = *(struct in_addr*) hp->h_addr_list[0];
	} else if (strcasecmp(av[5], "exec") == 0) {
	    if (client) {
		Notice("%s:%d: client mode can't use exec action", file, num);
		continue;
	    }
	    s->action = EXECER;
	    s->file = av[6];
	    s->avp = &av[7];
	}
	*next = s;
	next = &s->next;
    }
    return list;
}