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 */
portal_tcp(pcr,key,v,kso,fdp)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