xref: /original-bsd/sbin/mount_portal/pt_tcp.c (revision 27393bdf)
1 /*
2  * Copyright (c) 1992, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  * All rights reserved.
5  *
6  * This code is derived from software donated to Berkeley by
7  * Jan-Simon Pendry.
8  *
9  * %sccs.include.redist.c%
10  *
11  *	@(#)pt_tcp.c	8.5 (Berkeley) 04/28/95
12  *
13  * $Id: pt_tcp.c,v 1.1 1992/05/25 21:43:09 jsp Exp jsp $
14  */
15 
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <stdlib.h>
19 #include <errno.h>
20 #include <strings.h>
21 #include <sys/types.h>
22 #include <sys/param.h>
23 #include <sys/syslog.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <netdb.h>
28 
29 #include "portald.h"
30 
31 /*
32  * Key will be tcp/host/port[/"priv"]
33  * Create a TCP socket connected to the
34  * requested host and port.
35  * Some trailing suffix values have special meanings.
36  * An unrecognised suffix is an error.
37  */
38 int portal_tcp(pcr, key, v, kso, fdp)
39 	struct portal_cred *pcr;
40 	char *key;
41 	char **v;
42 	int kso;
43 	int *fdp;
44 {
45 	char host[MAXHOSTNAMELEN];
46 	char port[MAXHOSTNAMELEN];
47 	char *p = key + (v[1] ? strlen(v[1]) : 0);
48 	char *q;
49 	struct hostent *hp;
50 	struct servent *sp;
51 	struct in_addr **ipp;
52 	struct in_addr *ip[2];
53 	struct in_addr ina;
54 	int s_port;
55 	int priv = 0;
56 	struct sockaddr_in sain;
57 
58 	q = strchr(p, '/');
59 	if (q == 0 || q - p >= sizeof(host))
60 		return (EINVAL);
61 	*q = '\0';
62 	strcpy(host, p);
63 	p = q + 1;
64 
65 	q = strchr(p, '/');
66 	if (q)
67 		*q = '\0';
68 	if (strlen(p) >= sizeof(port))
69 		return (EINVAL);
70 	strcpy(port, p);
71 	if (q) {
72 		p = q + 1;
73 		if (strcmp(p, "priv") == 0) {
74 			if (pcr->pcr_uid == 0)
75 				priv = 1;
76 			else
77 				return (EPERM);
78 		} else {
79 			return (EINVAL);
80 		}
81 	}
82 
83 	hp = gethostbyname(host);
84 	if (hp != 0) {
85 		ipp = (struct in_addr **) hp->h_addr_list;
86 	} else {
87 		ina.s_addr = inet_addr(host);
88 		if (ina.s_addr == INADDR_NONE)
89 			return (EINVAL);
90 		ip[0] = &ina;
91 		ip[1] = 0;
92 		ipp = ip;
93 	}
94 
95 	sp = getservbyname(port, "tcp");
96 	if (sp != 0)
97 		s_port = sp->s_port;
98 	else {
99 		s_port = strtoul(port, &p, 0);
100 		if (s_port == 0 || *p != '\0')
101 			return (EINVAL);
102 		s_port = htons(s_port);
103 	}
104 
105 	memset(&sain, 0, sizeof(sain));
106 	sain.sin_len = sizeof(sain);
107 	sain.sin_family = AF_INET;
108 	sain.sin_port = s_port;
109 
110 	while (ipp[0]) {
111 		int so;
112 
113 		if (priv)
114 			so = rresvport((int *) 0);
115 		else
116 			so = socket(AF_INET, SOCK_STREAM, 0);
117 		if (so < 0) {
118 			syslog(LOG_ERR, "socket: %m");
119 			return (errno);
120 		}
121 
122 		sain.sin_addr = *ipp[0];
123 		if (connect(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
124 			*fdp = so;
125 			return (0);
126 		}
127 		(void) close(so);
128 
129 		ipp++;
130 	}
131 
132 	return (errno);
133 }
134