1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright (c) 1983 Regents of the University of California.
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms are permitted
11 * provided that the above copyright notice and this paragraph are
12 * duplicated in all such forms and that any documentation,
13 * advertising materials, and other materials related to such
14 * distribution and use acknowledge that the software was developed
15 * by the University of California, Berkeley. The name of the
16 * University may not be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 */
19
20 #include "defs.h"
21 #include <string.h>
22 #include <syslog.h>
23 #include <k5-int.h>
24 #include <krb5defs.h>
25 #include <priv_utils.h>
26
27 #define NHOSTS 100
28
29 /*
30 * Remote distribution program.
31 */
32
33 char *distfile = NULL;
34 char Tmpfile[] = "/tmp/rdistXXXXXX";
35 char *tmpname = &Tmpfile[5];
36
37 int debug; /* debugging flag */
38 int nflag; /* NOP flag, just print commands without executing */
39 int qflag; /* Quiet. Don't print messages */
40 int options; /* global options */
41 int iamremote; /* act as remote server for transfering files */
42
43 FILE *fin = NULL; /* input file pointer */
44 int rem = -1; /* file descriptor to remote source/sink process */
45 char host[32]; /* host name */
46 int nerrs; /* number of errors while sending/receiving */
47 char user[10]; /* user's name */
48 char homedir[128]; /* user's home directory */
49 char buf[RDIST_BUFSIZ]; /* general purpose buffer */
50
51 struct passwd *pw; /* pointer to static area used by getpwent */
52 struct group *gr; /* pointer to static area used by getgrent */
53
54 char des_inbuf[2 * RDIST_BUFSIZ]; /* needs to be > largest read size */
55 char des_outbuf[2 * RDIST_BUFSIZ]; /* needs to be > largest write size */
56 krb5_data desinbuf, desoutbuf;
57 krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */
58 krb5_context bsd_context = NULL;
59 krb5_auth_context auth_context;
60 krb5_creds *cred;
61 char *krb_cache = NULL;
62 krb5_flags authopts;
63 krb5_error_code status;
64 enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL;
65
66 int encrypt_flag = 0; /* Flag set when encryption is used */
67 int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */
68 static profile_options_boolean autologin_option[] = {
69 { "autologin", &krb5auth_flag, 0 },
70 { NULL, NULL, 0 }
71 };
72 static int no_krb5auth_flag = 0;
73
74 int debug_port = 0;
75
76 int retval = 0;
77 char *krb_realm = NULL;
78
79 /* Flag set, if -PN / -PO is specified */
80 static boolean_t rcmdoption_done = B_FALSE;
81
82 static int encrypt_done = 0; /* Flag set, if -x is specified */
83 profile_options_boolean option[] = {
84 { "encrypt", &encrypt_flag, 0 },
85 { NULL, NULL, 0 }
86 };
87
88 static char *rcmdproto = NULL;
89 profile_option_strings rcmdversion[] = {
90 { "rcmd_protocol", &rcmdproto, 0 },
91 { NULL, NULL, 0 }
92 };
93
94 char *realmdef[] = { "realms", NULL, "rdist", NULL };
95 char *appdef[] = { "appdefaults", "rdist", NULL };
96
97 static void usage(void);
98 static char *prtype(int t);
99 static void prsubcmd(struct subcmd *s);
100 static void docmdargs(int nargs, char *args[]);
101 void prnames();
102 void prcmd();
103
104 int
main(argc,argv)105 main(argc, argv)
106 int argc;
107 char *argv[];
108 {
109 register char *arg;
110 int cmdargs = 0;
111 char *dhosts[NHOSTS], **hp = dhosts;
112
113 (void) setlocale(LC_ALL, "");
114
115 pw = getpwuid(getuid());
116 if (pw == NULL) {
117 (void) fprintf(stderr, gettext("%s: Who are you?\n"), argv[0]);
118 exit(1);
119 }
120 strncpy(user, pw->pw_name, sizeof (user));
121 user[sizeof (user) - 1] = '\0';
122 strncpy(homedir, pw->pw_dir, sizeof (homedir));
123 homedir[sizeof (homedir) - 1] = '\0';
124 gethostname(host, sizeof (host));
125
126 while (--argc > 0) {
127 if ((arg = *++argv)[0] != '-')
128 break;
129 if ((strcmp(arg, "-Server") == 0))
130 iamremote++;
131 else while (*++arg) {
132 if (strncmp(*argv, "-PO", 3) == 0) {
133 if (rcmdoption_done == B_TRUE) {
134 (void) fprintf(stderr, gettext("rdist: "
135 "Only one of -PN "
136 "and -PO allowed.\n"));
137 usage();
138 }
139 kcmd_proto = KCMD_OLD_PROTOCOL;
140 krb5auth_flag++;
141 rcmdoption_done = B_TRUE;
142 break;
143 }
144 if (strncmp(*argv, "-PN", 3) == 0) {
145 if (rcmdoption_done == B_TRUE) {
146 (void) fprintf(stderr, gettext("rdist: "
147 "Only one of -PN "
148 "and -PO allowed.\n"));
149 usage();
150 }
151 kcmd_proto = KCMD_NEW_PROTOCOL;
152 krb5auth_flag++;
153 rcmdoption_done = B_TRUE;
154 break;
155 }
156
157 switch (*arg) {
158 #ifdef DEBUG
159 case 'p':
160 if (--argc <= 0)
161 usage();
162 debug_port = htons(atoi(*++argv));
163 break;
164 #endif /* DEBUG */
165 case 'k':
166 if (--argc <= 0) {
167 (void) fprintf(stderr, gettext("rdist: "
168 "-k flag must be followed with "
169 " a realm name.\n"));
170 exit(1);
171 }
172 if ((krb_realm = strdup(*++argv)) == NULL) {
173 (void) fprintf(stderr, gettext("rdist: "
174 "Cannot malloc.\n"));
175 exit(1);
176 }
177 krb5auth_flag++;
178 break;
179
180 case 'K':
181 no_krb5auth_flag++;
182 break;
183
184 case 'a':
185 krb5auth_flag++;
186 break;
187
188 case 'x':
189 encrypt_flag++;
190 encrypt_done++;
191 krb5auth_flag++;
192 break;
193
194 case 'f':
195 if (--argc <= 0)
196 usage();
197 distfile = *++argv;
198 if (distfile[0] == '-' && distfile[1] == '\0')
199 fin = stdin;
200 break;
201
202 case 'm':
203 if (--argc <= 0)
204 usage();
205 if (hp >= &dhosts[NHOSTS-2]) {
206 (void) fprintf(stderr, gettext("rdist:"
207 " too many destination"
208 " hosts\n"));
209 exit(1);
210 }
211 *hp++ = *++argv;
212 break;
213
214 case 'd':
215 if (--argc <= 0)
216 usage();
217 define(*++argv);
218 break;
219
220 case 'D':
221 debug++;
222 break;
223
224 case 'c':
225 cmdargs++;
226 break;
227
228 case 'n':
229 if (options & VERIFY) {
230 printf("rdist: -n overrides -v\n");
231 options &= ~VERIFY;
232 }
233 nflag++;
234 break;
235
236 case 'q':
237 qflag++;
238 break;
239
240 case 'b':
241 options |= COMPARE;
242 break;
243
244 case 'R':
245 options |= REMOVE;
246 break;
247
248 case 'v':
249 if (nflag) {
250 printf("rdist: -n overrides -v\n");
251 break;
252 }
253 options |= VERIFY;
254 break;
255
256 case 'w':
257 options |= WHOLE;
258 break;
259
260 case 'y':
261 options |= YOUNGER;
262 break;
263
264 case 'h':
265 options |= FOLLOW;
266 break;
267
268 case 'i':
269 options |= IGNLNKS;
270 break;
271
272 default:
273 usage();
274 }
275 }
276 }
277 *hp = NULL;
278
279 mktemp(Tmpfile);
280
281 /*
282 * if the user disables krb5 on the cmdline (-K), then skip
283 * all krb5 setup.
284 *
285 * if the user does not disable krb5 or enable krb5 on the
286 * cmdline, check krb5.conf to see if it should be enabled.
287 */
288
289 if (no_krb5auth_flag) {
290 krb5auth_flag = 0;
291 encrypt_flag = 0;
292 } else if (!krb5auth_flag) {
293 /* is autologin set in krb5.conf? */
294 status = krb5_init_context(&bsd_context);
295 /* don't sweat failure here */
296 if (!status) {
297 /*
298 * note that the call to profile_get_options_boolean
299 * with autologin_option can affect value of
300 * krb5auth_flag
301 */
302 (void) profile_get_options_boolean(bsd_context->profile,
303 appdef,
304 autologin_option);
305 }
306 }
307
308 if (krb5auth_flag > 0) {
309 if (!bsd_context) {
310 status = krb5_init_context(&bsd_context);
311 if (status) {
312 com_err("rdist", status,
313 gettext("while initializing krb5"));
314 exit(1);
315 }
316 }
317
318 /* Set up des buffers */
319 desinbuf.data = des_inbuf;
320 desoutbuf.data = des_outbuf;
321 desinbuf.length = sizeof (des_inbuf);
322 desoutbuf.length = sizeof (des_outbuf);
323
324 /*
325 * Get our local realm to look up local realm options.
326 */
327 status = krb5_get_default_realm(bsd_context, &realmdef[1]);
328 if (status) {
329 com_err("rdist", status,
330 gettext("while getting default realm"));
331 exit(1);
332 }
333 /*
334 * See if encryption should be done for this realm
335 */
336 profile_get_options_boolean(bsd_context->profile, realmdef,
337 option);
338 /*
339 * Check the appdefaults section
340 */
341 profile_get_options_boolean(bsd_context->profile, appdef,
342 option);
343 profile_get_options_string(bsd_context->profile, appdef,
344 rcmdversion);
345
346 if ((encrypt_done > 0) || (encrypt_flag > 0)) {
347 if (krb5_privacy_allowed() == TRUE) {
348 encrypt_flag++;
349 } else {
350 (void) fprintf(stderr, gettext("rdist: "
351 "Encryption not supported.\n"));
352 exit(1);
353 }
354 }
355
356 if ((rcmdoption_done == B_FALSE) && (rcmdproto != NULL)) {
357 if (strncmp(rcmdproto, "rcmdv2", 6) == 0) {
358 kcmd_proto = KCMD_NEW_PROTOCOL;
359 } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) {
360 kcmd_proto = KCMD_OLD_PROTOCOL;
361 } else {
362 (void) fprintf(stderr, gettext("Unrecognized "
363 "KCMD protocol (%s)"), rcmdproto);
364 exit(1);
365 }
366 }
367 }
368
369 if (iamremote) {
370 setreuid(getuid(), getuid());
371 server();
372 exit(nerrs != 0);
373 }
374 if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) {
375 (void) fprintf(stderr,
376 "rdist needs to run with sufficient privilege\n");
377 exit(1);
378 }
379
380 if (cmdargs)
381 docmdargs(argc, argv);
382 else {
383 if (fin == NULL) {
384 if (distfile == NULL) {
385 if ((fin = fopen("distfile", "r")) == NULL)
386 fin = fopen("Distfile", "r");
387 } else
388 fin = fopen(distfile, "r");
389 if (fin == NULL) {
390 perror(distfile ? distfile : "distfile");
391 exit(1);
392 }
393 }
394 yyparse();
395 if (nerrs == 0)
396 docmds(dhosts, argc, argv);
397 }
398
399 return (nerrs != 0);
400 }
401
402 static void
usage()403 usage()
404 {
405 printf(gettext("Usage: rdist [-nqbhirvwyDax] [-PN / -PO] "
406 #ifdef DEBUG
407 "[-p port] "
408 #endif /* DEBUG */
409 "[-k realm] [-f distfile] [-d var=value] [-m host] [file ...]\n"));
410 printf(gettext("or: rdist [-nqbhirvwyDax] [-PN / -PO] [-p port] "
411 "[-k realm] -c source [...] machine[:dest]\n"));
412 exit(1);
413 }
414
415 /*
416 * rcp like interface for distributing files.
417 */
418 static void
docmdargs(nargs,args)419 docmdargs(nargs, args)
420 int nargs;
421 char *args[];
422 {
423 register struct namelist *nl, *prev;
424 register char *cp;
425 struct namelist *files, *hosts;
426 struct subcmd *cmds;
427 char *dest;
428 static struct namelist tnl = { NULL, NULL };
429 int i;
430
431 if (nargs < 2)
432 usage();
433
434 prev = NULL;
435 for (i = 0; i < nargs - 1; i++) {
436 nl = makenl(args[i]);
437 if (prev == NULL)
438 files = prev = nl;
439 else {
440 prev->n_next = nl;
441 prev = nl;
442 }
443 }
444
445 cp = args[i];
446 if ((dest = index(cp, ':')) != NULL)
447 *dest++ = '\0';
448 tnl.n_name = cp;
449 hosts = expand(&tnl, E_ALL);
450 if (nerrs)
451 exit(1);
452
453 if (dest == NULL || *dest == '\0')
454 cmds = NULL;
455 else {
456 cmds = makesubcmd(INSTALL);
457 cmds->sc_options = options;
458 cmds->sc_name = dest;
459 }
460
461 if (debug) {
462 printf("docmdargs()\nfiles = ");
463 prnames(files);
464 printf("hosts = ");
465 prnames(hosts);
466 }
467 insert(NULL, files, hosts, cmds);
468 docmds(NULL, 0, NULL);
469 }
470
471 /*
472 * Print a list of NAME blocks (mostly for debugging).
473 */
474 void
prnames(nl)475 prnames(nl)
476 register struct namelist *nl;
477 {
478 printf("( ");
479 while (nl != NULL) {
480 printf("%s ", nl->n_name);
481 nl = nl->n_next;
482 }
483 printf(")\n");
484 }
485
486 void
prcmd(c)487 prcmd(c)
488 struct cmd *c;
489 {
490 extern char *prtype();
491
492 while (c) {
493 printf("c_type %s, c_name %s, c_label %s, c_files ",
494 prtype(c->c_type), c->c_name,
495 c->c_label? c->c_label : "NULL");
496 prnames(c->c_files);
497 prsubcmd(c->c_cmds);
498 c = c->c_next;
499 }
500 }
501
502 static void
prsubcmd(s)503 prsubcmd(s)
504 struct subcmd *s;
505 {
506 extern char *prtype();
507 extern char *proptions();
508
509 while (s) {
510 printf("sc_type %s, sc_options %d%s, sc_name %s, sc_args ",
511 prtype(s->sc_type),
512 s->sc_options, proptions(s->sc_options),
513 s->sc_name ? s->sc_name : "NULL");
514 prnames(s->sc_args);
515 s = s->sc_next;
516 }
517 }
518
519 char *
prtype(t)520 prtype(t)
521 int t;
522 {
523 switch (t) {
524 case EQUAL:
525 return ("EQUAL");
526 case LP:
527 return ("LP");
528 case RP:
529 return ("RP");
530 case SM:
531 return ("SM");
532 case ARROW:
533 return ("ARROW");
534 case COLON:
535 return ("COLON");
536 case DCOLON:
537 return ("DCOLON");
538 case NAME:
539 return ("NAME");
540 case STRING:
541 return ("STRING");
542 case INSTALL:
543 return ("INSTALL");
544 case NOTIFY:
545 return ("NOTIFY");
546 case EXCEPT:
547 return ("EXCEPT");
548 case PATTERN:
549 return ("PATTERN");
550 case SPECIAL:
551 return ("SPECIAL");
552 case OPTION:
553 return ("OPTION");
554 }
555 return (NULL);
556 }
557
558 char *
proptions(o)559 proptions(o)
560 int o;
561 {
562 return (printb((unsigned short) o, OBITS));
563 }
564
565 char *
printb(v,bits)566 printb(v, bits)
567 register char *bits;
568 register unsigned short v;
569 {
570 register int i, any = 0;
571 register char c;
572 char *p = buf;
573
574 bits++;
575 if (bits) {
576
577 *p++ = '<';
578 while ((i = *bits++) != 0) {
579 if (v & (1 << (i-1))) {
580 if (any)
581 *p++ = ',';
582 any = 1;
583 for (; (c = *bits) > 32; bits++)
584 *p++ = c;
585 } else
586 for (; *bits > 32; bits++)
587 ;
588 }
589 *p++ = '>';
590 }
591
592 *p = '\0';
593 return (buf);
594 }
595