/* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. */ #include "defs.h" #include #include #include #include #include #define NHOSTS 100 /* * Remote distribution program. */ char *distfile = NULL; char Tmpfile[] = "/tmp/rdistXXXXXX"; char *tmpname = &Tmpfile[5]; int debug; /* debugging flag */ int nflag; /* NOP flag, just print commands without executing */ int qflag; /* Quiet. Don't print messages */ int options; /* global options */ int iamremote; /* act as remote server for transfering files */ FILE *fin = NULL; /* input file pointer */ int rem = -1; /* file descriptor to remote source/sink process */ char host[32]; /* host name */ int nerrs; /* number of errors while sending/receiving */ char user[10]; /* user's name */ char homedir[128]; /* user's home directory */ char buf[RDIST_BUFSIZ]; /* general purpose buffer */ struct passwd *pw; /* pointer to static area used by getpwent */ struct group *gr; /* pointer to static area used by getgrent */ char des_inbuf[2 * RDIST_BUFSIZ]; /* needs to be > largest read size */ char des_outbuf[2 * RDIST_BUFSIZ]; /* needs to be > largest write size */ krb5_data desinbuf, desoutbuf; krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ krb5_context bsd_context = NULL; krb5_auth_context auth_context; krb5_creds *cred; char *krb_cache = NULL; krb5_flags authopts; krb5_error_code status; enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; int encrypt_flag = 0; /* Flag set when encryption is used */ int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */ static profile_options_boolean autologin_option[] = { { "autologin", &krb5auth_flag, 0 }, { NULL, NULL, 0 } }; static int no_krb5auth_flag = 0; int debug_port = 0; int retval = 0; char *krb_realm = NULL; /* Flag set, if -PN / -PO is specified */ static boolean_t rcmdoption_done = B_FALSE; static int encrypt_done = 0; /* Flag set, if -x is specified */ profile_options_boolean option[] = { { "encrypt", &encrypt_flag, 0 }, { NULL, NULL, 0 } }; static char *rcmdproto = NULL; profile_option_strings rcmdversion[] = { { "rcmd_protocol", &rcmdproto, 0 }, { NULL, NULL, 0 } }; char *realmdef[] = { "realms", NULL, "rdist", NULL }; char *appdef[] = { "appdefaults", "rdist", NULL }; static void usage(void); static char *prtype(int t); static void prsubcmd(struct subcmd *s); static void docmdargs(int nargs, char *args[]); void prnames(); void prcmd(); int main(argc, argv) int argc; char *argv[]; { register char *arg; int cmdargs = 0; char *dhosts[NHOSTS], **hp = dhosts; (void) setlocale(LC_ALL, ""); pw = getpwuid(getuid()); if (pw == NULL) { (void) fprintf(stderr, gettext("%s: Who are you?\n"), argv[0]); exit(1); } strncpy(user, pw->pw_name, sizeof (user)); user[sizeof (user) - 1] = '\0'; strncpy(homedir, pw->pw_dir, sizeof (homedir)); homedir[sizeof (homedir) - 1] = '\0'; gethostname(host, sizeof (host)); while (--argc > 0) { if ((arg = *++argv)[0] != '-') break; if ((strcmp(arg, "-Server") == 0)) iamremote++; else while (*++arg) { if (strncmp(*argv, "-PO", 3) == 0) { if (rcmdoption_done == B_TRUE) { (void) fprintf(stderr, gettext("rdist: " "Only one of -PN " "and -PO allowed.\n")); usage(); } kcmd_proto = KCMD_OLD_PROTOCOL; krb5auth_flag++; rcmdoption_done = B_TRUE; break; } if (strncmp(*argv, "-PN", 3) == 0) { if (rcmdoption_done == B_TRUE) { (void) fprintf(stderr, gettext("rdist: " "Only one of -PN " "and -PO allowed.\n")); usage(); } kcmd_proto = KCMD_NEW_PROTOCOL; krb5auth_flag++; rcmdoption_done = B_TRUE; break; } switch (*arg) { #ifdef DEBUG case 'p': if (--argc <= 0) usage(); debug_port = htons(atoi(*++argv)); break; #endif /* DEBUG */ case 'k': if (--argc <= 0) { (void) fprintf(stderr, gettext("rdist: " "-k flag must be followed with " " a realm name.\n")); exit(1); } if ((krb_realm = strdup(*++argv)) == NULL) { (void) fprintf(stderr, gettext("rdist: " "Cannot malloc.\n")); exit(1); } krb5auth_flag++; break; case 'K': no_krb5auth_flag++; break; case 'a': krb5auth_flag++; break; case 'x': encrypt_flag++; encrypt_done++; krb5auth_flag++; break; case 'f': if (--argc <= 0) usage(); distfile = *++argv; if (distfile[0] == '-' && distfile[1] == '\0') fin = stdin; break; case 'm': if (--argc <= 0) usage(); if (hp >= &dhosts[NHOSTS-2]) { (void) fprintf(stderr, gettext("rdist:" " too many destination" " hosts\n")); exit(1); } *hp++ = *++argv; break; case 'd': if (--argc <= 0) usage(); define(*++argv); break; case 'D': debug++; break; case 'c': cmdargs++; break; case 'n': if (options & VERIFY) { printf("rdist: -n overrides -v\n"); options &= ~VERIFY; } nflag++; break; case 'q': qflag++; break; case 'b': options |= COMPARE; break; case 'R': options |= REMOVE; break; case 'v': if (nflag) { printf("rdist: -n overrides -v\n"); break; } options |= VERIFY; break; case 'w': options |= WHOLE; break; case 'y': options |= YOUNGER; break; case 'h': options |= FOLLOW; break; case 'i': options |= IGNLNKS; break; default: usage(); } } } *hp = NULL; mktemp(Tmpfile); /* * if the user disables krb5 on the cmdline (-K), then skip * all krb5 setup. * * if the user does not disable krb5 or enable krb5 on the * cmdline, check krb5.conf to see if it should be enabled. */ if (no_krb5auth_flag) { krb5auth_flag = 0; encrypt_flag = 0; } else if (!krb5auth_flag) { /* is autologin set in krb5.conf? */ status = krb5_init_context(&bsd_context); /* don't sweat failure here */ if (!status) { /* * note that the call to profile_get_options_boolean * with autologin_option can affect value of * krb5auth_flag */ (void) profile_get_options_boolean(bsd_context->profile, appdef, autologin_option); } } if (krb5auth_flag > 0) { if (!bsd_context) { status = krb5_init_context(&bsd_context); if (status) { com_err("rdist", status, gettext("while initializing krb5")); exit(1); } } /* Set up des buffers */ desinbuf.data = des_inbuf; desoutbuf.data = des_outbuf; desinbuf.length = sizeof (des_inbuf); desoutbuf.length = sizeof (des_outbuf); /* * Get our local realm to look up local realm options. */ status = krb5_get_default_realm(bsd_context, &realmdef[1]); if (status) { com_err("rdist", status, gettext("while getting default realm")); exit(1); } /* * See if encryption should be done for this realm */ profile_get_options_boolean(bsd_context->profile, realmdef, option); /* * Check the appdefaults section */ profile_get_options_boolean(bsd_context->profile, appdef, option); profile_get_options_string(bsd_context->profile, appdef, rcmdversion); if ((encrypt_done > 0) || (encrypt_flag > 0)) { if (krb5_privacy_allowed() == TRUE) { encrypt_flag++; } else { (void) fprintf(stderr, gettext("rdist: " "Encryption not supported.\n")); exit(1); } } if ((rcmdoption_done == B_FALSE) && (rcmdproto != NULL)) { if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { kcmd_proto = KCMD_NEW_PROTOCOL; } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { kcmd_proto = KCMD_OLD_PROTOCOL; } else { (void) fprintf(stderr, gettext("Unrecognized " "KCMD protocol (%s)"), rcmdproto); exit(1); } } } if (iamremote) { setreuid(getuid(), getuid()); server(); exit(nerrs != 0); } if (__init_suid_priv(0, PRIV_NET_PRIVADDR, NULL) == -1) { (void) fprintf(stderr, "rdist needs to run with sufficient privilege\n"); exit(1); } if (cmdargs) docmdargs(argc, argv); else { if (fin == NULL) { if (distfile == NULL) { if ((fin = fopen("distfile", "r")) == NULL) fin = fopen("Distfile", "r"); } else fin = fopen(distfile, "r"); if (fin == NULL) { perror(distfile ? distfile : "distfile"); exit(1); } } yyparse(); if (nerrs == 0) docmds(dhosts, argc, argv); } return (nerrs != 0); } static void usage() { printf(gettext("Usage: rdist [-nqbhirvwyDax] [-PN / -PO] " #ifdef DEBUG "[-p port] " #endif /* DEBUG */ "[-k realm] [-f distfile] [-d var=value] [-m host] [file ...]\n")); printf(gettext("or: rdist [-nqbhirvwyDax] [-PN / -PO] [-p port] " "[-k realm] -c source [...] machine[:dest]\n")); exit(1); } /* * rcp like interface for distributing files. */ static void docmdargs(nargs, args) int nargs; char *args[]; { register struct namelist *nl, *prev; register char *cp; struct namelist *files, *hosts; struct subcmd *cmds; char *dest; static struct namelist tnl = { NULL, NULL }; int i; if (nargs < 2) usage(); prev = NULL; for (i = 0; i < nargs - 1; i++) { nl = makenl(args[i]); if (prev == NULL) files = prev = nl; else { prev->n_next = nl; prev = nl; } } cp = args[i]; if ((dest = index(cp, ':')) != NULL) *dest++ = '\0'; tnl.n_name = cp; hosts = expand(&tnl, E_ALL); if (nerrs) exit(1); if (dest == NULL || *dest == '\0') cmds = NULL; else { cmds = makesubcmd(INSTALL); cmds->sc_options = options; cmds->sc_name = dest; } if (debug) { printf("docmdargs()\nfiles = "); prnames(files); printf("hosts = "); prnames(hosts); } insert(NULL, files, hosts, cmds); docmds(NULL, 0, NULL); } /* * Print a list of NAME blocks (mostly for debugging). */ void prnames(nl) register struct namelist *nl; { printf("( "); while (nl != NULL) { printf("%s ", nl->n_name); nl = nl->n_next; } printf(")\n"); } void prcmd(c) struct cmd *c; { extern char *prtype(); while (c) { printf("c_type %s, c_name %s, c_label %s, c_files ", prtype(c->c_type), c->c_name, c->c_label? c->c_label : "NULL"); prnames(c->c_files); prsubcmd(c->c_cmds); c = c->c_next; } } static void prsubcmd(s) struct subcmd *s; { extern char *prtype(); extern char *proptions(); while (s) { printf("sc_type %s, sc_options %d%s, sc_name %s, sc_args ", prtype(s->sc_type), s->sc_options, proptions(s->sc_options), s->sc_name ? s->sc_name : "NULL"); prnames(s->sc_args); s = s->sc_next; } } char * prtype(t) int t; { switch (t) { case EQUAL: return ("EQUAL"); case LP: return ("LP"); case RP: return ("RP"); case SM: return ("SM"); case ARROW: return ("ARROW"); case COLON: return ("COLON"); case DCOLON: return ("DCOLON"); case NAME: return ("NAME"); case STRING: return ("STRING"); case INSTALL: return ("INSTALL"); case NOTIFY: return ("NOTIFY"); case EXCEPT: return ("EXCEPT"); case PATTERN: return ("PATTERN"); case SPECIAL: return ("SPECIAL"); case OPTION: return ("OPTION"); } return (NULL); } char * proptions(o) int o; { return (printb((unsigned short) o, OBITS)); } char * printb(v, bits) register char *bits; register unsigned short v; { register int i, any = 0; register char c; char *p = buf; bits++; if (bits) { *p++ = '<'; while ((i = *bits++) != 0) { if (v & (1 << (i-1))) { if (any) *p++ = ','; any = 1; for (; (c = *bits) > 32; bits++) *p++ = c; } else for (; *bits > 32; bits++) ; } *p++ = '>'; } *p = '\0'; return (buf); }