1 /* 2 * Copyright 2005 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 static void usage(void); 93 static char *prtype(int t); 94 static void prsubcmd(struct subcmd *s); 95 static void docmdargs(int nargs, char *args[]); 96 void prnames(); 97 void prcmd(); 98 99 int 100 main(argc, argv) 101 int argc; 102 char *argv[]; 103 { 104 register char *arg; 105 int cmdargs = 0; 106 char *dhosts[NHOSTS], **hp = dhosts; 107 108 (void) setlocale(LC_ALL, ""); 109 110 pw = getpwuid(getuid()); 111 if (pw == NULL) { 112 (void) fprintf(stderr, gettext("%s: Who are you?\n"), argv[0]); 113 exit(1); 114 } 115 strncpy(user, pw->pw_name, sizeof (user)); 116 user[sizeof (user) - 1] = '\0'; 117 strncpy(homedir, pw->pw_dir, sizeof (homedir)); 118 homedir[sizeof (homedir) - 1] = '\0'; 119 gethostname(host, sizeof (host)); 120 121 while (--argc > 0) { 122 if ((arg = *++argv)[0] != '-') 123 break; 124 if ((strcmp(arg, "-Server") == 0)) 125 iamremote++; 126 else while (*++arg) { 127 if (strncmp(*argv, "-PO", 3) == 0) { 128 if (rcmdoption_done == B_TRUE) { 129 (void) fprintf(stderr, gettext("rdist: " 130 "Only one of -PN " 131 "and -PO allowed.\n")); 132 usage(); 133 } 134 kcmd_proto = KCMD_OLD_PROTOCOL; 135 krb5auth_flag++; 136 rcmdoption_done = B_TRUE; 137 break; 138 } 139 if (strncmp(*argv, "-PN", 3) == 0) { 140 if (rcmdoption_done == B_TRUE) { 141 (void) fprintf(stderr, gettext("rdist: " 142 "Only one of -PN " 143 "and -PO allowed.\n")); 144 usage(); 145 } 146 kcmd_proto = KCMD_NEW_PROTOCOL; 147 krb5auth_flag++; 148 rcmdoption_done = B_TRUE; 149 break; 150 } 151 152 switch (*arg) { 153 #ifdef DEBUG 154 case 'p': 155 if (--argc <= 0) 156 usage(); 157 debug_port = htons(atoi(*++argv)); 158 break; 159 #endif /* DEBUG */ 160 case 'k': 161 if (--argc <= 0) { 162 (void) fprintf(stderr, gettext("rdist: " 163 "-k flag must be followed with " 164 " a realm name.\n")); 165 exit(1); 166 } 167 if ((krb_realm = strdup(*++argv)) == NULL) { 168 (void) fprintf(stderr, gettext("rdist: " 169 "Cannot malloc.\n")); 170 exit(1); 171 } 172 krb5auth_flag++; 173 break; 174 175 case 'a': 176 krb5auth_flag++; 177 break; 178 179 case 'x': 180 encrypt_flag++; 181 encrypt_done++; 182 krb5auth_flag++; 183 break; 184 185 case 'f': 186 if (--argc <= 0) 187 usage(); 188 distfile = *++argv; 189 if (distfile[0] == '-' && distfile[1] == '\0') 190 fin = stdin; 191 break; 192 193 case 'm': 194 if (--argc <= 0) 195 usage(); 196 if (hp >= &dhosts[NHOSTS-2]) { 197 (void) fprintf(stderr, gettext("rdist:" 198 " too many destination" 199 " hosts\n")); 200 exit(1); 201 } 202 *hp++ = *++argv; 203 break; 204 205 case 'd': 206 if (--argc <= 0) 207 usage(); 208 define(*++argv); 209 break; 210 211 case 'D': 212 debug++; 213 break; 214 215 case 'c': 216 cmdargs++; 217 break; 218 219 case 'n': 220 if (options & VERIFY) { 221 printf("rdist: -n overrides -v\n"); 222 options &= ~VERIFY; 223 } 224 nflag++; 225 break; 226 227 case 'q': 228 qflag++; 229 break; 230 231 case 'b': 232 options |= COMPARE; 233 break; 234 235 case 'R': 236 options |= REMOVE; 237 break; 238 239 case 'v': 240 if (nflag) { 241 printf("rdist: -n overrides -v\n"); 242 break; 243 } 244 options |= VERIFY; 245 break; 246 247 case 'w': 248 options |= WHOLE; 249 break; 250 251 case 'y': 252 options |= YOUNGER; 253 break; 254 255 case 'h': 256 options |= FOLLOW; 257 break; 258 259 case 'i': 260 options |= IGNLNKS; 261 break; 262 263 default: 264 usage(); 265 } 266 } 267 } 268 *hp = NULL; 269 270 mktemp(Tmpfile); 271 272 if (krb5auth_flag > 0) { 273 status = krb5_init_context(&bsd_context); 274 if (status) { 275 com_err("rdist", status, 276 gettext("while initializing krb5")); 277 exit(1); 278 } 279 280 /* Set up des buffers */ 281 desinbuf.data = des_inbuf; 282 desoutbuf.data = des_outbuf; 283 desinbuf.length = sizeof (des_inbuf); 284 desoutbuf.length = sizeof (des_outbuf); 285 286 /* 287 * Get our local realm to look up local realm options. 288 */ 289 status = krb5_get_default_realm(bsd_context, &realmdef[1]); 290 if (status) { 291 com_err("rdist", status, 292 gettext("while getting default realm")); 293 exit(1); 294 } 295 /* 296 * See if encryption should be done for this realm 297 */ 298 profile_get_options_boolean(bsd_context->profile, realmdef, 299 option); 300 /* 301 * Check the appdefaults section 302 */ 303 profile_get_options_boolean(bsd_context->profile, appdef, 304 option); 305 profile_get_options_string(bsd_context->profile, appdef, 306 rcmdversion); 307 308 if ((encrypt_done > 0) || (encrypt_flag > 0)) { 309 if (krb5_privacy_allowed() == TRUE) { 310 encrypt_flag++; 311 } else { 312 (void) fprintf(stderr, gettext("rdist: " 313 "Encryption not supported.\n")); 314 exit(1); 315 } 316 } 317 318 if ((rcmdoption_done == B_FALSE) && (rcmdproto != NULL)) { 319 if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { 320 kcmd_proto = KCMD_NEW_PROTOCOL; 321 } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { 322 kcmd_proto = KCMD_OLD_PROTOCOL; 323 } else { 324 (void) fprintf(stderr, gettext("Unrecognized " 325 "KCMD protocol (%s)"), rcmdproto); 326 exit(1); 327 } 328 } 329 } 330 331 if (iamremote) { 332 setreuid(getuid(), getuid()); 333 server(); 334 exit(nerrs != 0); 335 } 336 if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) { 337 (void) fprintf(stderr, 338 "rdist needs to run with sufficient privilege\n"); 339 exit(1); 340 } 341 342 if (cmdargs) 343 docmdargs(argc, argv); 344 else { 345 if (fin == NULL) { 346 if (distfile == NULL) { 347 if ((fin = fopen("distfile", "r")) == NULL) 348 fin = fopen("Distfile", "r"); 349 } else 350 fin = fopen(distfile, "r"); 351 if (fin == NULL) { 352 perror(distfile ? distfile : "distfile"); 353 exit(1); 354 } 355 } 356 yyparse(); 357 if (nerrs == 0) 358 docmds(dhosts, argc, argv); 359 } 360 361 return (nerrs != 0); 362 } 363 364 static void 365 usage() 366 { 367 printf(gettext("Usage: rdist [-nqbhirvwyDax] [-PN / -PO] " 368 #ifdef DEBUG 369 "[-p port] " 370 #endif /* DEBUG */ 371 "[-k realm] [-f distfile] [-d var=value] [-m host] [file ...]\n")); 372 printf(gettext("or: rdist [-nqbhirvwyDax] [-PN / -PO] [-p port] " 373 "[-k realm] -c source [...] machine[:dest]\n")); 374 exit(1); 375 } 376 377 /* 378 * rcp like interface for distributing files. 379 */ 380 static void 381 docmdargs(nargs, args) 382 int nargs; 383 char *args[]; 384 { 385 register struct namelist *nl, *prev; 386 register char *cp; 387 struct namelist *files, *hosts; 388 struct subcmd *cmds; 389 char *dest; 390 static struct namelist tnl = { NULL, NULL }; 391 int i; 392 393 if (nargs < 2) 394 usage(); 395 396 prev = NULL; 397 for (i = 0; i < nargs - 1; i++) { 398 nl = makenl(args[i]); 399 if (prev == NULL) 400 files = prev = nl; 401 else { 402 prev->n_next = nl; 403 prev = nl; 404 } 405 } 406 407 cp = args[i]; 408 if ((dest = index(cp, ':')) != NULL) 409 *dest++ = '\0'; 410 tnl.n_name = cp; 411 hosts = expand(&tnl, E_ALL); 412 if (nerrs) 413 exit(1); 414 415 if (dest == NULL || *dest == '\0') 416 cmds = NULL; 417 else { 418 cmds = makesubcmd(INSTALL); 419 cmds->sc_options = options; 420 cmds->sc_name = dest; 421 } 422 423 if (debug) { 424 printf("docmdargs()\nfiles = "); 425 prnames(files); 426 printf("hosts = "); 427 prnames(hosts); 428 } 429 insert(NULL, files, hosts, cmds); 430 docmds(NULL, 0, NULL); 431 } 432 433 /* 434 * Print a list of NAME blocks (mostly for debugging). 435 */ 436 void 437 prnames(nl) 438 register struct namelist *nl; 439 { 440 printf("( "); 441 while (nl != NULL) { 442 printf("%s ", nl->n_name); 443 nl = nl->n_next; 444 } 445 printf(")\n"); 446 } 447 448 void 449 prcmd(c) 450 struct cmd *c; 451 { 452 extern char *prtype(); 453 454 while (c) { 455 printf("c_type %s, c_name %s, c_label %s, c_files ", 456 prtype(c->c_type), c->c_name, 457 c->c_label? c->c_label : "NULL"); 458 prnames(c->c_files); 459 prsubcmd(c->c_cmds); 460 c = c->c_next; 461 } 462 } 463 464 static void 465 prsubcmd(s) 466 struct subcmd *s; 467 { 468 extern char *prtype(); 469 extern char *proptions(); 470 471 while (s) { 472 printf("sc_type %s, sc_options %d%s, sc_name %s, sc_args ", 473 prtype(s->sc_type), 474 s->sc_options, proptions(s->sc_options), 475 s->sc_name ? s->sc_name : "NULL"); 476 prnames(s->sc_args); 477 s = s->sc_next; 478 } 479 } 480 481 char * 482 prtype(t) 483 int t; 484 { 485 switch (t) { 486 case EQUAL: 487 return ("EQUAL"); 488 case LP: 489 return ("LP"); 490 case RP: 491 return ("RP"); 492 case SM: 493 return ("SM"); 494 case ARROW: 495 return ("ARROW"); 496 case COLON: 497 return ("COLON"); 498 case DCOLON: 499 return ("DCOLON"); 500 case NAME: 501 return ("NAME"); 502 case STRING: 503 return ("STRING"); 504 case INSTALL: 505 return ("INSTALL"); 506 case NOTIFY: 507 return ("NOTIFY"); 508 case EXCEPT: 509 return ("EXCEPT"); 510 case PATTERN: 511 return ("PATTERN"); 512 case SPECIAL: 513 return ("SPECIAL"); 514 case OPTION: 515 return ("OPTION"); 516 } 517 return (NULL); 518 } 519 520 char * 521 proptions(o) 522 int o; 523 { 524 return (printb((unsigned short) o, OBITS)); 525 } 526 527 char * 528 printb(v, bits) 529 register char *bits; 530 register unsigned short v; 531 { 532 register int i, any = 0; 533 register char c; 534 char *p = buf; 535 536 bits++; 537 if (bits) { 538 539 *p++ = '<'; 540 while ((i = *bits++) != 0) { 541 if (v & (1 << (i-1))) { 542 if (any) 543 *p++ = ','; 544 any = 1; 545 for (; (c = *bits) > 32; bits++) 546 *p++ = c; 547 } else 548 for (; *bits > 32; bits++) 549 ; 550 } 551 *p++ = '>'; 552 } 553 554 *p = '\0'; 555 return (buf); 556 } 557