141828Sdillon/*
241828Sdillon * Copyright (c) 1992, 1993
341828Sdillon *  The Regents of the University of California.  All rights reserved.
441828Sdillon * All rights reserved.
541828Sdillon *
641828Sdillon * This code is derived from software donated to Berkeley by
741828Sdillon * Jan-Simon Pendry.
841828Sdillon *
941828Sdillon * Modified by Duncan Barclay.
1041828Sdillon *
1141828Sdillon * Redistribution and use in source and binary forms, with or without
1241828Sdillon * modification, are permitted provided that the following conditions
1341828Sdillon * are met:
1441828Sdillon * 1. Redistributions of source code must retain the above copyright
1541828Sdillon *    notice, this list of conditions and the following disclaimer.
1641828Sdillon * 2. Redistributions in binary form must reproduce the above copyright
1741828Sdillon *    notice, this list of conditions and the following disclaimer in the
1841828Sdillon *    documentation and/or other materials provided with the distribution.
1941828Sdillon * 4. Neither the name of the University nor the names of its contributors
2041828Sdillon *    may be used to endorse or promote products derived from this software
2141828Sdillon *    without specific prior written permission.
2241828Sdillon *
2341828Sdillon * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2441828Sdillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2541828Sdillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2641828Sdillon * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2741828Sdillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2841828Sdillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2941828Sdillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3041828Sdillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3141828Sdillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3241828Sdillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3341828Sdillon * SUCH DAMAGE.
3441828Sdillon *
3541828Sdillon *  @(#)pt_tcp.c  8.3 (Berkeley) 3/27/94
3641828Sdillon *
3741828Sdillon * pt_tcp.c,v 1.1.1.1 1994/05/26 06:34:34 rgrimes Exp
3841828Sdillon */
3941828Sdillon
40129862Sstefanf#include <sys/cdefs.h>
41129862Sstefanf__FBSDID("$FreeBSD$");
42129862Sstefanf
4341828Sdillon#include <stdio.h>
4441828Sdillon#include <unistd.h>
4541828Sdillon#include <stdlib.h>
4641828Sdillon#include <errno.h>
47129863Sstefanf#include <string.h>
4841828Sdillon#include <sys/types.h>
4941828Sdillon#include <sys/param.h>
5041828Sdillon#include <sys/syslog.h>
5141828Sdillon#include <sys/socket.h>
5241828Sdillon#include <netinet/in.h>
5341828Sdillon#include <arpa/inet.h>
5441828Sdillon#include <netdb.h>
5541828Sdillon
5641828Sdillon#include "portald.h"
5741828Sdillon
5841828Sdillon/*
5941828Sdillon * Key will be tcplisten/host/port
6041828Sdillon *
6141828Sdillon * Create a TCP socket bound to the requested host and port.
6241828Sdillon * If the host is "ANY" the receving address will be set to INADDR_ANY.
6341828Sdillon * If the port is 0 the caller must find out the returned port number
6441828Sdillon * using a call to getsockname.
6541828Sdillon *
6641828Sdillon * XXX!  The owner of the socket will be root rather then the user.  This
6741828Sdillon * 	 may cause remote auth (identd) to return unexpected results.
6841828Sdillon *
6941828Sdillon */
70166157Srodrigcint portal_tcplisten(struct portal_cred *pcr, char *key, char **v,
71166157Srodrigc    int kso __unused, int *fdp)
7241828Sdillon{
7341828Sdillon       char host[MAXHOSTNAMELEN];
7441828Sdillon       char port[MAXHOSTNAMELEN];
7541828Sdillon       char *p = key + (v[1] ? strlen(v[1]) : 0);
7641828Sdillon       char *q;
7741828Sdillon       struct hostent *hp;
7841828Sdillon       struct servent *sp;
79166157Srodrigc       struct in_addr **ipp = NULL;
8041828Sdillon       struct in_addr *ip[2];
8141828Sdillon       struct in_addr ina;
8241828Sdillon       u_short s_port;
8341828Sdillon       int any = 0;
8441828Sdillon       struct sockaddr_in sain;
8541828Sdillon
8641828Sdillon       q = strchr(p, '/');
87166157Srodrigc       if (q == 0 || q - p >= (int)sizeof(host))
8841828Sdillon               return (EINVAL);
8941828Sdillon       *q = '\0';
9041828Sdillon       snprintf(host, sizeof(host), "%s", p);
9141828Sdillon       p = q + 1;
9241828Sdillon
9341828Sdillon       q = strchr(p, '/');
9441828Sdillon       if (q)
9541828Sdillon               *q = '\0';
9641828Sdillon       if (strlen(p) >= sizeof(port))
9741828Sdillon               return (EINVAL);
9841828Sdillon       snprintf(port, sizeof(port), "%s", p);
9941828Sdillon
10041828Sdillon       if (strcmp(host, "ANY") == 0) {
10141828Sdillon               any = 1;
10241828Sdillon       } else {
10341828Sdillon               hp = gethostbyname(host);
10441828Sdillon               if (hp != 0) {
10541828Sdillon                       ipp = (struct in_addr **) hp->h_addr_list;
10641828Sdillon               } else {
10741828Sdillon                       ina.s_addr = inet_addr(host);
10841828Sdillon                       if (ina.s_addr == INADDR_NONE)
10941828Sdillon                               return (EINVAL);
11041828Sdillon                       ip[0] = &ina;
11141828Sdillon                       ip[1] = 0;
11241828Sdillon                       ipp = ip;
11341828Sdillon               }
11441828Sdillon       }
11541828Sdillon#ifdef DEBUG
11641828Sdillon       if (any)
11741828Sdillon               printf("INADDR_ANY to be used for hostname\n");
11841828Sdillon       else
11941828Sdillon               printf("inet address for %s is %s\n", host, inet_ntoa(*ipp[0]));
12041828Sdillon#endif
12141828Sdillon
12241828Sdillon       sp = getservbyname(port, "tcp");
12341828Sdillon       if (sp != NULL) {
12441828Sdillon               s_port = (u_short) sp->s_port;
12541828Sdillon        } else {
12641828Sdillon               s_port = strtoul(port, &p, 0);
12741828Sdillon               if (*p != '\0')
12841828Sdillon                       return (EINVAL);
12941828Sdillon               s_port = htons(s_port);
13041828Sdillon       }
13141828Sdillon       if ((ntohs(s_port) != 0) &&
13241828Sdillon           (ntohs(s_port) <= IPPORT_RESERVED) &&
13341828Sdillon           (pcr->pcr_uid != 0))
13441828Sdillon               return (EPERM);
13541828Sdillon#ifdef DEBUG
13641828Sdillon       printf("port number for %s is %d\n", port, ntohs(s_port));
13741828Sdillon#endif
13841828Sdillon
13941828Sdillon       memset(&sain, 0, sizeof(sain));
14041828Sdillon       sain.sin_len = sizeof(sain);
14141828Sdillon       sain.sin_family = AF_INET;
14241828Sdillon       sain.sin_port = s_port;
14341828Sdillon
14441828Sdillon       if (any) {
14541828Sdillon               int so;
14641828Sdillon               int sock;
14741828Sdillon
14841828Sdillon               so = socket(AF_INET, SOCK_STREAM, 0);
14941828Sdillon               if (so < 0) {
15041828Sdillon                       syslog(LOG_ERR, "socket: %m");
15141828Sdillon                       return (errno);
15241828Sdillon               }
15341828Sdillon
15441828Sdillon               sain.sin_addr.s_addr = INADDR_ANY;
15541828Sdillon               if (bind(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
15641828Sdillon                       listen(so, 1);
15741828Sdillon                       if ((sock = accept(so, (struct sockaddr *)0, (int *)0)) == -1) {
15841828Sdillon                               syslog(LOG_ERR, "accept: %m");
15941828Sdillon                               (void) close(so);
16041828Sdillon                               return (errno);
16141828Sdillon                       }
16241828Sdillon                       *fdp = sock;
16341828Sdillon                       (void) close(so);
16441828Sdillon                       return (0);
16541828Sdillon               }
16641828Sdillon               syslog(LOG_ERR, "bind: %m");
16741828Sdillon               (void) close(so);
16841828Sdillon               return (errno);
16941828Sdillon       }
17041828Sdillon
17141828Sdillon       while (ipp[0]) {
17241828Sdillon               int so;
17341828Sdillon               int sock;
17441828Sdillon
17541828Sdillon               so = socket(AF_INET, SOCK_STREAM, 0);
17641828Sdillon               if (so < 0) {
17741828Sdillon                       syslog(LOG_ERR, "socket: %m");
17841828Sdillon                       return (errno);
17941828Sdillon               }
18041828Sdillon
18141828Sdillon               sain.sin_addr = *ipp[0];
18241828Sdillon               if (bind(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
18341828Sdillon                       listen(so, 1);
18441828Sdillon                       if ((sock = accept(so, (struct sockaddr *)0, (int *)0)) == -1) {
18541828Sdillon                               syslog(LOG_ERR, "accept: %m");
18641828Sdillon                               (void) close(so);
18741828Sdillon                               return (errno);
18841828Sdillon                       }
18941828Sdillon                       *fdp = sock;
19041828Sdillon                       (void) close(so);
19141828Sdillon                       return (0);
19241828Sdillon               }
19341828Sdillon               (void) close(so);
19441828Sdillon
19541828Sdillon               ipp++;
19641828Sdillon       }
19741828Sdillon
19841828Sdillon       syslog(LOG_ERR, "bind: %m");
19941828Sdillon       return (errno);
20041828Sdillon
20141828Sdillon}
202