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