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