28 |
*/ |
*/ |
29 |
|
|
30 |
#ifndef lint |
#ifndef lint |
31 |
static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88"; |
static char Xsccsid[] = "derived from @(#)rcmd.c 5.17 (Berkeley) 6/27/88"; |
32 |
static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93"; |
static char sccsid[] = "@(#)kcmd.c 8.2 (Berkeley) 8/19/93"; |
33 |
#endif /* not lint */ |
#endif /* not lint */ |
34 |
|
|
35 |
#ifdef HAVE_CONFIG_H |
#ifdef HAVE_CONFIG_H |
36 |
#include <config.h> |
#include <config.h> |
37 |
#endif |
#endif |
38 |
|
|
39 |
#ifdef KERBEROS |
#if defined(KERBEROS) || defined(SHISHI) |
40 |
|
|
41 |
#include <sys/param.h> |
#include <sys/param.h> |
42 |
#include <sys/file.h> |
#include <sys/file.h> |
46 |
#include <netinet/in.h> |
#include <netinet/in.h> |
47 |
#include <arpa/inet.h> |
#include <arpa/inet.h> |
48 |
|
|
49 |
#include <kerberosIV/des.h> |
#if defined(KERBEROS) |
50 |
#include <kerberosIV/krb.h> |
# include <kerberosIV/des.h> |
51 |
#include <kerberosIV/kparse.h> |
# include <kerberosIV/krb.h> |
52 |
|
#elif defined(SHISHI) |
53 |
|
# include <shishi.h> |
54 |
|
# include "shishi_def.h" |
55 |
|
#endif |
56 |
|
|
57 |
#include <ctype.h> |
#include <ctype.h> |
58 |
#include <errno.h> |
#include <errno.h> |
68 |
#define MAXHOSTNAMELEN 64 |
#define MAXHOSTNAMELEN 64 |
69 |
#endif |
#endif |
70 |
|
|
71 |
#define START_PORT 5120 /* arbitrary */ |
#define START_PORT 5120 /* arbitrary */ |
72 |
|
|
73 |
int getport __P((int *)); |
int getport __P ((int *)); |
74 |
|
|
75 |
|
#if defined (KERBEROS) |
76 |
int |
int |
77 |
kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm, |
kcmd (int *sock, char **ahost, u_short rport, char *locuser, |
78 |
cred, schedule, msg_data, laddr, faddr, authopts) |
char *remuser, char *cmd, int *fd2p, KTEXT ticket, |
79 |
int *sock; |
char *service, char *realm, |
80 |
char **ahost; |
CREDENTIALS * cred, Key_schedule schedule, MSG_DAT * msg_data, |
81 |
u_short rport; |
struct sockaddr_in *laddr, struct sockaddr_in *faddr, long authopts) |
82 |
char *locuser, *remuser, *cmd; |
#elif defined(SHISHI) |
83 |
int *fd2p; |
int |
84 |
KTEXT ticket; |
kcmd (Shishi ** h, int *sock, char **ahost, u_short rport, char *locuser, |
85 |
char *service; |
char **remuser, char *cmd, int *fd2p, char *service, char *realm, |
86 |
char *realm; |
Shishi_key ** key, |
87 |
CREDENTIALS *cred; |
struct sockaddr_in *laddr, struct sockaddr_in *faddr, long authopts) |
88 |
Key_schedule schedule; |
#endif |
|
MSG_DAT *msg_data; |
|
|
struct sockaddr_in *laddr, *faddr; |
|
|
long authopts; |
|
89 |
{ |
{ |
90 |
int s, timo = 1, pid; |
int s, timo = 1, pid; |
91 |
long oldmask; |
long oldmask; |
92 |
struct sockaddr_in sin, from; |
struct sockaddr_in sin, from; |
93 |
char c; |
char c; |
94 |
|
|
95 |
#ifdef ATHENA_COMPAT |
#ifdef ATHENA_COMPAT |
96 |
int lport = IPPORT_RESERVED - 1; |
int lport = IPPORT_RESERVED - 1; |
97 |
#else |
#else |
98 |
int lport = START_PORT; |
int lport = START_PORT; |
99 |
|
#endif |
100 |
|
struct hostent *hp; |
101 |
|
int rc; |
102 |
|
char *host_save; |
103 |
|
int status; |
104 |
|
|
105 |
|
#if defined(SHISHI) |
106 |
|
int zero = 0; |
107 |
#endif |
#endif |
|
struct hostent *hp; |
|
|
int rc; |
|
|
char *host_save; |
|
|
int status; |
|
|
|
|
|
pid = getpid(); |
|
|
hp = gethostbyname(*ahost); |
|
|
if (hp == NULL) { |
|
|
/* fprintf(stderr, "%s: unknown host\n", *ahost); */ |
|
|
return (-1); |
|
|
} |
|
108 |
|
|
109 |
host_save = malloc(strlen(hp->h_name) + 1); |
pid = getpid (); |
110 |
strcpy(host_save, hp->h_name); |
hp = gethostbyname (*ahost); |
111 |
*ahost = host_save; |
if (hp == NULL) |
112 |
|
{ |
113 |
|
/* fprintf(stderr, "%s: unknown host\n", *ahost); */ |
114 |
|
return (-1); |
115 |
|
} |
116 |
|
|
117 |
|
host_save = malloc (strlen (hp->h_name) + 1); |
118 |
|
strcpy (host_save, hp->h_name); |
119 |
|
*ahost = host_save; |
120 |
|
|
121 |
#ifdef KERBEROS |
#ifdef KERBEROS |
122 |
/* If realm is null, look up from table */ |
/* If realm is null, look up from table */ |
123 |
if (realm == NULL || realm[0] == '\0') |
if (realm == NULL || realm[0] == '\0') |
124 |
realm = krb_realmofhost(host_save); |
realm = krb_realmofhost (host_save); |
125 |
#endif /* KERBEROS */ |
#endif /* KERBEROS */ |
126 |
|
|
127 |
oldmask = sigblock(sigmask(SIGURG)); |
oldmask = sigblock (sigmask (SIGURG)); |
128 |
for (;;) { |
for (;;) |
129 |
s = getport(&lport); |
{ |
130 |
if (s < 0) { |
s = getport (&lport); |
131 |
if (errno == EAGAIN) |
if (s < 0) |
132 |
fprintf(stderr, |
{ |
133 |
"kcmd(socket): All ports in use\n"); |
if (errno == EAGAIN) |
134 |
else |
fprintf (stderr, "kcmd(socket): All ports in use\n"); |
135 |
perror("kcmd: socket"); |
else |
136 |
sigsetmask(oldmask); |
perror ("kcmd: socket"); |
137 |
return (-1); |
sigsetmask (oldmask); |
138 |
} |
return (-1); |
139 |
fcntl(s, F_SETOWN, pid); |
} |
140 |
sin.sin_family = hp->h_addrtype; |
fcntl (s, F_SETOWN, pid); |
141 |
|
sin.sin_family = hp->h_addrtype; |
142 |
#if defined(ultrix) || defined(sun) |
#if defined(ultrix) || defined(sun) |
143 |
bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length); |
bcopy (hp->h_addr, (caddr_t) & sin.sin_addr, hp->h_length); |
144 |
#else |
#else |
145 |
bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, hp->h_length); |
bcopy (hp->h_addr_list[0], (caddr_t) & sin.sin_addr, hp->h_length); |
146 |
#endif |
#endif |
147 |
sin.sin_port = rport; |
sin.sin_port = rport; |
|
if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) |
|
|
break; |
|
|
(void) close(s); |
|
|
if (errno == EADDRINUSE) { |
|
|
lport--; |
|
|
continue; |
|
|
} |
|
|
/* |
|
|
* don't wait very long for Kerberos rcmd. |
|
|
*/ |
|
|
if (errno == ECONNREFUSED && timo <= 4) { |
|
|
/* sleep(timo); don't wait at all here */ |
|
|
timo *= 2; |
|
|
continue; |
|
|
} |
|
|
#if !(defined(ultrix) || defined(sun)) |
|
|
if (hp->h_addr_list[1] != NULL) { |
|
|
int oerrno = errno; |
|
148 |
|
|
149 |
fprintf(stderr, |
if (connect (s, (struct sockaddr *) &sin, sizeof (sin)) >= 0) |
150 |
"kcmd: connect to address %s: ", |
break; |
151 |
inet_ntoa(sin.sin_addr)); |
close (s); |
152 |
errno = oerrno; |
if (errno == EADDRINUSE) |
153 |
perror(NULL); |
{ |
154 |
hp->h_addr_list++; |
lport--; |
155 |
bcopy(hp->h_addr_list[0], (caddr_t)&sin.sin_addr, |
continue; |
156 |
hp->h_length); |
} |
157 |
fprintf(stderr, "Trying %s...\n", |
/* |
158 |
inet_ntoa(sin.sin_addr)); |
* don't wait very long for Kerberos rcmd. |
159 |
continue; |
*/ |
160 |
} |
if (errno == ECONNREFUSED && timo <= 4) |
161 |
|
{ |
162 |
|
/* sleep(timo); don't wait at all here */ |
163 |
|
timo *= 2; |
164 |
|
continue; |
165 |
|
} |
166 |
|
#if !(defined(ultrix) || defined(sun)) |
167 |
|
if (hp->h_addr_list[1] != NULL) |
168 |
|
{ |
169 |
|
int oerrno = errno; |
170 |
|
|
171 |
|
fprintf (stderr, |
172 |
|
"kcmd: connect to address %s: ", inet_ntoa (sin.sin_addr)); |
173 |
|
errno = oerrno; |
174 |
|
perror (NULL); |
175 |
|
hp->h_addr_list++; |
176 |
|
bcopy (hp->h_addr_list[0], (caddr_t) & sin.sin_addr, hp->h_length); |
177 |
|
fprintf (stderr, "Trying %s...\n", inet_ntoa (sin.sin_addr)); |
178 |
|
continue; |
179 |
|
} |
180 |
#endif /* !(defined(ultrix) || defined(sun)) */ |
#endif /* !(defined(ultrix) || defined(sun)) */ |
181 |
if (errno != ECONNREFUSED) |
if (errno != ECONNREFUSED) |
182 |
perror(hp->h_name); |
perror (hp->h_name); |
183 |
sigsetmask(oldmask); |
sigsetmask (oldmask); |
184 |
return (-1); |
|
185 |
} |
return (-1); |
186 |
lport--; |
} |
187 |
if (fd2p == 0) { |
lport--; |
188 |
write(s, "", 1); |
if (fd2p == 0) |
189 |
lport = 0; |
{ |
190 |
} else { |
write (s, "", 1); |
191 |
char num[8]; |
lport = 0; |
192 |
int s2 = getport(&lport), s3; |
} |
193 |
int len = sizeof(from); |
else |
194 |
|
{ |
195 |
if (s2 < 0) { |
char num[8]; |
196 |
status = -1; |
int s2 = getport (&lport), s3; |
197 |
goto bad; |
int len = sizeof (from); |
198 |
} |
|
199 |
listen(s2, 1); |
if (s2 < 0) |
200 |
(void) sprintf(num, "%d", lport); |
{ |
201 |
if (write(s, num, strlen(num) + 1) != strlen(num) + 1) { |
status = -1; |
202 |
perror("kcmd(write): setting up stderr"); |
goto bad; |
203 |
(void) close(s2); |
} |
204 |
status = -1; |
listen (s2, 1); |
205 |
goto bad; |
sprintf (num, "%d", lport); |
206 |
} |
if (write (s, num, strlen (num) + 1) != strlen (num) + 1) |
207 |
s3 = accept(s2, (struct sockaddr *)&from, &len); |
{ |
208 |
(void) close(s2); |
perror ("kcmd(write): setting up stderr"); |
209 |
if (s3 < 0) { |
close (s2); |
210 |
perror("kcmd:accept"); |
status = -1; |
211 |
lport = 0; |
goto bad; |
|
status = -1; |
|
|
goto bad; |
|
|
} |
|
|
*fd2p = s3; |
|
|
from.sin_port = ntohs((u_short)from.sin_port); |
|
|
if (from.sin_family != AF_INET || |
|
|
from.sin_port >= IPPORT_RESERVED) { |
|
|
fprintf(stderr, |
|
|
"kcmd(socket): protocol failure in circuit setup.\n"); |
|
|
status = -1; |
|
|
goto bad2; |
|
|
} |
|
|
} |
|
|
/* |
|
|
* Kerberos-authenticated service. Don't have to send locuser, |
|
|
* since its already in the ticket, and we'll extract it on |
|
|
* the other side. |
|
|
*/ |
|
|
/* (void) write(s, locuser, strlen(locuser)+1); */ |
|
|
|
|
|
/* set up the needed stuff for mutual auth, but only if necessary */ |
|
|
if (authopts & KOPT_DO_MUTUAL) { |
|
|
int sin_len; |
|
|
*faddr = sin; |
|
|
|
|
|
sin_len = sizeof(struct sockaddr_in); |
|
|
if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) { |
|
|
perror("kcmd(getsockname)"); |
|
|
status = -1; |
|
|
goto bad2; |
|
|
} |
|
212 |
} |
} |
213 |
|
s3 = accept (s2, (struct sockaddr *) &from, &len); |
214 |
|
close (s2); |
215 |
|
if (s3 < 0) |
216 |
|
{ |
217 |
|
perror ("kcmd:accept"); |
218 |
|
lport = 0; |
219 |
|
status = -1; |
220 |
|
goto bad; |
221 |
|
} |
222 |
|
*fd2p = s3; |
223 |
|
from.sin_port = ntohs ((u_short) from.sin_port); |
224 |
|
if (from.sin_family != AF_INET || from.sin_port >= IPPORT_RESERVED) |
225 |
|
{ |
226 |
|
fprintf (stderr, |
227 |
|
"kcmd(socket): protocol failure in circuit setup.\n"); |
228 |
|
status = -1; |
229 |
|
goto bad2; |
230 |
|
} |
231 |
|
} |
232 |
|
/* |
233 |
|
* Kerberos-authenticated service. Don't have to send locuser, |
234 |
|
* since its already in the ticket, and we'll extract it on |
235 |
|
* the other side. |
236 |
|
*/ |
237 |
|
/* write(s, locuser, strlen(locuser)+1); */ |
238 |
|
|
239 |
|
/* set up the needed stuff for mutual auth, but only if necessary */ |
240 |
#ifdef KERBEROS |
#ifdef KERBEROS |
241 |
if ((status = krb_sendauth(authopts, s, ticket, service, *ahost, |
if (authopts & KOPT_DO_MUTUAL) |
242 |
realm, (unsigned long) getpid(), msg_data, |
{ |
243 |
cred, schedule, |
int sin_len; |
244 |
laddr, |
|
245 |
faddr, |
*faddr = sin; |
246 |
"KCMDV0.1")) != KSUCCESS) |
|
247 |
goto bad2; |
sin_len = sizeof (struct sockaddr_in); |
248 |
#endif /* KERBEROS */ |
if (getsockname (s, (struct sockaddr *) laddr, &sin_len) < 0) |
249 |
|
{ |
250 |
|
perror ("kcmd(getsockname)"); |
251 |
|
status = -1; |
252 |
|
goto bad2; |
253 |
|
} |
254 |
|
} |
255 |
|
|
256 |
|
if ((status = krb_sendauth (authopts, s, ticket, service, *ahost, |
257 |
|
realm, (unsigned long) getpid (), msg_data, |
258 |
|
cred, schedule, |
259 |
|
laddr, faddr, "KCMDV0.1")) != KSUCCESS) |
260 |
|
goto bad2; |
261 |
|
#elif defined(SHISHI) |
262 |
|
if (authopts & SHISHI_APOPTIONS_MUTUAL_REQUIRED) |
263 |
|
{ |
264 |
|
int sin_len; |
265 |
|
|
266 |
|
*faddr = sin; |
267 |
|
|
268 |
|
sin_len = sizeof (struct sockaddr_in); |
269 |
|
if (getsockname (s, (struct sockaddr *) laddr, &sin_len) < 0) |
270 |
|
{ |
271 |
|
perror ("kcmd(getsockname)"); |
272 |
|
status = -1; |
273 |
|
goto bad2; |
274 |
|
} |
275 |
|
} |
276 |
|
|
277 |
(void) write(s, remuser, strlen(remuser)+1); |
if ((status = |
278 |
(void) write(s, cmd, strlen(cmd)+1); |
shishi_auth (h, 0, remuser, *ahost, s, cmd, rport, key, |
279 |
|
realm)) != SHISHI_OK) |
280 |
|
goto bad2; |
281 |
|
|
282 |
if ((rc = read(s, &c, 1)) != 1) { |
#endif /* SHISHI */ |
283 |
if (rc == -1) |
|
284 |
perror(*ahost); |
write (s, *remuser, strlen (*remuser) + 1); |
285 |
else |
write (s, cmd, strlen (cmd) + 1); |
286 |
fprintf(stderr,"kcmd: bad connection with remote host\n"); |
|
287 |
status = -1; |
#ifdef SHISHI |
288 |
goto bad2; |
write (s, *remuser, strlen (*remuser) + 1); |
289 |
} |
write (s, &zero, sizeof (int)); |
290 |
if (c != '\0') { |
#endif |
291 |
while (read(s, &c, 1) == 1) { |
|
292 |
(void) write(2, &c, 1); |
if ((rc = read (s, &c, 1)) != 1) |
293 |
if (c == '\n') |
{ |
294 |
break; |
if (rc == -1) |
295 |
} |
perror (*ahost); |
296 |
status = -1; |
else |
297 |
goto bad2; |
fprintf (stderr, "kcmd: bad connection with remote host\n"); |
298 |
} |
status = -1; |
299 |
sigsetmask(oldmask); |
goto bad2; |
300 |
*sock = s; |
} |
301 |
return (KSUCCESS); |
if (c != '\0') |
302 |
|
{ |
303 |
|
while (read (s, &c, 1) == 1) |
304 |
|
{ |
305 |
|
write (2, &c, 1); |
306 |
|
if (c == '\n') |
307 |
|
break; |
308 |
|
} |
309 |
|
status = -1; |
310 |
|
goto bad2; |
311 |
|
} |
312 |
|
sigsetmask (oldmask); |
313 |
|
*sock = s; |
314 |
|
#if defined(KERBEROS) |
315 |
|
return (KSUCCESS); |
316 |
|
#elif defined(SHISHI) |
317 |
|
return (SHISHI_OK); |
318 |
|
#endif |
319 |
bad2: |
bad2: |
320 |
if (lport) |
if (lport) |
321 |
(void) close(*fd2p); |
close (*fd2p); |
322 |
bad: |
bad: |
323 |
(void) close(s); |
close (s); |
324 |
sigsetmask(oldmask); |
sigsetmask (oldmask); |
325 |
return (status); |
return (status); |
326 |
} |
} |
327 |
|
|
328 |
int |
int |
329 |
getport(alport) |
getport (int *alport) |
|
int *alport; |
|
330 |
{ |
{ |
331 |
struct sockaddr_in sin; |
struct sockaddr_in sin; |
332 |
int s; |
int s; |
333 |
|
|
334 |
sin.sin_family = AF_INET; |
sin.sin_family = AF_INET; |
335 |
sin.sin_addr.s_addr = INADDR_ANY; |
sin.sin_addr.s_addr = INADDR_ANY; |
336 |
s = socket(AF_INET, SOCK_STREAM, 0); |
s = socket (AF_INET, SOCK_STREAM, 0); |
337 |
if (s < 0) |
if (s < 0) |
338 |
return (-1); |
return (-1); |
339 |
for (;;) { |
for (;;) |
340 |
sin.sin_port = htons((u_short)*alport); |
{ |
341 |
if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0) |
sin.sin_port = htons ((u_short) * alport); |
342 |
return (s); |
if (bind (s, (struct sockaddr *) &sin, sizeof (sin)) >= 0) |
343 |
if (errno != EADDRINUSE) { |
return (s); |
344 |
(void) close(s); |
if (errno != EADDRINUSE) |
345 |
return (-1); |
{ |
346 |
} |
close (s); |
347 |
(*alport)--; |
return (-1); |
348 |
|
} |
349 |
|
(*alport)--; |
350 |
#ifdef ATHENA_COMPAT |
#ifdef ATHENA_COMPAT |
351 |
if (*alport == IPPORT_RESERVED/2) { |
if (*alport == IPPORT_RESERVED / 2) |
352 |
|
{ |
353 |
#else |
#else |
354 |
if (*alport == IPPORT_RESERVED) { |
if (*alport == IPPORT_RESERVED) |
355 |
|
{ |
356 |
#endif |
#endif |
357 |
(void) close(s); |
close (s); |
358 |
errno = EAGAIN; /* close */ |
errno = EAGAIN; /* close */ |
359 |
return (-1); |
return (-1); |
|
} |
|
360 |
} |
} |
361 |
|
} |
362 |
} |
} |
363 |
|
|
364 |
#endif /* KERBEROS */ |
#endif /* KERBEROS */ |