Home | History | Annotate | Download | only in rdist
      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
    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
    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
    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
    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
    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
    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 *
    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 *
    559 proptions(o)
    560 	int o;
    561 {
    562 	return (printb((unsigned short) o, OBITS));
    563 }
    564 
    565 char *
    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