pt_tcp.c revision 1.14 1 /* $NetBSD: pt_tcp.c,v 1.14 2000/12/31 06:03:53 itojun 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.14 2000/12/31 06:03:53 itojun 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_ERR, "%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_ERR, "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