summaryrefslogtreecommitdiff
path: root/usr/src/cmd/cmd-inet/usr.bin/rdist/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/cmd-inet/usr.bin/rdist/main.c')
-rw-r--r--usr/src/cmd/cmd-inet/usr.bin/rdist/main.c555
1 files changed, 555 insertions, 0 deletions
diff --git a/usr/src/cmd/cmd-inet/usr.bin/rdist/main.c b/usr/src/cmd/cmd-inet/usr.bin/rdist/main.c
new file mode 100644
index 0000000000..015daefa6b
--- /dev/null
+++ b/usr/src/cmd/cmd-inet/usr.bin/rdist/main.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright 1998-2003 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.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include "defs.h"
+#include <string.h>
+#include <syslog.h>
+#include <krb5defs.h>
+#include <k5-int.h>
+#include <priv_utils.h>
+
+#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;
+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 */
+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 };
+
+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 '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 (krb5auth_flag > 0) {
+ 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);
+ }
+
+ exit(nerrs != 0);
+ /* NOTREACHED */
+}
+
+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.
+ */
+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).
+ */
+prnames(nl)
+ register struct namelist *nl;
+{
+ printf("( ");
+ while (nl != NULL) {
+ printf("%s ", nl->n_name);
+ nl = nl->n_next;
+ }
+ printf(")\n");
+}
+
+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;
+ }
+}
+
+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");
+ }
+}
+
+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);
+}
+
+/*VARARGS*/
+warn(fmt, a1, a2, a3)
+ char *fmt;
+{
+ extern int yylineno;
+
+ fprintf(stderr, "rdist: line %d: Warning: ", yylineno);
+ fprintf(stderr, fmt, a1, a2, a3);
+ fputc('\n', stderr);
+}