scaffold.c revision 272461
1139749Simp /*
240024Sgibbs  * Routines for testing only. Not really industrial strength.
340024Sgibbs  *
440024Sgibbs  * Author: Wietse Venema, Eindhoven University of Technology, The Netherlands.
540024Sgibbs  *
640024Sgibbs  * $FreeBSD: releng/10.1/contrib/tcp_wrappers/scaffold.c 63158 2000-07-14 17:15:34Z ume $
756979Sgibbs  */
840024Sgibbs
956979Sgibbs#ifndef lint
1040024Sgibbsstatic char sccs_id[] = "@(#) scaffold.c 1.6 97/03/21 19:27:24";
1140024Sgibbs#endif
1240024Sgibbs
1340024Sgibbs/* System libraries. */
1440024Sgibbs
1540024Sgibbs#include <sys/types.h>
1640024Sgibbs#include <sys/stat.h>
1756979Sgibbs#include <sys/socket.h>
1840024Sgibbs#include <netinet/in.h>
1940024Sgibbs#include <arpa/inet.h>
2040024Sgibbs#include <netdb.h>
2140024Sgibbs#include <stdio.h>
2240024Sgibbs#include <syslog.h>
2340024Sgibbs#include <setjmp.h>
2440024Sgibbs#include <string.h>
2540024Sgibbs
2640024Sgibbs#ifndef INADDR_NONE
2740024Sgibbs#define	INADDR_NONE	(-1)		/* XXX should be 0xffffffff */
2840024Sgibbs#endif
2940024Sgibbs
3040024Sgibbs#ifndef INET6
3140024Sgibbsextern char *malloc();
3240024Sgibbs#endif
3340024Sgibbs
3440024Sgibbs/* Application-specific. */
3540024Sgibbs
3640024Sgibbs#include "tcpd.h"
3740024Sgibbs#include "scaffold.h"
3840024Sgibbs
3940024Sgibbs /*
4040024Sgibbs  * These are referenced by the options module and by rfc931.c.
4140024Sgibbs  */
4240024Sgibbsint     allow_severity = SEVERITY;
4340024Sgibbsint     deny_severity = LOG_WARNING;
4440024Sgibbsint     rfc931_timeout = RFC931_TIMEOUT;
4540024Sgibbs
46119418Sobrien#ifndef INET6
47119418Sobrien/* dup_hostent - create hostent in one memory block */
48119418Sobrien
4940024Sgibbsstatic struct hostent *dup_hostent(hp)
5040024Sgibbsstruct hostent *hp;
5140024Sgibbs{
5240024Sgibbs    struct hostent_block {
53117126Sscottl	struct hostent host;
54117126Sscottl	char   *addr_list[1];
5556979Sgibbs    };
5640024Sgibbs    struct hostent_block *hb;
5740024Sgibbs    int     count;
5856979Sgibbs    char   *data;
5940024Sgibbs    char   *addr;
6056979Sgibbs
6156979Sgibbs    for (count = 0; hp->h_addr_list[count] != 0; count++)
6240024Sgibbs	 /* void */ ;
6340024Sgibbs
6440024Sgibbs    if ((hb = (struct hostent_block *) malloc(sizeof(struct hostent_block)
6540024Sgibbs			 + (hp->h_length + sizeof(char *)) * count)) == 0) {
6640024Sgibbs	fprintf(stderr, "Sorry, out of memory\n");
6740024Sgibbs	exit(1);
6840024Sgibbs    }
6940024Sgibbs    memset((char *) &hb->host, 0, sizeof(hb->host));
7040024Sgibbs    hb->host.h_length = hp->h_length;
7140024Sgibbs    hb->host.h_addr_list = hb->addr_list;
7240024Sgibbs    hb->host.h_addr_list[count] = 0;
7340024Sgibbs    data = (char *) (hb->host.h_addr_list + count + 1);
7440024Sgibbs
7540024Sgibbs    for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
7640024Sgibbs	hb->host.h_addr_list[count] = data + hp->h_length * count;
7740024Sgibbs	memcpy(hb->host.h_addr_list[count], addr, hp->h_length);
7857679Sgibbs    }
7940024Sgibbs    return (&hb->host);
8040024Sgibbs}
8140024Sgibbs#endif
8240024Sgibbs
8340024Sgibbs/* find_inet_addr - find all addresses for this host, result to free() */
8440024Sgibbs
8540024Sgibbs#ifdef INET6
8640024Sgibbsstruct addrinfo *find_inet_addr(host)
8740024Sgibbschar   *host;
8840024Sgibbs{
8940024Sgibbs    struct addrinfo hints, *res;
9040024Sgibbs
9140024Sgibbs    memset(&hints, 0, sizeof(hints));
9240024Sgibbs    hints.ai_family = PF_UNSPEC;
9340024Sgibbs    hints.ai_socktype = SOCK_STREAM;
9440024Sgibbs    hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
9540024Sgibbs    if (getaddrinfo(host, NULL, &hints, &res) == 0)
9640024Sgibbs	return (res);
9740024Sgibbs
9840024Sgibbs    memset(&hints, 0, sizeof(hints));
9940024Sgibbs    hints.ai_family = PF_UNSPEC;
10040024Sgibbs    hints.ai_socktype = SOCK_STREAM;
10140024Sgibbs    hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
10257679Sgibbs    if (getaddrinfo(host, NULL, &hints, &res) != 0) {
10357679Sgibbs	tcpd_warn("%s: host not found", host);
10457679Sgibbs	return (0);
10557679Sgibbs    }
10657679Sgibbs    if (res->ai_family != AF_INET6 && res->ai_family != AF_INET) {
10757679Sgibbs	tcpd_warn("%d: not an internet host", res->ai_family);
10840024Sgibbs	freeaddrinfo(res);
10940024Sgibbs	return (0);
11040024Sgibbs    }
11140024Sgibbs    if (!res->ai_canonname) {
11240024Sgibbs	tcpd_warn("%s: hostname alias", host);
11340024Sgibbs	tcpd_warn("(cannot obtain official name)", res->ai_canonname);
11440024Sgibbs    } else if (STR_NE(host, res->ai_canonname)) {
11540024Sgibbs	tcpd_warn("%s: hostname alias", host);
11640024Sgibbs	tcpd_warn("(official name: %.*s)", STRING_LENGTH, res->ai_canonname);
11740024Sgibbs    }
11840024Sgibbs    return (res);
11940024Sgibbs}
12040024Sgibbs#else
12140024Sgibbsstruct hostent *find_inet_addr(host)
12240024Sgibbschar   *host;
12340024Sgibbs{
12440024Sgibbs    struct in_addr addr;
12540024Sgibbs    struct hostent *hp;
12640024Sgibbs    static struct hostent h;
12740024Sgibbs    static char *addr_list[2];
12840024Sgibbs
12940024Sgibbs    /*
13040024Sgibbs     * Host address: translate it to internal form.
13140024Sgibbs     */
13240024Sgibbs    if ((addr.s_addr = dot_quad_addr(host)) != INADDR_NONE) {
13340024Sgibbs	h.h_addr_list = addr_list;
13440024Sgibbs	h.h_addr_list[0] = (char *) &addr;
13540024Sgibbs	h.h_length = sizeof(addr);
13640024Sgibbs	return (dup_hostent(&h));
13740024Sgibbs    }
13840024Sgibbs
13940024Sgibbs    /*
14040024Sgibbs     * Map host name to a series of addresses. Watch out for non-internet
14140024Sgibbs     * forms or aliases. The NOT_INADDR() is here in case gethostbyname() has
14240024Sgibbs     * been "enhanced" to accept numeric addresses. Make a copy of the
14340024Sgibbs     * address list so that later gethostbyXXX() calls will not clobber it.
14440024Sgibbs     */
14540024Sgibbs    if (NOT_INADDR(host) == 0) {
14640024Sgibbs	tcpd_warn("%s: not an internet address", host);
14740024Sgibbs	return (0);
14840024Sgibbs    }
14940024Sgibbs    if ((hp = gethostbyname(host)) == 0) {
15040024Sgibbs	tcpd_warn("%s: host not found", host);
15140024Sgibbs	return (0);
15240024Sgibbs    }
15340024Sgibbs    if (hp->h_addrtype != AF_INET) {
15440024Sgibbs	tcpd_warn("%d: not an internet host", hp->h_addrtype);
15540024Sgibbs	return (0);
15640024Sgibbs    }
15740024Sgibbs    if (STR_NE(host, hp->h_name)) {
15840024Sgibbs	tcpd_warn("%s: hostname alias", host);
15940024Sgibbs	tcpd_warn("(official name: %.*s)", STRING_LENGTH, hp->h_name);
16040024Sgibbs    }
16140024Sgibbs    return (dup_hostent(hp));
16240024Sgibbs}
16340024Sgibbs#endif
16440024Sgibbs
16540024Sgibbs/* check_dns - give each address thorough workout, return address count */
16640024Sgibbs
16740024Sgibbsint     check_dns(host)
16840024Sgibbschar   *host;
16940024Sgibbs{
17040024Sgibbs    struct request_info request;
17140024Sgibbs#ifdef INET6
17240024Sgibbs    struct sockaddr_storage sin;
17340024Sgibbs    struct addrinfo *hp, *res;
17440024Sgibbs#else
17540024Sgibbs    struct sockaddr_in sin;
17640024Sgibbs    struct hostent *hp;
17740024Sgibbs#endif
17840024Sgibbs    int     count;
17940024Sgibbs    char   *addr;
18040024Sgibbs
18140024Sgibbs    if ((hp = find_inet_addr(host)) == 0)
18240024Sgibbs	return (0);
18340024Sgibbs    request_init(&request, RQ_CLIENT_SIN, &sin, 0);
18440024Sgibbs    sock_methods(&request);
18540024Sgibbs#ifndef INET6
18640024Sgibbs    memset((char *) &sin, 0, sizeof(sin));
18740024Sgibbs    sin.sin_family = AF_INET;
18840024Sgibbs#endif
18940024Sgibbs
19040024Sgibbs#ifdef INET6
19140024Sgibbs    for (res = hp, count = 0; res; res = res->ai_next, count++) {
19240024Sgibbs	memcpy(&sin, res->ai_addr, res->ai_addrlen);
19340024Sgibbs#else
19440024Sgibbs    for (count = 0; (addr = hp->h_addr_list[count]) != 0; count++) {
19540024Sgibbs	memcpy((char *) &sin.sin_addr, addr, sizeof(sin.sin_addr));
19640024Sgibbs#endif
19740024Sgibbs
19840024Sgibbs	/*
19940024Sgibbs	 * Force host name and address conversions. Use the request structure
20040024Sgibbs	 * as a cache. Detect hostname lookup problems. Any name/name or
20140024Sgibbs	 * name/address conflicts will be reported while eval_hostname() does
20240024Sgibbs	 * its job.
20340024Sgibbs	 */
20440024Sgibbs	request_set(&request, RQ_CLIENT_ADDR, "", RQ_CLIENT_NAME, "", 0);
20540024Sgibbs	if (STR_EQ(eval_hostname(request.client), unknown))
20640024Sgibbs	    tcpd_warn("host address %s->name lookup failed",
20740024Sgibbs		      eval_hostaddr(request.client));
20840024Sgibbs    }
20940024Sgibbs#ifdef INET6
21040024Sgibbs    freeaddrinfo(hp);
21140024Sgibbs#else
21240024Sgibbs    free((char *) hp);
21340024Sgibbs#endif
21440024Sgibbs    return (count);
21540024Sgibbs}
21640024Sgibbs
21756979Sgibbs/* dummy function to intercept the real shell_cmd() */
21856979Sgibbs
21956979Sgibbs/* ARGSUSED */
22056979Sgibbs
22140024Sgibbsvoid    shell_cmd(command)
22240024Sgibbschar   *command;
22340024Sgibbs{
22440024Sgibbs    if (hosts_access_verbose)
22540024Sgibbs	printf("command: %s", command);
22640024Sgibbs}
22740024Sgibbs
22840024Sgibbs/* dummy function  to intercept the real clean_exit() */
22940024Sgibbs
23040024Sgibbs/* ARGSUSED */
23140024Sgibbs
23240024Sgibbsvoid    clean_exit(request)
23340024Sgibbsstruct request_info *request;
23440024Sgibbs{
23540024Sgibbs    exit(0);
23640024Sgibbs}
23740024Sgibbs
23840024Sgibbs/* dummy function  to intercept the real rfc931() */
23940420Sgibbs
24040024Sgibbs/* ARGSUSED */
24140024Sgibbs
24240024Sgibbsvoid    rfc931(request)
24340024Sgibbsstruct request_info *request;
24440024Sgibbs{
24540024Sgibbs    strcpy(request->user, unknown);
24640024Sgibbs}
24740024Sgibbs
24840024Sgibbs/* check_path - examine accessibility */
24940024Sgibbs
25040024Sgibbsint     check_path(path, st)
25140024Sgibbschar   *path;
25240024Sgibbsstruct stat *st;
25340024Sgibbs{
25440024Sgibbs    struct stat stbuf;
25540024Sgibbs    char    buf[BUFSIZ];
25640024Sgibbs
25740024Sgibbs    if (stat(path, st) < 0)
25840024Sgibbs	return (-1);
259115343Sscottl#ifdef notdef
26040024Sgibbs    if (st->st_uid != 0)
26140024Sgibbs	tcpd_warn("%s: not owned by root", path);
26240024Sgibbs    if (st->st_mode & 020)
26340024Sgibbs	tcpd_warn("%s: group writable", path);
26440024Sgibbs#endif
26540024Sgibbs    if (st->st_mode & 002)
26640024Sgibbs	tcpd_warn("%s: world writable", path);
26740024Sgibbs    if (path[0] == '/' && path[1] != 0) {
26840024Sgibbs	strrchr(strcpy(buf, path), '/')[0] = 0;
26940024Sgibbs	(void) check_path(buf[0] ? buf : "/", &stbuf);
27040024Sgibbs    }
27140024Sgibbs    return (0);
27240024Sgibbs}
27340024Sgibbs