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