]> git.saurik.com Git - apple/network_cmds.git/blob - rlogin.tproj/kcmd.c
0f8e6e3eada2414bf7ef453593a1eaf31d39b834
[apple/network_cmds.git] / rlogin.tproj / kcmd.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1983, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58 #if !defined(__APPLE__) || defined(KERBEROS)
59
60 #include <sys/param.h>
61 #include <sys/file.h>
62 #include <sys/socket.h>
63 #include <sys/stat.h>
64
65 #include <netinet/in.h>
66 #include <arpa/inet.h>
67
68 #include <kerberosIV/des.h>
69 #include <kerberosIV/krb.h>
70 #include <kerberosIV/kparse.h>
71
72 #include <ctype.h>
73 #include <errno.h>
74 #include <netdb.h>
75 #include <pwd.h>
76 #include <signal.h>
77 #include <stdio.h>
78 #include <stdlib.h>
79 #include <string.h>
80 #include <unistd.h>
81
82 #include "krb.h"
83
84 #ifndef MAXHOSTNAMELEN
85 #define MAXHOSTNAMELEN 64
86 #endif
87
88 #define START_PORT 5120 /* arbitrary */
89
90 int getport __P((int *));
91
92 int
93 kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
94 cred, schedule, msg_data, laddr, faddr, authopts)
95 int *sock;
96 char **ahost;
97 u_short rport;
98 char *locuser, *remuser, *cmd;
99 int *fd2p;
100 KTEXT ticket;
101 char *service;
102 char *realm;
103 CREDENTIALS *cred;
104 Key_schedule schedule;
105 MSG_DAT *msg_data;
106 struct sockaddr_in *laddr, *faddr;
107 long authopts;
108 {
109 int s, timo = 1, pid;
110 long oldmask;
111 struct sockaddr_in sin, from;
112 char c;
113 #ifdef ATHENA_COMPAT
114 int lport = IPPORT_RESERVED - 1;
115 #else
116 int lport = START_PORT;
117 #endif
118 struct hostent *hp;
119 int rc;
120 char *host_save;
121 int status;
122
123 pid = getpid();
124 hp = gethostbyname(*ahost);
125 if (hp == NULL) {
126 /* fprintf(stderr, "%s: unknown host\n", *ahost); */
127 return (-1);
128 }
129
130 host_save = malloc(strlen(hp->h_name) + 1);
131 strcpy(host_save, hp->h_name);
132 *ahost = host_save;
133
134 #ifdef KERBEROS
135 /* If realm is null, look up from table */
136 if (realm == NULL || realm[0] == '\0')
137 realm = krb_realmofhost(host_save);
138 #endif /* KERBEROS */
139
140 oldmask = sigblock(sigmask(SIGURG));
141 for (;;) {
142 s = getport(&lport);
143 if (s < 0) {
144 if (errno == EAGAIN)
145 fprintf(stderr,
146 "kcmd(socket): All ports in use\n");
147 else
148 perror("kcmd: socket");
149 sigsetmask(oldmask);
150 return (-1);
151 }
152 fcntl(s, F_SETOWN, pid);
153 sin.sin_family = hp->h_addrtype;
154 #if defined(ultrix) || defined(sun)
155 bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
156 #else
157 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length);
158 #endif
159 sin.sin_port = rport;
160 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
161 break;
162 (void) close(s);
163 if (errno == EADDRINUSE) {
164 lport--;
165 continue;
166 }
167 /*
168 * don't wait very long for Kerberos rcmd.
169 */
170 if (errno == ECONNREFUSED && timo <= 4) {
171 /* sleep(timo); don't wait at all here */
172 timo *= 2;
173 continue;
174 }
175 #if !(defined(ultrix) || defined(sun))
176 if (hp->h_addr_list[1] != NULL) {
177 int oerrno = errno;
178
179 fprintf(stderr,
180 "kcmd: connect to address %s: ",
181 inet_ntoa(sin.sin_addr));
182 errno = oerrno;
183 perror(NULL);
184 hp->h_addr_list++;
185 bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr,
186 hp->h_length);
187 fprintf(stderr, "Trying %s...\n",
188 inet_ntoa(sin.sin_addr));
189 continue;
190 }
191 #endif /* !(defined(ultrix) || defined(sun)) */
192 if (errno != ECONNREFUSED)
193 perror(hp->h_name);
194 sigsetmask(oldmask);
195 return (-1);
196 }
197 lport--;
198 if (fd2p == 0) {
199 write(s, "", 1);
200 lport = 0;
201 } else {
202 char num[8];
203 int s2 = getport(&lport), s3;
204 int len = sizeof(from);
205
206 if (s2 < 0) {
207 status = -1;
208 goto bad;
209 }
210 listen(s2, 1);
211 (void) sprintf(num, "%d", lport);
212 if (write(s, num, strlen(num) + 1) != strlen(num) + 1) {
213 perror("kcmd(write): setting up stderr");
214 (void) close(s2);
215 status = -1;
216 goto bad;
217 }
218 s3 = accept(s2, (struct sockaddr *)&from, &len);
219 (void) close(s2);
220 if (s3 < 0) {
221 perror("kcmd:accept");
222 lport = 0;
223 status = -1;
224 goto bad;
225 }
226 *fd2p = s3;
227 from.sin_port = ntohs((u_short)from.sin_port);
228 if (from.sin_family != AF_INET ||
229 from.sin_port >= IPPORT_RESERVED) {
230 fprintf(stderr,
231 "kcmd(socket): protocol failure in circuit setup.\n");
232 status = -1;
233 goto bad2;
234 }
235 }
236 /*
237 * Kerberos-authenticated service. Don't have to send locuser,
238 * since its already in the ticket, and we'll extract it on
239 * the other side.
240 */
241 /* (void) write(s, locuser, strlen(locuser)+1); */
242
243 /* set up the needed stuff for mutual auth, but only if necessary */
244 if (authopts & KOPT_DO_MUTUAL) {
245 int sin_len;
246 *faddr = sin;
247
248 sin_len = sizeof(struct sockaddr_in);
249 if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) {
250 perror("kcmd(getsockname)");
251 status = -1;
252 goto bad2;
253 }
254 }
255 #ifdef KERBEROS
256 if ((status = krb_sendauth(authopts, s, ticket, service, *ahost,
257 realm, (unsigned long) getpid(), msg_data,
258 cred, schedule,
259 laddr,
260 faddr,
261 "KCMDV0.1")) != KSUCCESS)
262 goto bad2;
263 #endif /* KERBEROS */
264
265 (void) write(s, remuser, strlen(remuser)+1);
266 (void) write(s, cmd, strlen(cmd)+1);
267
268 if ((rc = read(s, &c, 1)) != 1) {
269 if (rc == -1)
270 perror(*ahost);
271 else
272 fprintf(stderr,"kcmd: bad connection with remote host\n");
273 status = -1;
274 goto bad2;
275 }
276 if (c != '\0') {
277 while (read(s, &c, 1) == 1) {
278 (void) write(2, &c, 1);
279 if (c == '\n')
280 break;
281 }
282 status = -1;
283 goto bad2;
284 }
285 sigsetmask(oldmask);
286 *sock = s;
287 return (KSUCCESS);
288 bad2:
289 if (lport)
290 (void) close(*fd2p);
291 bad:
292 (void) close(s);
293 sigsetmask(oldmask);
294 return (status);
295 }
296
297 int
298 getport(alport)
299 int *alport;
300 {
301 struct sockaddr_in sin;
302 int s;
303
304 sin.sin_family = AF_INET;
305 sin.sin_addr.s_addr = INADDR_ANY;
306 s = socket(AF_INET, SOCK_STREAM, 0);
307 if (s < 0)
308 return (-1);
309 for (;;) {
310 sin.sin_port = htons((u_short)*alport);
311 if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
312 return (s);
313 if (errno != EADDRINUSE) {
314 (void) close(s);
315 return (-1);
316 }
317 (*alport)--;
318 #ifdef ATHENA_COMPAT
319 if (*alport == IPPORT_RESERVED/2) {
320 #else
321 if (*alport == IPPORT_RESERVED) {
322 #endif
323 (void) close(s);
324 errno = EAGAIN; /* close */
325 return (-1);
326 }
327 }
328 }
329
330 #endif /* !NeXT || KERBEROS */