xref: /original-bsd/sbin/mount_portal/pt_tcp.c (revision e58c8952)
1 /*
2  * Copyright (c) 1992, 1993
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.3 (Berkeley) 03/27/94
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 = atoi(port);
100 		if (s_port == 0)
101 			return (EINVAL);
102 	}
103 
104 	bzero(&sain, sizeof(sain));
105 	sain.sin_len = sizeof(sain);
106 	sain.sin_family = AF_INET;
107 	sain.sin_port = s_port;
108 
109 	while (ipp[0]) {
110 		int so;
111 
112 		if (priv)
113 			so = rresvport((int *) 0);
114 		else
115 			so = socket(AF_INET, SOCK_STREAM, 0);
116 		if (so < 0) {
117 			syslog(LOG_ERR, "socket: %m");
118 			return (errno);
119 		}
120 
121 		sain.sin_addr = *ipp[0];
122 		if (connect(so, (struct sockaddr *) &sain, sizeof(sain)) == 0) {
123 			*fdp = so;
124 			return (0);
125 		}
126 		(void) close(so);
127 
128 		ipp++;
129 	}
130 
131 	return (errno);
132 }
133