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