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