/*-
 * Copyright (c) 1993, 1996 Trusted Information Systems, Incorporated
 * All rights reserved.
 *
 * Redistribution and use are governed by the terms detailed in the
 * license document ("LICENSE") included with the toolkit.
 */

/*
 *	Author: Marcus J. Ranum, Trusted Information Systems, Inc.
 */
/*
 *  This version was slightly patched for lp protocol compatibility
 *  (ArkanoiD, Oct 1998)
 *
 */

#include	<ctype.h>
#include	<string.h>
#include	<strings.h>
#include	<sys/types.h>
#include	<sys/time.h>
#include	<sys/socket.h>
#include	<netinet/in.h>
#include	<netdb.h>
#include	<syslog.h>
#include	<errno.h>
#include	<unistd.h>
#include	<stdio.h>
#include	<arpa/inet.h>

#include	"firewall.h"

extern  size_t 	strlcat(char*,const char*,size_t);
extern  size_t 	strlcpy(char*,const char*,size_t);


int
lp_conn_server(srv,portnum,priv,rbuf)
char	*srv;
int	portnum;
int	priv;
char	*rbuf;
{
	struct	sockaddr_in	addr;
	struct	hostent		*hp = 0;
	int			fd;
	char			*p;
	char			**ap;

	p = srv;
	while(*p != '\0' && (*p == '.' || isdigit(*p)))
		p++;

	ap = 0;
	/* not all digits or dots */
	if(*p != '\0') {
		if((hp = gethostbyname(srv)) == (struct hostent *)0) {
			if(rbuf != (char *)0)
				strlcpy(rbuf,"hostname unknown",MAX_STR);
			return(-1);
		}

		ap = hp->h_addr_list;
	} else {
		unsigned long	f;

		if((f = inet_addr(srv)) == -1L) {
			if(rbuf != (char *)0)
				strlcpy(rbuf,"hostname unparsable",MAX_STR);
			return(-1);
		}

		(void)bcopy((char *)&f,(char *)&addr.sin_addr,sizeof(f));
	}

newaddr:

	if (hp) {
		if (hp->h_length > sizeof(addr.sin_addr.s_addr)) {
			syslog(LLEV,"securityalert: invalid host address length (%d) hostname %.512s", hp->h_length, srv);
			strlcpy(rbuf, "hostname invalid",MAX_STR);
			return (-1);
		}
		(void)bcopy(*ap,(char *)&addr.sin_addr,hp->h_length);
	}

	addr.sin_port = htons(portnum);
	addr.sin_family = AF_INET;

	if(priv) {
		int lport;
		for (lport=721; lport<=731; lport++) {
			if ((fd = rresvport(&lport)) > 0 )
				break;
		}
	} else
		fd = socket(AF_INET,SOCK_STREAM,0);
	
	if(fd < 0) {
		if(rbuf != (char *)0)
			snprintf(rbuf,BUFSIZ,"socket: %s",strerror(errno));
		return(-2);
	}

	if(connect(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0) {
		if (hp && *++ap)
			goto newaddr;
		if(rbuf != (char *)0)
			snprintf(rbuf,MAX_STR,"connect: %s",strerror(errno));
		return(-3);
	}
	return(fd);
}
