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