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