xref: /netbsd/sbin/mount_portal/pt_tcp.c (revision bf9ec67e)
1 /*	$NetBSD: pt_tcp.c,v 1.15 2001/01/10 03:33:16 lukem Exp $	*/
2 
3 /*
4  * Copyright (c) 1992, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software donated to Berkeley by
8  * Jan-Simon Pendry.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *	This product includes software developed by the University of
21  *	California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	from: Id: pt_tcp.c,v 1.1 1992/05/25 21:43:09 jsp Exp
39  *	@(#)pt_tcp.c	8.5 (Berkeley) 4/28/95
40  */
41 
42 #include <sys/cdefs.h>
43 #ifndef lint
44 __RCSID("$NetBSD: pt_tcp.c,v 1.15 2001/01/10 03:33:16 lukem Exp $");
45 #endif /* not lint */
46 
47 #include <stdio.h>
48 #include <unistd.h>
49 #include <stdlib.h>
50 #include <errno.h>
51 #include <string.h>
52 #include <sys/types.h>
53 #include <sys/param.h>
54 #include <sys/syslog.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #include <netdb.h>
59 
60 #include "portald.h"
61 
62 /*
63  * Key will be tcp/host/port[/"priv"]
64  * Create a TCP socket connected to the
65  * requested host and port.
66  * Some trailing suffix values have special meanings.
67  * An unrecognised suffix is an error.
68  */
69 int
70 portal_tcp(pcr, key, v, kso, fdp)
71 	struct portal_cred *pcr;
72 	char *key;
73 	char **v;
74 	int kso;
75 	int *fdp;
76 {
77 	char host[MAXHOSTNAMELEN];
78 	char port[MAXHOSTNAMELEN];
79 	char *p = key + (v[1] ? strlen(v[1]) : 0);
80 	char *q;
81 	int priv = 0;
82 #ifdef INET6
83 	struct addrinfo hints, *res, *lres;
84 	int so = -1;
85 	const char *cause = "unknown";
86 #else /* ! INET6 */
87 	struct hostent *hp;
88 	struct servent *sp;
89 	struct in_addr **ipp;
90 	struct in_addr *ip[2];
91 	struct in_addr ina;
92 	int s_port;
93 	struct sockaddr_in sain;
94 #endif
95 
96 	q = strchr(p, '/');
97 	if (q == 0 || q - p >= sizeof(host))
98 		return (EINVAL);
99 	*q = '\0';
100 	strcpy(host, p);
101 	p = q + 1;
102 
103 	q = strchr(p, '/');
104 	if (q)
105 		*q = '\0';
106 	if (strlen(p) >= sizeof(port))
107 		return (EINVAL);
108 	strcpy(port, p);
109 	if (q) {
110 		p = q + 1;
111 		if (strcmp(p, "priv") == 0) {
112 			if (pcr->pcr_uid == 0)
113 				priv = 1;
114 			else
115 				return (EPERM);
116 		} else {
117 			return (EINVAL);
118 		}
119 	}
120 
121 #ifdef INET6
122 	memset(&hints, 0, sizeof(hints));
123 	hints.ai_family = PF_UNSPEC;
124 	hints.ai_socktype = SOCK_STREAM;
125 	hints.ai_protocol = 0;
126 	if (getaddrinfo(host, port, &hints, &res) != 0)
127 		return(EINVAL);
128 
129 	for (lres = res; lres; lres = lres->ai_next) {
130 		if (priv)
131 			so = rresvport((int *) 0);
132 		else
133 			so = socket(lres->ai_family, lres->ai_socktype,
134 			    lres->ai_protocol);
135 		if (so < 0) {
136 			cause = "socket";
137 			continue;
138 		}
139 
140 		if (connect(so, lres->ai_addr, lres->ai_addrlen) != 0) {
141 			cause = "connect";
142 			(void)close(so);
143 			so = -1;
144 			continue;
145 		}
146 
147 		*fdp = so;
148 		errno = 0;
149 		break;
150 	}
151 
152 	if (so < 0)
153 		syslog(LOG_WARNING, "%s: %m", cause);
154 
155 	freeaddrinfo(res);
156 #else /* ! INET6 */
157 	if (inet_aton(host, &ina) == 0) {
158 		hp = gethostbyname(host);
159 		if (hp == 0)
160 			return (EINVAL);
161 		ipp = (struct in_addr **) hp->h_addr_list;
162 	} else {
163 		ip[0] = &ina;
164 		ip[1] = 0;
165 		ipp = ip;
166 	}
167 
168 	sp = getservbyname(port, "tcp");
169 	if (sp != 0)
170 		s_port = sp->s_port;
171 	else {
172 		s_port = strtoul(port, &p, 0);
173 		if (s_port == 0 || *p != '\0')
174 			return (EINVAL);
175 		s_port = htons(s_port);
176 	}
177 
178 	memset(&sain, 0, sizeof(sain));
179 	sain.sin_len = sizeof(sain);
180 	sain.sin_family = AF_INET;
181 	sain.sin_port = s_port;
182 
183 	while (ipp[0]) {
184 		int so;
185 
186 		if (priv)
187 			so = rresvport((int *) 0);
188 		else
189 			so = socket(AF_INET, SOCK_STREAM, 0);
190 		if (so < 0) {
191 			syslog(LOG_WARNING, "socket: %m");
192 			return (errno);
193 		}
194 
195 		sain.sin_addr = *ipp[0];
196 		if (connect(so, (struct sockaddr *) &sain,
197 		    sizeof(sain)) == 0) {
198 			*fdp = so;
199 			return (0);
200 		}
201 		(void) close(so);
202 
203 		ipp++;
204 	}
205 #endif /* INET6 */
206 
207 	return (errno);
208 }
209