Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/appl/rsh/rsh.c
34869 views
1
/*
2
* Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
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.
16
*
17
* 3. Neither the name of the Institute 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 INSTITUTE 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 INSTITUTE 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.
32
*/
33
34
#include "rsh_locl.h"
35
RCSID("$Id$");
36
37
enum auth_method auth_method;
38
#if defined(KRB5)
39
int do_encrypt = -1;
40
#endif
41
#ifdef KRB5
42
int do_unique_tkfile = 0;
43
char *unique_tkfile = NULL;
44
char tkfile[MAXPATHLEN];
45
int do_forward = -1;
46
int do_forwardable = -1;
47
krb5_context context;
48
krb5_keyblock *keyblock;
49
krb5_crypto crypto;
50
#endif
51
int sock_debug = 0;
52
53
#ifdef KRB5
54
static int use_v5 = -1;
55
#endif
56
#if defined(KRB5)
57
static int use_only_broken = 0;
58
#else
59
static int use_only_broken = 1;
60
#endif
61
static int use_broken = 1;
62
static char *port_str;
63
static const char *user;
64
static int do_version;
65
static int do_help;
66
static int do_errsock = 1;
67
#ifdef KRB5
68
static char *protocol_version_str;
69
static int protocol_version = 2;
70
#endif
71
72
/*
73
*
74
*/
75
76
static int input = 1; /* Read from stdin */
77
78
static int
79
rsh_loop (int s, int errsock)
80
{
81
fd_set real_readset;
82
int count = 1;
83
84
#ifdef KRB5
85
if(auth_method == AUTH_KRB5 && protocol_version == 2)
86
init_ivecs(1, errsock != -1);
87
#endif
88
89
if (s >= FD_SETSIZE || (errsock != -1 && errsock >= FD_SETSIZE))
90
errx (1, "fd too large");
91
92
FD_ZERO(&real_readset);
93
FD_SET(s, &real_readset);
94
if (errsock != -1) {
95
FD_SET(errsock, &real_readset);
96
++count;
97
}
98
if(input)
99
FD_SET(STDIN_FILENO, &real_readset);
100
101
for (;;) {
102
int ret;
103
fd_set readset;
104
char buf[RSH_BUFSIZ];
105
106
readset = real_readset;
107
ret = select (max(s, errsock) + 1, &readset, NULL, NULL, NULL);
108
if (ret < 0) {
109
if (errno == EINTR)
110
continue;
111
else
112
err (1, "select");
113
}
114
if (FD_ISSET(s, &readset)) {
115
ret = do_read (s, buf, sizeof(buf), ivec_in[0]);
116
if (ret < 0)
117
err (1, "read");
118
else if (ret == 0) {
119
close (s);
120
FD_CLR(s, &real_readset);
121
if (--count == 0)
122
return 0;
123
} else
124
net_write (STDOUT_FILENO, buf, ret);
125
}
126
if (errsock != -1 && FD_ISSET(errsock, &readset)) {
127
ret = do_read (errsock, buf, sizeof(buf), ivec_in[1]);
128
if (ret < 0)
129
err (1, "read");
130
else if (ret == 0) {
131
close (errsock);
132
FD_CLR(errsock, &real_readset);
133
if (--count == 0)
134
return 0;
135
} else
136
net_write (STDERR_FILENO, buf, ret);
137
}
138
if (FD_ISSET(STDIN_FILENO, &readset)) {
139
ret = read (STDIN_FILENO, buf, sizeof(buf));
140
if (ret < 0)
141
err (1, "read");
142
else if (ret == 0) {
143
close (STDIN_FILENO);
144
FD_CLR(STDIN_FILENO, &real_readset);
145
shutdown (s, SHUT_WR);
146
} else
147
do_write (s, buf, ret, ivec_out[0]);
148
}
149
}
150
}
151
152
#ifdef KRB5
153
/*
154
* Send forward information on `s' for host `hostname', them being
155
* forwardable themselves if `forwardable'
156
*/
157
158
static int
159
krb5_forward_cred (krb5_auth_context auth_context,
160
int s,
161
const char *hostname,
162
int forwardable)
163
{
164
krb5_error_code ret;
165
krb5_ccache ccache;
166
krb5_creds creds;
167
krb5_kdc_flags flags;
168
krb5_data out_data;
169
krb5_principal principal;
170
171
memset (&creds, 0, sizeof(creds));
172
173
ret = krb5_cc_default (context, &ccache);
174
if (ret) {
175
warnx ("could not forward creds: krb5_cc_default: %s",
176
krb5_get_err_text (context, ret));
177
return 1;
178
}
179
180
ret = krb5_cc_get_principal (context, ccache, &principal);
181
if (ret) {
182
warnx ("could not forward creds: krb5_cc_get_principal: %s",
183
krb5_get_err_text (context, ret));
184
return 1;
185
}
186
187
creds.client = principal;
188
189
ret = krb5_make_principal(context,
190
&creds.server,
191
principal->realm,
192
"krbtgt",
193
principal->realm,
194
NULL);
195
196
if (ret) {
197
warnx ("could not forward creds: krb5_make_principal: %s",
198
krb5_get_err_text (context, ret));
199
return 1;
200
}
201
202
creds.times.endtime = 0;
203
204
flags.i = 0;
205
flags.b.forwarded = 1;
206
flags.b.forwardable = forwardable;
207
208
ret = krb5_get_forwarded_creds (context,
209
auth_context,
210
ccache,
211
flags.i,
212
hostname,
213
&creds,
214
&out_data);
215
if (ret) {
216
warnx ("could not forward creds: krb5_get_forwarded_creds: %s",
217
krb5_get_err_text (context, ret));
218
return 1;
219
}
220
221
ret = krb5_write_message (context,
222
(void *)&s,
223
&out_data);
224
krb5_data_free (&out_data);
225
226
if (ret)
227
warnx ("could not forward creds: krb5_write_message: %s",
228
krb5_get_err_text (context, ret));
229
return 0;
230
}
231
232
static int sendauth_version_error;
233
234
static int
235
send_krb5_auth(int s,
236
struct sockaddr *thisaddr,
237
struct sockaddr *thataddr,
238
const char *hostname,
239
const char *remote_user,
240
const char *local_user,
241
size_t cmd_len,
242
const char *cmd)
243
{
244
krb5_principal server;
245
krb5_data cksum_data;
246
int status;
247
size_t len;
248
krb5_auth_context auth_context = NULL;
249
const char *protocol_string = NULL;
250
krb5_flags ap_opts;
251
char *str;
252
253
status = krb5_sname_to_principal(context,
254
hostname,
255
"host",
256
KRB5_NT_SRV_HST,
257
&server);
258
if (status) {
259
warnx ("%s: %s", hostname, krb5_get_err_text(context, status));
260
return 1;
261
}
262
263
if(do_encrypt == -1) {
264
krb5_appdefault_boolean(context, NULL,
265
krb5_principal_get_realm(context, server),
266
"encrypt",
267
FALSE,
268
&do_encrypt);
269
}
270
271
cksum_data.length = asprintf (&str,
272
"%u:%s%s%s",
273
ntohs(socket_get_port(thataddr)),
274
do_encrypt ? "-x " : "",
275
cmd,
276
remote_user);
277
if (str == NULL) {
278
warnx ("%s: failed to allocate command", hostname);
279
return 1;
280
}
281
cksum_data.data = str;
282
283
ap_opts = 0;
284
285
if(do_encrypt)
286
ap_opts |= AP_OPTS_MUTUAL_REQUIRED;
287
288
switch(protocol_version) {
289
case 2:
290
ap_opts |= AP_OPTS_USE_SUBKEY;
291
protocol_string = KCMD_NEW_VERSION;
292
break;
293
case 1:
294
protocol_string = KCMD_OLD_VERSION;
295
key_usage = KRB5_KU_OTHER_ENCRYPTED;
296
break;
297
default:
298
abort();
299
}
300
301
status = krb5_sendauth (context,
302
&auth_context,
303
&s,
304
protocol_string,
305
NULL,
306
server,
307
ap_opts,
308
&cksum_data,
309
NULL,
310
NULL,
311
NULL,
312
NULL,
313
NULL);
314
315
/* do this while we have a principal */
316
if(do_forward == -1 || do_forwardable == -1) {
317
krb5_const_realm realm = krb5_principal_get_realm(context, server);
318
if (do_forwardable == -1)
319
krb5_appdefault_boolean(context, NULL, realm,
320
"forwardable", FALSE,
321
&do_forwardable);
322
if (do_forward == -1)
323
krb5_appdefault_boolean(context, NULL, realm,
324
"forward", FALSE,
325
&do_forward);
326
}
327
328
krb5_free_principal(context, server);
329
krb5_data_free(&cksum_data);
330
331
if (status) {
332
if(status == KRB5_SENDAUTH_REJECTED &&
333
protocol_version == 2 && protocol_version_str == NULL)
334
sendauth_version_error = 1;
335
else
336
krb5_warn(context, status, "%s", hostname);
337
return 1;
338
}
339
340
status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock);
341
if(keyblock == NULL)
342
status = krb5_auth_con_getkey (context, auth_context, &keyblock);
343
if (status) {
344
warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status));
345
return 1;
346
}
347
348
status = krb5_auth_con_setaddrs_from_fd (context,
349
auth_context,
350
&s);
351
if (status) {
352
warnx("krb5_auth_con_setaddrs_from_fd: %s",
353
krb5_get_err_text(context, status));
354
return(1);
355
}
356
357
status = krb5_crypto_init(context, keyblock, 0, &crypto);
358
if(status) {
359
warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status));
360
return 1;
361
}
362
363
len = strlen(remote_user) + 1;
364
if (net_write (s, remote_user, len) != len) {
365
warn ("write");
366
return 1;
367
}
368
if (do_encrypt && net_write (s, "-x ", 3) != 3) {
369
warn ("write");
370
return 1;
371
}
372
if (net_write (s, cmd, cmd_len) != cmd_len) {
373
warn ("write");
374
return 1;
375
}
376
377
if (do_unique_tkfile) {
378
if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) {
379
warn ("write");
380
return 1;
381
}
382
}
383
len = strlen(local_user) + 1;
384
if (net_write (s, local_user, len) != len) {
385
warn ("write");
386
return 1;
387
}
388
389
if (!do_forward
390
|| krb5_forward_cred (auth_context, s, hostname, do_forwardable)) {
391
/* Empty forwarding info */
392
393
u_char zero[4] = {0, 0, 0, 0};
394
write (s, &zero, 4);
395
}
396
krb5_auth_con_free (context, auth_context);
397
return 0;
398
}
399
400
#endif /* KRB5 */
401
402
static int
403
send_broken_auth(int s,
404
struct sockaddr *thisaddr,
405
struct sockaddr *thataddr,
406
const char *hostname,
407
const char *remote_user,
408
const char *local_user,
409
size_t cmd_len,
410
const char *cmd)
411
{
412
size_t len;
413
414
len = strlen(local_user) + 1;
415
if (net_write (s, local_user, len) != len) {
416
warn ("write");
417
return 1;
418
}
419
len = strlen(remote_user) + 1;
420
if (net_write (s, remote_user, len) != len) {
421
warn ("write");
422
return 1;
423
}
424
if (net_write (s, cmd, cmd_len) != cmd_len) {
425
warn ("write");
426
return 1;
427
}
428
return 0;
429
}
430
431
static int
432
proto (int s, int errsock,
433
const char *hostname, const char *local_user, const char *remote_user,
434
const char *cmd, size_t cmd_len,
435
int (*auth_func)(int s,
436
struct sockaddr *this, struct sockaddr *that,
437
const char *hostname, const char *remote_user,
438
const char *local_user, size_t cmd_len,
439
const char *cmd))
440
{
441
int errsock2;
442
char buf[BUFSIZ];
443
char *p;
444
size_t len;
445
char reply;
446
struct sockaddr_storage thisaddr_ss;
447
struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss;
448
struct sockaddr_storage thataddr_ss;
449
struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss;
450
struct sockaddr_storage erraddr_ss;
451
struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss;
452
socklen_t addrlen;
453
int ret;
454
455
addrlen = sizeof(thisaddr_ss);
456
if (getsockname (s, thisaddr, &addrlen) < 0) {
457
warn ("getsockname(%s)", hostname);
458
return 1;
459
}
460
addrlen = sizeof(thataddr_ss);
461
if (getpeername (s, thataddr, &addrlen) < 0) {
462
warn ("getpeername(%s)", hostname);
463
return 1;
464
}
465
466
if (errsock != -1) {
467
468
addrlen = sizeof(erraddr_ss);
469
if (getsockname (errsock, erraddr, &addrlen) < 0) {
470
warn ("getsockname");
471
return 1;
472
}
473
474
if (listen (errsock, 1) < 0) {
475
warn ("listen");
476
return 1;
477
}
478
479
p = buf;
480
snprintf (p, sizeof(buf), "%u",
481
ntohs(socket_get_port(erraddr)));
482
len = strlen(buf) + 1;
483
if(net_write (s, buf, len) != len) {
484
warn ("write");
485
close (errsock);
486
return 1;
487
}
488
489
490
for (;;) {
491
fd_set fdset;
492
493
if (errsock >= FD_SETSIZE || s >= FD_SETSIZE)
494
errx (1, "fd too large");
495
496
FD_ZERO(&fdset);
497
FD_SET(errsock, &fdset);
498
FD_SET(s, &fdset);
499
500
ret = select (max(errsock, s) + 1, &fdset, NULL, NULL, NULL);
501
if (ret < 0) {
502
if (errno == EINTR)
503
continue;
504
warn ("select");
505
close (errsock);
506
return 1;
507
}
508
if (FD_ISSET(errsock, &fdset)) {
509
errsock2 = accept (errsock, NULL, NULL);
510
close (errsock);
511
if (errsock2 < 0) {
512
warn ("accept");
513
return 1;
514
}
515
break;
516
}
517
518
/*
519
* there should not arrive any data on this fd so if it's
520
* readable it probably indicates that the other side when
521
* away.
522
*/
523
524
if (FD_ISSET(s, &fdset)) {
525
warnx ("socket closed");
526
close (errsock);
527
errsock2 = -1;
528
break;
529
}
530
}
531
} else {
532
if (net_write (s, "0", 2) != 2) {
533
warn ("write");
534
return 1;
535
}
536
errsock2 = -1;
537
}
538
539
if ((*auth_func)(s, thisaddr, thataddr, hostname,
540
remote_user, local_user,
541
cmd_len, cmd)) {
542
close (errsock2);
543
return 1;
544
}
545
546
ret = net_read (s, &reply, 1);
547
if (ret < 0) {
548
warn ("read");
549
close (errsock2);
550
return 1;
551
} else if (ret == 0) {
552
warnx ("unexpected EOF from %s", hostname);
553
close (errsock2);
554
return 1;
555
}
556
if (reply != 0) {
557
558
warnx ("Error from rshd at %s:", hostname);
559
560
while ((ret = read (s, buf, sizeof(buf))) > 0)
561
write (STDOUT_FILENO, buf, ret);
562
write (STDOUT_FILENO,"\n",1);
563
close (errsock2);
564
return 1;
565
}
566
567
if (sock_debug) {
568
int one = 1;
569
if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(one)) < 0)
570
warn("setsockopt remote");
571
if (errsock2 != -1 &&
572
setsockopt(errsock2, SOL_SOCKET, SO_DEBUG,
573
(void *)&one, sizeof(one)) < 0)
574
warn("setsockopt stderr");
575
}
576
577
return rsh_loop (s, errsock2);
578
}
579
580
/*
581
* Return in `res' a copy of the concatenation of `argc, argv' into
582
* malloced space. */
583
584
static size_t
585
construct_command (char **res, int argc, char **argv)
586
{
587
int i;
588
size_t len = 0;
589
char *tmp;
590
591
for (i = 0; i < argc; ++i)
592
len += strlen(argv[i]) + 1;
593
len = max (1, len);
594
tmp = malloc (len);
595
if (tmp == NULL)
596
errx (1, "malloc %lu failed", (unsigned long)len);
597
598
*tmp = '\0';
599
for (i = 0; i < argc - 1; ++i) {
600
strlcat (tmp, argv[i], len);
601
strlcat (tmp, " ", len);
602
}
603
if (argc > 0)
604
strlcat (tmp, argv[argc-1], len);
605
*res = tmp;
606
return len;
607
}
608
609
static char *
610
print_addr (const struct sockaddr *sa)
611
{
612
char addr_str[256];
613
char *res;
614
const char *as = NULL;
615
616
if(sa->sa_family == AF_INET)
617
as = inet_ntop (sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr,
618
addr_str, sizeof(addr_str));
619
#ifdef HAVE_INET6
620
else if(sa->sa_family == AF_INET6)
621
as = inet_ntop (sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr,
622
addr_str, sizeof(addr_str));
623
#endif
624
if(as == NULL)
625
return NULL;
626
res = strdup(as);
627
if (res == NULL)
628
errx (1, "malloc: out of memory");
629
return res;
630
}
631
632
static int
633
doit_broken (int argc,
634
char **argv,
635
int hostindex,
636
struct addrinfo *ai,
637
const char *remote_user,
638
const char *local_user,
639
int priv_socket1,
640
int priv_socket2,
641
const char *cmd,
642
size_t cmd_len)
643
{
644
struct addrinfo *a;
645
646
if (connect (priv_socket1, ai->ai_addr, ai->ai_addrlen) < 0) {
647
int save_errno = errno;
648
649
close(priv_socket1);
650
close(priv_socket2);
651
652
for (a = ai->ai_next; a != NULL; a = a->ai_next) {
653
pid_t pid;
654
char *adr = print_addr(a->ai_addr);
655
if(adr == NULL)
656
continue;
657
658
pid = fork();
659
if (pid < 0)
660
err (1, "fork");
661
else if(pid == 0) {
662
char **new_argv;
663
int i = 0;
664
665
new_argv = malloc((argc + 2) * sizeof(*new_argv));
666
if (new_argv == NULL)
667
errx (1, "malloc: out of memory");
668
new_argv[i] = argv[i];
669
++i;
670
if (hostindex == i)
671
new_argv[i++] = adr;
672
new_argv[i++] = "-K";
673
for(; i <= argc; ++i)
674
new_argv[i] = argv[i - 1];
675
if (hostindex > 1)
676
new_argv[hostindex + 1] = adr;
677
new_argv[argc + 1] = NULL;
678
execv(PATH_RSH, new_argv);
679
err(1, "execv(%s)", PATH_RSH);
680
} else {
681
int status;
682
free(adr);
683
684
while(waitpid(pid, &status, 0) < 0)
685
;
686
if(WIFEXITED(status) && WEXITSTATUS(status) == 0)
687
return 0;
688
}
689
}
690
errno = save_errno;
691
warn("%s", argv[hostindex]);
692
return 1;
693
} else {
694
int ret;
695
696
ret = proto (priv_socket1, priv_socket2,
697
argv[hostindex],
698
local_user, remote_user,
699
cmd, cmd_len,
700
send_broken_auth);
701
return ret;
702
}
703
}
704
705
#if defined(KRB5)
706
static int
707
doit (const char *hostname,
708
struct addrinfo *ai,
709
const char *remote_user,
710
const char *local_user,
711
const char *cmd,
712
size_t cmd_len,
713
int (*auth_func)(int s,
714
struct sockaddr *this, struct sockaddr *that,
715
const char *hostname, const char *remote_user,
716
const char *local_user, size_t cmd_len,
717
const char *cmd))
718
{
719
int error;
720
struct addrinfo *a;
721
int socketfailed = 1;
722
int ret;
723
724
for (a = ai; a != NULL; a = a->ai_next) {
725
int s;
726
int errsock;
727
728
s = socket (a->ai_family, a->ai_socktype, a->ai_protocol);
729
if (s < 0)
730
continue;
731
socketfailed = 0;
732
if (connect (s, a->ai_addr, a->ai_addrlen) < 0) {
733
char addr[128];
734
if(getnameinfo(a->ai_addr, a->ai_addrlen,
735
addr, sizeof(addr), NULL, 0, NI_NUMERICHOST) == 0)
736
warn ("connect(%s [%s])", hostname, addr);
737
else
738
warn ("connect(%s)", hostname);
739
close (s);
740
continue;
741
}
742
if (do_errsock) {
743
struct addrinfo *ea, *eai;
744
struct addrinfo hints;
745
746
memset (&hints, 0, sizeof(hints));
747
hints.ai_socktype = a->ai_socktype;
748
hints.ai_protocol = a->ai_protocol;
749
hints.ai_family = a->ai_family;
750
hints.ai_flags = AI_PASSIVE;
751
752
errsock = -1;
753
754
error = getaddrinfo (NULL, "0", &hints, &eai);
755
if (error)
756
errx (1, "getaddrinfo: %s", gai_strerror(error));
757
for (ea = eai; ea != NULL; ea = ea->ai_next) {
758
errsock = socket (ea->ai_family, ea->ai_socktype,
759
ea->ai_protocol);
760
if (errsock < 0)
761
continue;
762
if (bind (errsock, ea->ai_addr, ea->ai_addrlen) < 0)
763
err (1, "bind");
764
break;
765
}
766
if (errsock < 0)
767
err (1, "socket");
768
freeaddrinfo (eai);
769
} else
770
errsock = -1;
771
772
ret = proto (s, errsock,
773
hostname,
774
local_user, remote_user,
775
cmd, cmd_len, auth_func);
776
close (s);
777
return ret;
778
}
779
if(socketfailed)
780
warnx ("failed to contact %s", hostname);
781
return -1;
782
}
783
#endif /* KRB5 */
784
785
struct getargs args[] = {
786
#ifdef KRB5
787
{ "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5" },
788
{ "forward", 'f', arg_flag, &do_forward, "Forward credentials [krb5]"},
789
{ "forwardable", 'F', arg_flag, &do_forwardable,
790
"Forward forwardable credentials [krb5]" },
791
{ NULL, 'G', arg_negative_flag,&do_forward, "Don't forward credentials" },
792
{ "unique", 'u', arg_flag, &do_unique_tkfile,
793
"Use unique remote credentials cache [krb5]" },
794
{ "tkfile", 'U', arg_string, &unique_tkfile,
795
"Specifies remote credentials cache [krb5]" },
796
{ "protocol", 'P', arg_string, &protocol_version_str,
797
"Protocol version [krb5]", "protocol" },
798
#endif
799
{ "broken", 'K', arg_flag, &use_only_broken, "Use only priv port" },
800
#if defined(KRB5)
801
{ "encrypt", 'x', arg_flag, &do_encrypt, "Encrypt connection" },
802
{ NULL, 'z', arg_negative_flag, &do_encrypt,
803
"Don't encrypt connection", NULL },
804
#endif
805
{ NULL, 'd', arg_flag, &sock_debug, "Enable socket debugging" },
806
{ "input", 'n', arg_negative_flag, &input, "Close stdin" },
807
{ "port", 'p', arg_string, &port_str, "Use this port",
808
"port" },
809
{ "user", 'l', arg_string, &user, "Run as this user", "login" },
810
{ "stderr", 'e', arg_negative_flag, &do_errsock, "Don't open stderr"},
811
#ifdef KRB5
812
#endif
813
{ "version", 0, arg_flag, &do_version, NULL },
814
{ "help", 0, arg_flag, &do_help, NULL }
815
};
816
817
static void
818
usage (int ret)
819
{
820
arg_printusage (args,
821
sizeof(args) / sizeof(args[0]),
822
NULL,
823
"[login@]host [command]");
824
exit (ret);
825
}
826
827
/*
828
*
829
*/
830
831
int
832
main(int argc, char **argv)
833
{
834
int priv_port1, priv_port2;
835
int priv_socket1, priv_socket2;
836
int argindex = 0;
837
int error;
838
struct addrinfo hints, *ai;
839
int ret = 1;
840
char *cmd;
841
char *tmp;
842
size_t cmd_len;
843
const char *local_user;
844
char *host = NULL;
845
int host_index = -1;
846
#ifdef KRB5
847
int status;
848
#endif
849
uid_t uid;
850
851
priv_port1 = priv_port2 = IPPORT_RESERVED-1;
852
priv_socket1 = rresvport(&priv_port1);
853
priv_socket2 = rresvport(&priv_port2);
854
uid = getuid ();
855
if (setuid (uid) || (uid != 0 && setuid(0) == 0))
856
err (1, "setuid");
857
858
setprogname (argv[0]);
859
860
if (argc >= 2 && argv[1][0] != '-') {
861
host = argv[host_index = 1];
862
argindex = 1;
863
}
864
865
if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv,
866
&argindex))
867
usage (1);
868
869
if (do_help)
870
usage (0);
871
872
if (do_version) {
873
print_version (NULL);
874
return 0;
875
}
876
877
#ifdef KRB5
878
if(protocol_version_str != NULL) {
879
if(strcasecmp(protocol_version_str, "N") == 0)
880
protocol_version = 2;
881
else if(strcasecmp(protocol_version_str, "O") == 0)
882
protocol_version = 1;
883
else {
884
char *end;
885
int v;
886
v = strtol(protocol_version_str, &end, 0);
887
if(*end != '\0' || (v != 1 && v != 2)) {
888
errx(1, "unknown protocol version \"%s\"",
889
protocol_version_str);
890
}
891
protocol_version = v;
892
}
893
}
894
895
status = krb5_init_context (&context);
896
if (status) {
897
if(use_v5 == 1)
898
errx(1, "krb5_init_context failed: %d", status);
899
else
900
use_v5 = 0;
901
}
902
903
/* request for forwardable on the command line means we should
904
also forward */
905
if (do_forwardable == 1)
906
do_forward = 1;
907
908
#endif
909
910
if (use_only_broken) {
911
#ifdef KRB5
912
use_v5 = 0;
913
#endif
914
}
915
916
if(priv_socket1 < 0) {
917
if (use_only_broken)
918
errx (1, "unable to bind reserved port: is rsh setuid root?");
919
use_broken = 0;
920
}
921
922
#if defined(KRB5)
923
if (do_encrypt == 1 && use_only_broken)
924
errx (1, "encryption not supported with old style authentication");
925
#endif
926
927
928
929
#ifdef KRB5
930
if (do_unique_tkfile && unique_tkfile != NULL)
931
errx (1, "Only one of -u and -U allowed.");
932
933
if (do_unique_tkfile)
934
strlcpy(tkfile,"-u ", sizeof(tkfile));
935
else if (unique_tkfile != NULL) {
936
if (strchr(unique_tkfile,' ') != NULL) {
937
warnx("Space is not allowed in tkfilename");
938
usage(1);
939
}
940
do_unique_tkfile = 1;
941
snprintf (tkfile, sizeof(tkfile), "-U %s ", unique_tkfile);
942
}
943
#endif
944
945
if (host == NULL) {
946
if (argc - argindex < 1)
947
usage (1);
948
else
949
host = argv[host_index = argindex++];
950
}
951
952
if((tmp = strchr(host, '@')) != NULL) {
953
*tmp++ = '\0';
954
user = host;
955
host = tmp;
956
}
957
958
if (argindex == argc) {
959
close (priv_socket1);
960
close (priv_socket2);
961
argv[0] = "rlogin";
962
execvp ("rlogin", argv);
963
err (1, "execvp rlogin");
964
}
965
966
local_user = get_default_username ();
967
if (local_user == NULL)
968
errx (1, "who are you?");
969
970
if (user == NULL)
971
user = local_user;
972
973
cmd_len = construct_command(&cmd, argc - argindex, argv + argindex);
974
975
/*
976
* Try all different authentication methods
977
*/
978
979
#ifdef KRB5
980
if (ret && use_v5) {
981
memset (&hints, 0, sizeof(hints));
982
hints.ai_socktype = SOCK_STREAM;
983
hints.ai_protocol = IPPROTO_TCP;
984
985
if(port_str == NULL) {
986
error = getaddrinfo(host, "kshell", &hints, &ai);
987
if(error == EAI_NONAME)
988
error = getaddrinfo(host, "544", &hints, &ai);
989
} else
990
error = getaddrinfo(host, port_str, &hints, &ai);
991
992
if(error)
993
errx (1, "getaddrinfo: %s", gai_strerror(error));
994
995
auth_method = AUTH_KRB5;
996
again:
997
ret = doit (host, ai, user, local_user, cmd, cmd_len,
998
send_krb5_auth);
999
if(ret != 0 && sendauth_version_error &&
1000
protocol_version == 2) {
1001
protocol_version = 1;
1002
goto again;
1003
}
1004
freeaddrinfo(ai);
1005
}
1006
#endif
1007
if (ret && use_broken) {
1008
memset (&hints, 0, sizeof(hints));
1009
hints.ai_socktype = SOCK_STREAM;
1010
hints.ai_protocol = IPPROTO_TCP;
1011
1012
if(port_str == NULL) {
1013
error = getaddrinfo(host, "shell", &hints, &ai);
1014
if(error == EAI_NONAME)
1015
error = getaddrinfo(host, "514", &hints, &ai);
1016
} else
1017
error = getaddrinfo(host, port_str, &hints, &ai);
1018
1019
if(error)
1020
errx (1, "getaddrinfo: %s", gai_strerror(error));
1021
1022
auth_method = AUTH_BROKEN;
1023
ret = doit_broken (argc, argv, host_index, ai,
1024
user, local_user,
1025
priv_socket1,
1026
do_errsock ? priv_socket2 : -1,
1027
cmd, cmd_len);
1028
freeaddrinfo(ai);
1029
}
1030
free(cmd);
1031
return ret;
1032
}
1033
1034