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