17c478bd9Sstevel@tonic-gate /* 20b4fd3b1SSurya Prakki * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 37c478bd9Sstevel@tonic-gate * Use is subject to license terms. 47c478bd9Sstevel@tonic-gate */ 57c478bd9Sstevel@tonic-gate 67c478bd9Sstevel@tonic-gate /* 77c478bd9Sstevel@tonic-gate * Copyright (c) 1983 The Regents of the University of California. 87c478bd9Sstevel@tonic-gate * All rights reserved. 97c478bd9Sstevel@tonic-gate * 107c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 117c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 127c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 137c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 147c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 157c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 167c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 177c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate */ 207c478bd9Sstevel@tonic-gate 217c478bd9Sstevel@tonic-gate #define _FILE_OFFSET_BITS 64 227c478bd9Sstevel@tonic-gate 237c478bd9Sstevel@tonic-gate /* 247c478bd9Sstevel@tonic-gate * rcp 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate #include <sys/param.h> 277c478bd9Sstevel@tonic-gate #include <sys/file.h> 287c478bd9Sstevel@tonic-gate #include <sys/stat.h> 297c478bd9Sstevel@tonic-gate #include <sys/time.h> 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 327c478bd9Sstevel@tonic-gate #include <sys/acl.h> 337c478bd9Sstevel@tonic-gate #include <dirent.h> 347c478bd9Sstevel@tonic-gate #include <signal.h> 357c478bd9Sstevel@tonic-gate #include <sys/socket.h> 367c478bd9Sstevel@tonic-gate #include <netinet/in.h> 377c478bd9Sstevel@tonic-gate #include <pwd.h> 387c478bd9Sstevel@tonic-gate #include <netdb.h> 397c478bd9Sstevel@tonic-gate #include <wchar.h> 407c478bd9Sstevel@tonic-gate #include <stdlib.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 427c478bd9Sstevel@tonic-gate #include <locale.h> 437c478bd9Sstevel@tonic-gate #include <strings.h> 447c478bd9Sstevel@tonic-gate #include <stdio.h> 457c478bd9Sstevel@tonic-gate #include <ctype.h> 467c478bd9Sstevel@tonic-gate #include <fcntl.h> 477c478bd9Sstevel@tonic-gate #include <unistd.h> 487c478bd9Sstevel@tonic-gate #include <limits.h> 497c478bd9Sstevel@tonic-gate #include <priv_utils.h> 507c478bd9Sstevel@tonic-gate #include <sys/sendfile.h> 517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 527c478bd9Sstevel@tonic-gate #include <sys/wait.h> 53fa9e4066Sahrens #include <aclutils.h> 5440164e4fSsn199410 #include <sys/varargs.h> 557c478bd9Sstevel@tonic-gate 567c478bd9Sstevel@tonic-gate /* 577c478bd9Sstevel@tonic-gate * It seems like Berkeley got these from pathnames.h? 587c478bd9Sstevel@tonic-gate */ 597c478bd9Sstevel@tonic-gate #define _PATH_RSH "/usr/bin/rsh" 607c478bd9Sstevel@tonic-gate #define _PATH_CP "/usr/bin/cp" 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #define ACL_FAIL 1 637c478bd9Sstevel@tonic-gate #define ACL_OK 0 647c478bd9Sstevel@tonic-gate #define RCP_BUFSIZE (64 * 1024) 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate #define RCP_ACL "/usr/lib/sunw,rcp" 677c478bd9Sstevel@tonic-gate /* see PSARC/1993/004/opinion */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate typedef struct _buf { 707c478bd9Sstevel@tonic-gate int cnt; 717c478bd9Sstevel@tonic-gate char *buf; 727c478bd9Sstevel@tonic-gate } BUF; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate static char *cmd_sunw; 757c478bd9Sstevel@tonic-gate static struct passwd *pwd; 767c478bd9Sstevel@tonic-gate static int errs; 777c478bd9Sstevel@tonic-gate static int pflag; 787c478bd9Sstevel@tonic-gate static uid_t userid; 797c478bd9Sstevel@tonic-gate static int rem; 807c478bd9Sstevel@tonic-gate static int zflag; 817c478bd9Sstevel@tonic-gate static int iamremote; 827c478bd9Sstevel@tonic-gate static int iamrecursive; 837c478bd9Sstevel@tonic-gate static int targetshouldbedirectory; 847c478bd9Sstevel@tonic-gate static int aclflag; 85fa9e4066Sahrens static int acl_aclflag; 867c478bd9Sstevel@tonic-gate static int retval = 0; 877c478bd9Sstevel@tonic-gate static int portnumber = 0; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate static void lostconn(void); 907c478bd9Sstevel@tonic-gate static char *search_char(unsigned char *, unsigned char); 917c478bd9Sstevel@tonic-gate static char *removebrackets(char *); 927c478bd9Sstevel@tonic-gate static char *colon(char *); 937c478bd9Sstevel@tonic-gate static int response(void); 947c478bd9Sstevel@tonic-gate static void usage(void); 957c478bd9Sstevel@tonic-gate static void source(int, char **); 967c478bd9Sstevel@tonic-gate static void sink(int, char **); 977c478bd9Sstevel@tonic-gate static void toremote(char *, int, char **); 987c478bd9Sstevel@tonic-gate static void tolocal(int, char **); 997c478bd9Sstevel@tonic-gate static void verifydir(char *); 1007c478bd9Sstevel@tonic-gate static int okname(char *); 10140164e4fSsn199410 static int susystem(char *, char **); 1027c478bd9Sstevel@tonic-gate static void rsource(char *, struct stat *); 1037c478bd9Sstevel@tonic-gate static int sendacl(int); 1047c478bd9Sstevel@tonic-gate static int recvacl(int, int, int); 1057c478bd9Sstevel@tonic-gate static int zwrite(int, char *, int); 1067c478bd9Sstevel@tonic-gate static void zopen(int, int); 1077c478bd9Sstevel@tonic-gate static int zclose(int); 1087c478bd9Sstevel@tonic-gate static int notzero(char *, int); 1097c478bd9Sstevel@tonic-gate static BUF *allocbuf(BUF *, int, int); 1107c478bd9Sstevel@tonic-gate static void error(char *fmt, ...); 11140164e4fSsn199410 static void addargs(char **, ...); 1127c478bd9Sstevel@tonic-gate 1137c478bd9Sstevel@tonic-gate /* 1147c478bd9Sstevel@tonic-gate * As a 32 bit application, we can only transfer (2gb - 1) i.e 0x7FFFFFFF 1157c478bd9Sstevel@tonic-gate * bytes of data. We would like the size to be aligned to the nearest 1167c478bd9Sstevel@tonic-gate * MAXBOFFSET (8192) boundary for optimal performance. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate #define SENDFILE_SIZE 0x7FFFE000 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate #include <k5-int.h> 1217c478bd9Sstevel@tonic-gate #include <profile/prof_int.h> 1227c478bd9Sstevel@tonic-gate #include <com_err.h> 1237c478bd9Sstevel@tonic-gate #include <kcmd.h> 1247c478bd9Sstevel@tonic-gate 1257c478bd9Sstevel@tonic-gate #define NULLBUF (BUF *) 0 12640164e4fSsn199410 #define MAXARGS 10 /* Number of arguments passed to execv() */ 1277c478bd9Sstevel@tonic-gate 1287c478bd9Sstevel@tonic-gate static int sock; 1297c478bd9Sstevel@tonic-gate static char *cmd, *cmd_orig, *cmd_sunw_orig; 1307c478bd9Sstevel@tonic-gate static char *krb_realm = NULL; 1317c478bd9Sstevel@tonic-gate static char *krb_cache = NULL; 1327c478bd9Sstevel@tonic-gate static char *krb_config = NULL; 1337c478bd9Sstevel@tonic-gate static char des_inbuf[2 * RCP_BUFSIZE]; 1347c478bd9Sstevel@tonic-gate /* needs to be > largest read size */ 1357c478bd9Sstevel@tonic-gate static char des_outbuf[2 * RCP_BUFSIZE]; 1367c478bd9Sstevel@tonic-gate /* needs to be > largest write size */ 1377c478bd9Sstevel@tonic-gate 1387c478bd9Sstevel@tonic-gate static krb5_data desinbuf, desoutbuf; 1397c478bd9Sstevel@tonic-gate static krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ 1407c478bd9Sstevel@tonic-gate static krb5_keyblock *session_key; /* static key for session */ 1413ca4cacdSPeter Shoults static krb5_context bsd_context = NULL; 1427c478bd9Sstevel@tonic-gate static krb5_auth_context auth_context; 1437c478bd9Sstevel@tonic-gate static krb5_flags authopts; 1447c478bd9Sstevel@tonic-gate static krb5_error_code status; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate static void try_normal_rcp(int, char **); 1477c478bd9Sstevel@tonic-gate static int init_service(int); 1487c478bd9Sstevel@tonic-gate static char **save_argv(int, char **); 1497c478bd9Sstevel@tonic-gate static void answer_auth(char *, char *); 1507c478bd9Sstevel@tonic-gate static int desrcpwrite(int, char *, int); 1517c478bd9Sstevel@tonic-gate static int desrcpread(int, char *, int); 1527c478bd9Sstevel@tonic-gate 1537c478bd9Sstevel@tonic-gate /* 1547c478bd9Sstevel@tonic-gate * Not sure why these two don't have their own header file declarations, but 1557c478bd9Sstevel@tonic-gate * lint complains about absent declarations so place some here. Sigh. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_boolean(profile_t, char **, 1587c478bd9Sstevel@tonic-gate profile_options_boolean *); 1597c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_string(profile_t, char **, 1607c478bd9Sstevel@tonic-gate profile_option_strings *); 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate static int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */ 1633ca4cacdSPeter Shoults static profile_options_boolean autologin_option[] = { 1643ca4cacdSPeter Shoults { "autologin", &krb5auth_flag, 0 }, 1653ca4cacdSPeter Shoults { NULL, NULL, 0 } 1663ca4cacdSPeter Shoults }; 1673ca4cacdSPeter Shoults static int no_krb5auth_flag = 0; 1683ca4cacdSPeter Shoults 1697c478bd9Sstevel@tonic-gate static int encrypt_flag = 0; /* Flag set, when encryption is enabled */ 1707c478bd9Sstevel@tonic-gate static int encrypt_done = 0; /* Flag set, if "-x" is specified */ 1717c478bd9Sstevel@tonic-gate static enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate /* Flag set, if -PN / -PO is specified */ 1747c478bd9Sstevel@tonic-gate static boolean_t rcmdoption_done = B_FALSE; 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate static profile_options_boolean option[] = { 1777c478bd9Sstevel@tonic-gate { "encrypt", &encrypt_flag, 0 }, 1787c478bd9Sstevel@tonic-gate { NULL, NULL, 0 } 1797c478bd9Sstevel@tonic-gate }; 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate static char *rcmdproto = NULL; 1827c478bd9Sstevel@tonic-gate static profile_option_strings rcmdversion[] = { 1837c478bd9Sstevel@tonic-gate { "rcmd_protocol", &rcmdproto, 0 }, 1847c478bd9Sstevel@tonic-gate { NULL, NULL, 0 } 1857c478bd9Sstevel@tonic-gate }; 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate static char *realmdef[] = { "realms", NULL, "rcp", NULL }; 1887c478bd9Sstevel@tonic-gate static char *appdef[] = { "appdefaults", "rcp", NULL }; 1897c478bd9Sstevel@tonic-gate static char **prev_argv; 1907c478bd9Sstevel@tonic-gate static int prev_argc; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate int 1937c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 1947c478bd9Sstevel@tonic-gate { 1957c478bd9Sstevel@tonic-gate int ch, fflag, tflag; 1967c478bd9Sstevel@tonic-gate char *targ; 1977c478bd9Sstevel@tonic-gate size_t cmdsiz; 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if (strcmp(argv[0], RCP_ACL) == 0) 2027c478bd9Sstevel@tonic-gate aclflag = 1; 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate if (!(pwd = getpwuid(userid = getuid()))) { 2057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: unknown user %d.\n", 2067c478bd9Sstevel@tonic-gate (uint_t)userid); 2077c478bd9Sstevel@tonic-gate return (1); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate fflag = tflag = 0; 2113ca4cacdSPeter Shoults while ((ch = getopt(argc, argv, "axdfprtz:D:k:P:ZK")) != EOF) { 2127c478bd9Sstevel@tonic-gate switch (ch) { 2137c478bd9Sstevel@tonic-gate case 'd': 2147c478bd9Sstevel@tonic-gate targetshouldbedirectory = 1; 2157c478bd9Sstevel@tonic-gate break; 2167c478bd9Sstevel@tonic-gate case 'f': /* "from" */ 2177c478bd9Sstevel@tonic-gate fflag = 1; 218fa9e4066Sahrens if (aclflag | acl_aclflag) 2197c478bd9Sstevel@tonic-gate /* ok response */ 2207c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 2217c478bd9Sstevel@tonic-gate break; 2227c478bd9Sstevel@tonic-gate case 'p': /* preserve access/mod times */ 2237c478bd9Sstevel@tonic-gate ++pflag; 2247c478bd9Sstevel@tonic-gate break; 2257c478bd9Sstevel@tonic-gate case 'r': 2267c478bd9Sstevel@tonic-gate ++iamrecursive; 2277c478bd9Sstevel@tonic-gate break; 2287c478bd9Sstevel@tonic-gate case 't': /* "to" */ 2297c478bd9Sstevel@tonic-gate tflag = 1; 2307c478bd9Sstevel@tonic-gate break; 231fa9e4066Sahrens case 'Z': 232fa9e4066Sahrens acl_aclflag++; 233fa9e4066Sahrens break; 2343ca4cacdSPeter Shoults case 'K': 2353ca4cacdSPeter Shoults no_krb5auth_flag++; 2363ca4cacdSPeter Shoults break; 2377c478bd9Sstevel@tonic-gate case 'x': 2387c478bd9Sstevel@tonic-gate if (!krb5_privacy_allowed()) { 2397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: " 2407c478bd9Sstevel@tonic-gate "Encryption not supported.\n")); 2417c478bd9Sstevel@tonic-gate return (1); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate encrypt_flag++; 2447c478bd9Sstevel@tonic-gate krb5auth_flag++; 2457c478bd9Sstevel@tonic-gate encrypt_done++; 2467c478bd9Sstevel@tonic-gate break; 2477c478bd9Sstevel@tonic-gate case 'k': 2487c478bd9Sstevel@tonic-gate if ((krb_realm = (char *)strdup(optarg)) == NULL) { 2497c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp:" 2507c478bd9Sstevel@tonic-gate " Cannot malloc.\n")); 2517c478bd9Sstevel@tonic-gate return (1); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate krb5auth_flag++; 2547c478bd9Sstevel@tonic-gate break; 2557c478bd9Sstevel@tonic-gate case 'P': 2567c478bd9Sstevel@tonic-gate if (strncmp(optarg, "O", 1) == 0) { 2577c478bd9Sstevel@tonic-gate if (rcmdoption_done == B_TRUE) { 2587c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: " 2597c478bd9Sstevel@tonic-gate "Only one of -PN and -PO " 2607c478bd9Sstevel@tonic-gate "allowed.\n")); 2617c478bd9Sstevel@tonic-gate usage(); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 2647c478bd9Sstevel@tonic-gate rcmdoption_done = B_TRUE; 2657c478bd9Sstevel@tonic-gate } else if (strncmp(optarg, "N", 1) == 0) { 2667c478bd9Sstevel@tonic-gate if (rcmdoption_done == B_TRUE) { 2677c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: " 2687c478bd9Sstevel@tonic-gate "Only one of -PN and -PO " 2697c478bd9Sstevel@tonic-gate "allowed.\n")); 2707c478bd9Sstevel@tonic-gate usage(); 2717c478bd9Sstevel@tonic-gate } 2727c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 2737c478bd9Sstevel@tonic-gate rcmdoption_done = B_TRUE; 2747c478bd9Sstevel@tonic-gate } else { 2757c478bd9Sstevel@tonic-gate usage(); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate krb5auth_flag++; 2787c478bd9Sstevel@tonic-gate break; 2797c478bd9Sstevel@tonic-gate case 'a': 2807c478bd9Sstevel@tonic-gate krb5auth_flag++; 2817c478bd9Sstevel@tonic-gate break; 2827c478bd9Sstevel@tonic-gate #ifdef DEBUG 2837c478bd9Sstevel@tonic-gate case 'D': 2847c478bd9Sstevel@tonic-gate portnumber = htons(atoi(optarg)); 2857c478bd9Sstevel@tonic-gate krb5auth_flag++; 2867c478bd9Sstevel@tonic-gate break; 2877c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2887c478bd9Sstevel@tonic-gate case '?': 2897c478bd9Sstevel@tonic-gate default: 2907c478bd9Sstevel@tonic-gate usage(); 2917c478bd9Sstevel@tonic-gate } 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate argc -= optind; 2947c478bd9Sstevel@tonic-gate argv += optind; 2957c478bd9Sstevel@tonic-gate 2963ca4cacdSPeter Shoults /* 2973ca4cacdSPeter Shoults * if the user disables krb5 on the cmdline (-K), then skip 2983ca4cacdSPeter Shoults * all krb5 setup. 2993ca4cacdSPeter Shoults * 3003ca4cacdSPeter Shoults * if the user does not disable krb5 or enable krb5 on the 3013ca4cacdSPeter Shoults * cmdline, check krb5.conf to see if it should be enabled. 3023ca4cacdSPeter Shoults */ 3033ca4cacdSPeter Shoults 3043ca4cacdSPeter Shoults if (no_krb5auth_flag) { 3053ca4cacdSPeter Shoults krb5auth_flag = 0; 3063ca4cacdSPeter Shoults fflag = encrypt_flag = 0; 3073ca4cacdSPeter Shoults } else if (!krb5auth_flag) { 3083ca4cacdSPeter Shoults /* is autologin set in krb5.conf? */ 3093ca4cacdSPeter Shoults status = krb5_init_context(&bsd_context); 3103ca4cacdSPeter Shoults /* don't sweat failure here */ 3113ca4cacdSPeter Shoults if (!status) { 3123ca4cacdSPeter Shoults /* 3133ca4cacdSPeter Shoults * note that the call to profile_get_options_boolean 3143ca4cacdSPeter Shoults * with autologin_option can affect value of 3153ca4cacdSPeter Shoults * krb5auth_flag 3163ca4cacdSPeter Shoults */ 3173ca4cacdSPeter Shoults (void) profile_get_options_boolean(bsd_context->profile, 3183ca4cacdSPeter Shoults appdef, 3193ca4cacdSPeter Shoults autologin_option); 3203ca4cacdSPeter Shoults } 3213ca4cacdSPeter Shoults } 3223ca4cacdSPeter Shoults 3237c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 3243ca4cacdSPeter Shoults if (!bsd_context) { 3257c478bd9Sstevel@tonic-gate status = krb5_init_context(&bsd_context); 3267c478bd9Sstevel@tonic-gate if (status) { 3277c478bd9Sstevel@tonic-gate com_err("rcp", status, 3287c478bd9Sstevel@tonic-gate gettext("while initializing krb5")); 3297c478bd9Sstevel@tonic-gate return (1); 3307c478bd9Sstevel@tonic-gate } 3313ca4cacdSPeter Shoults } 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate /* 3347c478bd9Sstevel@tonic-gate * Set up buffers for desread and deswrite. 3357c478bd9Sstevel@tonic-gate */ 3367c478bd9Sstevel@tonic-gate desinbuf.data = des_inbuf; 3377c478bd9Sstevel@tonic-gate desoutbuf.data = des_outbuf; 3387c478bd9Sstevel@tonic-gate desinbuf.length = sizeof (des_inbuf); 3397c478bd9Sstevel@tonic-gate desoutbuf.length = sizeof (des_outbuf); 3407c478bd9Sstevel@tonic-gate } 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate if (fflag || tflag) 3437c478bd9Sstevel@tonic-gate if (encrypt_flag > 0) 3447c478bd9Sstevel@tonic-gate (void) answer_auth(krb_config, krb_cache); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate if (fflag) { 3477c478bd9Sstevel@tonic-gate iamremote = 1; 3487c478bd9Sstevel@tonic-gate (void) response(); 3497c478bd9Sstevel@tonic-gate (void) setuid(userid); 3507c478bd9Sstevel@tonic-gate source(argc, argv); 3517c478bd9Sstevel@tonic-gate return (errs); 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate if (tflag) { 3557c478bd9Sstevel@tonic-gate iamremote = 1; 3567c478bd9Sstevel@tonic-gate (void) setuid(userid); 3577c478bd9Sstevel@tonic-gate sink(argc, argv); 3587c478bd9Sstevel@tonic-gate return (errs); 3597c478bd9Sstevel@tonic-gate } 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate if (argc < 2) 3627c478bd9Sstevel@tonic-gate usage(); 3637c478bd9Sstevel@tonic-gate 3647c478bd9Sstevel@tonic-gate /* This will make "rcmd_af()" magically get the proper privilege */ 3657c478bd9Sstevel@tonic-gate if (__init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL) == -1) { 3667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: must be set-uid root\n"); 3677c478bd9Sstevel@tonic-gate exit(1); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate 3707c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * Get our local realm to look up local realm options. 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate status = krb5_get_default_realm(bsd_context, &realmdef[1]); 3757c478bd9Sstevel@tonic-gate if (status) { 3767c478bd9Sstevel@tonic-gate com_err("rcp", status, 3777c478bd9Sstevel@tonic-gate gettext("while getting default realm")); 3787c478bd9Sstevel@tonic-gate return (1); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate /* 3817c478bd9Sstevel@tonic-gate * See if encryption should be done for this realm 3827c478bd9Sstevel@tonic-gate */ 3830b4fd3b1SSurya Prakki (void) profile_get_options_boolean(bsd_context->profile, 3840b4fd3b1SSurya Prakki realmdef, option); 3857c478bd9Sstevel@tonic-gate /* 3867c478bd9Sstevel@tonic-gate * Check the appdefaults section 3877c478bd9Sstevel@tonic-gate */ 3880b4fd3b1SSurya Prakki (void) profile_get_options_boolean(bsd_context->profile, 3890b4fd3b1SSurya Prakki appdef, option); 3900b4fd3b1SSurya Prakki (void) profile_get_options_string(bsd_context->profile, 3910b4fd3b1SSurya Prakki appdef, rcmdversion); 3927c478bd9Sstevel@tonic-gate if ((encrypt_done > 0) || (encrypt_flag > 0)) { 3937c478bd9Sstevel@tonic-gate if (krb5_privacy_allowed() == TRUE) { 3947c478bd9Sstevel@tonic-gate encrypt_flag++; 3957c478bd9Sstevel@tonic-gate } else { 3967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Encryption" 3977c478bd9Sstevel@tonic-gate " not supported.\n")); 3987c478bd9Sstevel@tonic-gate return (1); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate } 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate if ((rcmdoption_done == B_FALSE) && (rcmdproto != NULL)) { 4037c478bd9Sstevel@tonic-gate if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { 4047c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 4057c478bd9Sstevel@tonic-gate } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { 4067c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 4077c478bd9Sstevel@tonic-gate } else { 4087c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Unrecognized " 4097c478bd9Sstevel@tonic-gate "KCMD protocol (%s)"), rcmdproto); 4107c478bd9Sstevel@tonic-gate return (1); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate if (argc > 2) 4167c478bd9Sstevel@tonic-gate targetshouldbedirectory = 1; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate rem = -1; 4197c478bd9Sstevel@tonic-gate 4207c478bd9Sstevel@tonic-gate if (portnumber == 0) { 4217c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 4227c478bd9Sstevel@tonic-gate retval = init_service(krb5auth_flag); 4237c478bd9Sstevel@tonic-gate if (!retval) { 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * Connecting to the kshell service failed, 4267c478bd9Sstevel@tonic-gate * fallback to normal rcp & reset KRB5 flags. 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate krb5auth_flag = encrypt_flag = 0; 4297c478bd9Sstevel@tonic-gate encrypt_done = 0; 4307c478bd9Sstevel@tonic-gate (void) init_service(krb5auth_flag); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate else 4347c478bd9Sstevel@tonic-gate (void) init_service(krb5auth_flag); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate #ifdef DEBUG 4387c478bd9Sstevel@tonic-gate if (retval || krb5auth_flag) { 4397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Kerberized rcp session, " 4407c478bd9Sstevel@tonic-gate "port %d in use "), portnumber); 4417c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_OLD_PROTOCOL) 4427c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("[kcmd ver.1]\n")); 4437c478bd9Sstevel@tonic-gate else 4447c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("[kcmd ver.2]\n")); 4457c478bd9Sstevel@tonic-gate } else { 4467c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Normal rcp session, port %d " 4477c478bd9Sstevel@tonic-gate "in use.\n"), portnumber); 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 4527c478bd9Sstevel@tonic-gate /* 4537c478bd9Sstevel@tonic-gate * We calculate here a buffer size that can be used in the 4547c478bd9Sstevel@tonic-gate * allocation of the three buffers cmd, cmd_orig and 4557c478bd9Sstevel@tonic-gate * cmd_sunw_orig that are used to hold different incantations 4567c478bd9Sstevel@tonic-gate * of rcp. 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate cmdsiz = MAX(sizeof ("-x rcp -r -p -d -k ") + 4597c478bd9Sstevel@tonic-gate strlen(krb_realm != NULL ? krb_realm : ""), 4607c478bd9Sstevel@tonic-gate sizeof (RCP_ACL " -r -p -z -d")); 4617c478bd9Sstevel@tonic-gate 4627c478bd9Sstevel@tonic-gate if (((cmd = (char *)malloc(cmdsiz)) == NULL) || 4637c478bd9Sstevel@tonic-gate ((cmd_sunw_orig = (char *)malloc(cmdsiz)) == NULL) || 4647c478bd9Sstevel@tonic-gate ((cmd_orig = (char *)malloc(cmdsiz)) == NULL)) { 4657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Cannot " 4667c478bd9Sstevel@tonic-gate "malloc.\n")); 4677c478bd9Sstevel@tonic-gate return (1); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate 4707c478bd9Sstevel@tonic-gate (void) snprintf(cmd, cmdsiz, "%srcp %s%s%s%s%s", 4717c478bd9Sstevel@tonic-gate encrypt_flag ? "-x " : "", 4727c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", pflag ? " -p" : "", 4737c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : "", 4747c478bd9Sstevel@tonic-gate krb_realm != NULL ? " -k " : "", 4757c478bd9Sstevel@tonic-gate krb_realm != NULL ? krb_realm : ""); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate /* 4787c478bd9Sstevel@tonic-gate * We would use cmd-orig as the 'cmd-buffer' if kerberized 4797c478bd9Sstevel@tonic-gate * rcp fails, in which case we fallback to normal rcp. We also 4807c478bd9Sstevel@tonic-gate * save argc & argv for the same purpose 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate (void) snprintf(cmd_orig, cmdsiz, "rcp%s%s%s%s", 4837c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 4847c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 4857c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 4867c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate (void) snprintf(cmd_sunw_orig, cmdsiz, "%s%s%s%s%s", RCP_ACL, 4897c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 4907c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 4917c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 4927c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate prev_argc = argc; 4957c478bd9Sstevel@tonic-gate prev_argv = save_argv(argc, argv); 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate } else { 4987c478bd9Sstevel@tonic-gate cmdsiz = sizeof ("rcp -r -p -z -d"); 4997c478bd9Sstevel@tonic-gate if (((cmd = (char *)malloc(cmdsiz)) == NULL)) { 5007c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Cannot " 5017c478bd9Sstevel@tonic-gate "malloc.\n")); 5027c478bd9Sstevel@tonic-gate return (1); 5037c478bd9Sstevel@tonic-gate } 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate (void) snprintf(cmd, cmdsiz, "rcp%s%s%s%s", 5067c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 5077c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 5087c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 5097c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 5107c478bd9Sstevel@tonic-gate } 5117c478bd9Sstevel@tonic-gate 5127c478bd9Sstevel@tonic-gate cmdsiz = sizeof (RCP_ACL " -r -p -z -d"); 5137c478bd9Sstevel@tonic-gate if ((cmd_sunw = (char *)malloc(cmdsiz)) == NULL) { 5147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Cannot malloc.\n")); 5157c478bd9Sstevel@tonic-gate return (1); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate (void) snprintf(cmd_sunw, cmdsiz, "%s%s%s%s%s", RCP_ACL, 5197c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 5207c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 5217c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 5227c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 5237c478bd9Sstevel@tonic-gate 5247c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, (void (*)(int))lostconn); 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate if (targ = colon(argv[argc - 1])) 5277c478bd9Sstevel@tonic-gate toremote(targ, argc, argv); 5287c478bd9Sstevel@tonic-gate else { 5297c478bd9Sstevel@tonic-gate tolocal(argc, argv); 5307c478bd9Sstevel@tonic-gate if (targetshouldbedirectory) 5317c478bd9Sstevel@tonic-gate verifydir(argv[argc - 1]); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate return (errs > 0 ? EXIT_FAILURE : EXIT_SUCCESS); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate static void 5397c478bd9Sstevel@tonic-gate toremote(char *targ, int argc, char *argv[]) 5407c478bd9Sstevel@tonic-gate { 5417c478bd9Sstevel@tonic-gate int i; 5427c478bd9Sstevel@tonic-gate char *host, *src, *suser, *thost, *tuser; 5437c478bd9Sstevel@tonic-gate char resp; 5447c478bd9Sstevel@tonic-gate size_t buffersize; 5457c478bd9Sstevel@tonic-gate char bp[RCP_BUFSIZE]; 5467c478bd9Sstevel@tonic-gate krb5_creds *cred; 54740164e4fSsn199410 char *arglist[MAXARGS+1]; 5487c478bd9Sstevel@tonic-gate buffersize = RCP_BUFSIZE; 5497c478bd9Sstevel@tonic-gate 5507c478bd9Sstevel@tonic-gate *targ++ = 0; 5517c478bd9Sstevel@tonic-gate if (*targ == 0) 5527c478bd9Sstevel@tonic-gate targ = "."; 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate if (thost = search_char((unsigned char *)argv[argc - 1], '@')) { 5557c478bd9Sstevel@tonic-gate *thost++ = 0; 5567c478bd9Sstevel@tonic-gate tuser = argv[argc - 1]; 5577c478bd9Sstevel@tonic-gate if (*tuser == '\0') 5587c478bd9Sstevel@tonic-gate tuser = NULL; 5597c478bd9Sstevel@tonic-gate else if (!okname(tuser)) 5607c478bd9Sstevel@tonic-gate exit(1); 5617c478bd9Sstevel@tonic-gate } else { 5627c478bd9Sstevel@tonic-gate thost = argv[argc - 1]; 5637c478bd9Sstevel@tonic-gate tuser = NULL; 5647c478bd9Sstevel@tonic-gate } 5657c478bd9Sstevel@tonic-gate thost = removebrackets(thost); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate for (i = 0; i < argc - 1; i++) { 5687c478bd9Sstevel@tonic-gate src = colon(argv[i]); 5697c478bd9Sstevel@tonic-gate if (src) { /* remote to remote */ 5707c478bd9Sstevel@tonic-gate *src++ = 0; 5717c478bd9Sstevel@tonic-gate if (*src == 0) 5727c478bd9Sstevel@tonic-gate src = "."; 5737c478bd9Sstevel@tonic-gate host = search_char((unsigned char *)argv[i], '@'); 5747c478bd9Sstevel@tonic-gate if (host) { 5757c478bd9Sstevel@tonic-gate *host++ = 0; 5767c478bd9Sstevel@tonic-gate host = removebrackets(host); 5777c478bd9Sstevel@tonic-gate suser = argv[i]; 5787c478bd9Sstevel@tonic-gate if (*suser == '\0') { 5797c478bd9Sstevel@tonic-gate suser = pwd->pw_name; 5807c478bd9Sstevel@tonic-gate } else if (!okname(suser)) { 5817c478bd9Sstevel@tonic-gate errs++; 5827c478bd9Sstevel@tonic-gate continue; 5837c478bd9Sstevel@tonic-gate } 58440164e4fSsn199410 (void) snprintf(bp, buffersize, "'%s%s%s:%s'", 5857c478bd9Sstevel@tonic-gate tuser ? tuser : "", tuser ? "@" : "", 5867c478bd9Sstevel@tonic-gate thost, targ); 58740164e4fSsn199410 (void) addargs(arglist, "rsh", host, "-l", 58840164e4fSsn199410 suser, "-n", cmd, src, bp, (char *)NULL); 5897c478bd9Sstevel@tonic-gate } else { 5907c478bd9Sstevel@tonic-gate host = removebrackets(argv[i]); 59140164e4fSsn199410 (void) snprintf(bp, buffersize, "'%s%s%s:%s'", 5927c478bd9Sstevel@tonic-gate tuser ? tuser : "", tuser ? "@" : "", 5937c478bd9Sstevel@tonic-gate thost, targ); 59440164e4fSsn199410 (void) addargs(arglist, "rsh", host, "-n", cmd, 59540164e4fSsn199410 src, bp, (char *)NULL); 5967c478bd9Sstevel@tonic-gate } 59740164e4fSsn199410 if (susystem(_PATH_RSH, arglist) == -1) 5987c478bd9Sstevel@tonic-gate errs++; 5997c478bd9Sstevel@tonic-gate } else { /* local to remote */ 6007c478bd9Sstevel@tonic-gate if (rem == -1) { 6017c478bd9Sstevel@tonic-gate host = thost; 6027c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, 6057c478bd9Sstevel@tonic-gate "%s -t %s", cmd, targ); 6067c478bd9Sstevel@tonic-gate authopts = AP_OPTS_MUTUAL_REQUIRED; 6077c478bd9Sstevel@tonic-gate status = kcmd(&sock, &host, 6087c478bd9Sstevel@tonic-gate portnumber, 6097c478bd9Sstevel@tonic-gate pwd->pw_name, 6107c478bd9Sstevel@tonic-gate tuser ? tuser : 6117c478bd9Sstevel@tonic-gate pwd->pw_name, 6127c478bd9Sstevel@tonic-gate bp, 6137c478bd9Sstevel@tonic-gate 0, 6147c478bd9Sstevel@tonic-gate "host", 6157c478bd9Sstevel@tonic-gate krb_realm, 6167c478bd9Sstevel@tonic-gate bsd_context, 6177c478bd9Sstevel@tonic-gate &auth_context, 6187c478bd9Sstevel@tonic-gate &cred, 6197c478bd9Sstevel@tonic-gate 0, /* No seq # */ 6207c478bd9Sstevel@tonic-gate 0, /* No server seq # */ 6217c478bd9Sstevel@tonic-gate authopts, 6227c478bd9Sstevel@tonic-gate 0, /* Not any port # */ 6237c478bd9Sstevel@tonic-gate &kcmd_proto); 6247c478bd9Sstevel@tonic-gate if (status) { 6257c478bd9Sstevel@tonic-gate /* 6267c478bd9Sstevel@tonic-gate * If new protocol requested, we dont 6277c478bd9Sstevel@tonic-gate * fallback to less secure ones. 6287c478bd9Sstevel@tonic-gate */ 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 6317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6327c478bd9Sstevel@tonic-gate gettext("rcp: kcmdv2 " 6337c478bd9Sstevel@tonic-gate "to host %s failed - %s" 6347c478bd9Sstevel@tonic-gate "\nFallback to normal " 6357c478bd9Sstevel@tonic-gate "rcp denied."), host, 6367c478bd9Sstevel@tonic-gate error_message(status)); 6377c478bd9Sstevel@tonic-gate exit(1); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate if (status != -1) { 6407c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6417c478bd9Sstevel@tonic-gate gettext("rcp: kcmd to host " 6427c478bd9Sstevel@tonic-gate "%s failed - %s,\n" 6437c478bd9Sstevel@tonic-gate "trying normal rcp...\n\n"), 644e800c2e3SMilan Jurik host, 645e800c2e3SMilan Jurik error_message(status)); 6467c478bd9Sstevel@tonic-gate } else { 6477c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 6487c478bd9Sstevel@tonic-gate gettext("trying normal" 6497c478bd9Sstevel@tonic-gate " rcp...\n")); 6507c478bd9Sstevel@tonic-gate } 6517c478bd9Sstevel@tonic-gate /* 6527c478bd9Sstevel@tonic-gate * kcmd() failed, so we have to 6537c478bd9Sstevel@tonic-gate * fallback to normal rcp 6547c478bd9Sstevel@tonic-gate */ 6557c478bd9Sstevel@tonic-gate try_normal_rcp(prev_argc, prev_argv); 6567c478bd9Sstevel@tonic-gate } else { 6577c478bd9Sstevel@tonic-gate rem = sock; 6587c478bd9Sstevel@tonic-gate session_key = &cred->keyblock; 6597c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 6607c478bd9Sstevel@tonic-gate /* CSTYLED */ 6617c478bd9Sstevel@tonic-gate status = krb5_auth_con_getlocalsubkey(bsd_context, auth_context, &session_key); 6627c478bd9Sstevel@tonic-gate if (status) { 6637c478bd9Sstevel@tonic-gate com_err("rcp", status, 6647c478bd9Sstevel@tonic-gate "determining " 6657c478bd9Sstevel@tonic-gate "subkey for " 6667c478bd9Sstevel@tonic-gate "session"); 6677c478bd9Sstevel@tonic-gate exit(1); 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate if (!session_key) { 6707c478bd9Sstevel@tonic-gate com_err("rcp", 0, 6717c478bd9Sstevel@tonic-gate "no subkey " 6727c478bd9Sstevel@tonic-gate "negotiated for" 6737c478bd9Sstevel@tonic-gate " connection"); 6747c478bd9Sstevel@tonic-gate exit(1); 6757c478bd9Sstevel@tonic-gate } 6767c478bd9Sstevel@tonic-gate } 6777c478bd9Sstevel@tonic-gate eblock.crypto_entry = 6787c478bd9Sstevel@tonic-gate session_key->enctype; 6797c478bd9Sstevel@tonic-gate eblock.key = 6807c478bd9Sstevel@tonic-gate (krb5_keyblock *)session_key; 6817c478bd9Sstevel@tonic-gate 6827c478bd9Sstevel@tonic-gate init_encrypt(encrypt_flag, 6837c478bd9Sstevel@tonic-gate bsd_context, kcmd_proto, 6847c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, 6857c478bd9Sstevel@tonic-gate &eblock); 6867c478bd9Sstevel@tonic-gate if (encrypt_flag > 0) { 6877c478bd9Sstevel@tonic-gate char *s = gettext("This rcp " 6887c478bd9Sstevel@tonic-gate "session is using " 6897c478bd9Sstevel@tonic-gate "encryption for all " 6907c478bd9Sstevel@tonic-gate "data transmissions." 6917c478bd9Sstevel@tonic-gate "\r\n"); 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate (void) write(2, s, strlen(s)); 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate } 6967c478bd9Sstevel@tonic-gate if (response() < 0) 6977c478bd9Sstevel@tonic-gate exit(1); 6987c478bd9Sstevel@tonic-gate 699fa9e4066Sahrens } else { 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 702e800c2e3SMilan Jurik * ACL support: try to find out if the 703e800c2e3SMilan Jurik * remote site is running acl cognizant 704e800c2e3SMilan Jurik * version of rcp. A special binary 705e800c2e3SMilan Jurik * name is used for this purpose. 7067c478bd9Sstevel@tonic-gate */ 7077c478bd9Sstevel@tonic-gate aclflag = 1; 708fa9e4066Sahrens acl_aclflag = 1; 7097c478bd9Sstevel@tonic-gate 710fa9e4066Sahrens /* 711e800c2e3SMilan Jurik * First see if the remote side will 712e800c2e3SMilan Jurik * support both aclent_t and ace_t 713e800c2e3SMilan Jurik * acl's? 714fa9e4066Sahrens */ 715e800c2e3SMilan Jurik (void) snprintf(bp, buffersize, 716e800c2e3SMilan Jurik "%s -tZ %s", 7177c478bd9Sstevel@tonic-gate cmd_sunw, targ); 718e800c2e3SMilan Jurik rem = rcmd_af(&host, portnumber, 719e800c2e3SMilan Jurik pwd->pw_name, 7207c478bd9Sstevel@tonic-gate tuser ? tuser : pwd->pw_name, 7217c478bd9Sstevel@tonic-gate bp, 0, AF_INET6); 7227c478bd9Sstevel@tonic-gate if (rem < 0) 7237c478bd9Sstevel@tonic-gate exit(1); 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate /* 726e800c2e3SMilan Jurik * This is similar to routine 727e800c2e3SMilan Jurik * response(). If response is not ok, 728e800c2e3SMilan Jurik * treat the other side as non-acl rcp. 7297c478bd9Sstevel@tonic-gate */ 7307c478bd9Sstevel@tonic-gate if (read(rem, &resp, sizeof (resp)) 7317c478bd9Sstevel@tonic-gate != sizeof (resp)) 7327c478bd9Sstevel@tonic-gate lostconn(); 7337c478bd9Sstevel@tonic-gate if (resp != 0) { 734fa9e4066Sahrens acl_aclflag = 0; 735fa9e4066Sahrens (void) snprintf(bp, buffersize, 736fa9e4066Sahrens "%s -t %s", cmd_sunw, targ); 737fa9e4066Sahrens 738fa9e4066Sahrens (void) close(rem); 739fa9e4066Sahrens host = thost; 740fa9e4066Sahrens rem = rcmd_af(&host, portnumber, 741fa9e4066Sahrens pwd->pw_name, 742e800c2e3SMilan Jurik tuser ? tuser : 743e800c2e3SMilan Jurik pwd->pw_name, 744fa9e4066Sahrens bp, 0, AF_INET6); 745fa9e4066Sahrens if (rem < 0) 746fa9e4066Sahrens exit(1); 747fa9e4066Sahrens 748e800c2e3SMilan Jurik if (read(rem, &resp, 749e800c2e3SMilan Jurik sizeof (resp)) 750fa9e4066Sahrens != sizeof (resp)) 751fa9e4066Sahrens lostconn(); 752fa9e4066Sahrens if (resp != 0) { 7537c478bd9Sstevel@tonic-gate /* 7547c478bd9Sstevel@tonic-gate * Not OK: 755e800c2e3SMilan Jurik * The other side is 756e800c2e3SMilan Jurik * running non-acl rcp. 757e800c2e3SMilan Jurik * Try again with 758e800c2e3SMilan Jurik * normal stuff. 7597c478bd9Sstevel@tonic-gate */ 7607c478bd9Sstevel@tonic-gate aclflag = 0; 761e800c2e3SMilan Jurik (void) snprintf(bp, 762e800c2e3SMilan Jurik buffersize, 763e800c2e3SMilan Jurik "%s -t %s", cmd, 764e800c2e3SMilan Jurik targ); 7657c478bd9Sstevel@tonic-gate (void) close(rem); 7667c478bd9Sstevel@tonic-gate host = thost; 767e800c2e3SMilan Jurik rem = rcmd_af(&host, 768e800c2e3SMilan Jurik portnumber, 7697c478bd9Sstevel@tonic-gate pwd->pw_name, 7707c478bd9Sstevel@tonic-gate tuser ? tuser : 7717c478bd9Sstevel@tonic-gate pwd->pw_name, bp, 0, 7727c478bd9Sstevel@tonic-gate AF_INET6); 7737c478bd9Sstevel@tonic-gate if (rem < 0) 7747c478bd9Sstevel@tonic-gate exit(1); 7757c478bd9Sstevel@tonic-gate if (response() < 0) 7767c478bd9Sstevel@tonic-gate exit(1); 7777c478bd9Sstevel@tonic-gate } 778fa9e4066Sahrens } 7797c478bd9Sstevel@tonic-gate /* everything should be fine now */ 7807c478bd9Sstevel@tonic-gate (void) setuid(userid); 7817c478bd9Sstevel@tonic-gate 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate source(1, argv + i); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate } 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate static void 7907c478bd9Sstevel@tonic-gate tolocal(int argc, char *argv[]) 7917c478bd9Sstevel@tonic-gate { 7927c478bd9Sstevel@tonic-gate int i; 7937c478bd9Sstevel@tonic-gate char *host, *src, *suser, *lhost; 7947c478bd9Sstevel@tonic-gate char resp; 7957c478bd9Sstevel@tonic-gate size_t buffersize; 7967c478bd9Sstevel@tonic-gate char bp[RCP_BUFSIZE]; 7977c478bd9Sstevel@tonic-gate krb5_creds *cred; 79840164e4fSsn199410 char *arglist[MAXARGS+1]; 7997c478bd9Sstevel@tonic-gate buffersize = RCP_BUFSIZE; 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate for (i = 0; i < argc - 1; i++) { 8027c478bd9Sstevel@tonic-gate if (!(src = colon(argv[i]))) { /* local to local */ 80340164e4fSsn199410 (void) addargs(arglist, "cp", 80440164e4fSsn199410 iamrecursive ? "-r" : "", pflag ? "-p" : "", 80540164e4fSsn199410 zflag ? "-z" : "", argv[i], argv[argc - 1], 80640164e4fSsn199410 (char *)NULL); 80740164e4fSsn199410 if (susystem(_PATH_CP, arglist) == -1) 8087c478bd9Sstevel@tonic-gate errs++; 8097c478bd9Sstevel@tonic-gate continue; 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate *src++ = 0; 8127c478bd9Sstevel@tonic-gate if (*src == 0) 8137c478bd9Sstevel@tonic-gate src = "."; 8147c478bd9Sstevel@tonic-gate host = search_char((unsigned char *)argv[i], '@'); 8157c478bd9Sstevel@tonic-gate if (host) { 8167c478bd9Sstevel@tonic-gate *host++ = 0; 8177c478bd9Sstevel@tonic-gate suser = argv[i]; 8187c478bd9Sstevel@tonic-gate if (*suser == '\0') { 8197c478bd9Sstevel@tonic-gate suser = pwd->pw_name; 8207c478bd9Sstevel@tonic-gate } else if (!okname(suser)) { 8217c478bd9Sstevel@tonic-gate errs++; 8227c478bd9Sstevel@tonic-gate continue; 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate } else { 8257c478bd9Sstevel@tonic-gate host = argv[i]; 8267c478bd9Sstevel@tonic-gate suser = pwd->pw_name; 8277c478bd9Sstevel@tonic-gate } 8287c478bd9Sstevel@tonic-gate host = removebrackets(host); 8297c478bd9Sstevel@tonic-gate lhost = host; 8307c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, "%s -f %s", cmd, src); 8337c478bd9Sstevel@tonic-gate authopts = AP_OPTS_MUTUAL_REQUIRED; 8347c478bd9Sstevel@tonic-gate status = kcmd(&sock, &host, 8357c478bd9Sstevel@tonic-gate portnumber, 8367c478bd9Sstevel@tonic-gate pwd->pw_name, suser, 8377c478bd9Sstevel@tonic-gate bp, 8387c478bd9Sstevel@tonic-gate 0, /* &rfd2 */ 8397c478bd9Sstevel@tonic-gate "host", 8407c478bd9Sstevel@tonic-gate krb_realm, 8417c478bd9Sstevel@tonic-gate bsd_context, 8427c478bd9Sstevel@tonic-gate &auth_context, 8437c478bd9Sstevel@tonic-gate &cred, 8447c478bd9Sstevel@tonic-gate 0, /* No seq # */ 8457c478bd9Sstevel@tonic-gate 0, /* No server seq # */ 8467c478bd9Sstevel@tonic-gate authopts, 8477c478bd9Sstevel@tonic-gate 1, /* Not any port # */ 8487c478bd9Sstevel@tonic-gate &kcmd_proto); 8497c478bd9Sstevel@tonic-gate if (status) { 8507c478bd9Sstevel@tonic-gate /* 8517c478bd9Sstevel@tonic-gate * If new protocol requested, we dont 8527c478bd9Sstevel@tonic-gate * fallback to less secure ones. 8537c478bd9Sstevel@tonic-gate */ 8547c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 855e800c2e3SMilan Jurik (void) fprintf(stderr, 856e800c2e3SMilan Jurik gettext("rcp: kcmdv2 " 8577c478bd9Sstevel@tonic-gate "to host %s failed - %s\n" 8587c478bd9Sstevel@tonic-gate "Fallback to normal rcp denied."), 8597c478bd9Sstevel@tonic-gate host, error_message(status)); 8607c478bd9Sstevel@tonic-gate exit(1); 8617c478bd9Sstevel@tonic-gate } 8627c478bd9Sstevel@tonic-gate if (status != -1) { 863e800c2e3SMilan Jurik (void) fprintf(stderr, 864e800c2e3SMilan Jurik gettext("rcp: kcmd " 8657c478bd9Sstevel@tonic-gate "to host %s failed - %s,\n" 8667c478bd9Sstevel@tonic-gate "trying normal rcp...\n\n"), 8677c478bd9Sstevel@tonic-gate host, error_message(status)); 8687c478bd9Sstevel@tonic-gate } else { 8697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 8707c478bd9Sstevel@tonic-gate gettext("trying normal rcp...\n")); 8717c478bd9Sstevel@tonic-gate } 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * kcmd() failed, so we have to 8747c478bd9Sstevel@tonic-gate * fallback to normal rcp 8757c478bd9Sstevel@tonic-gate */ 8767c478bd9Sstevel@tonic-gate try_normal_rcp(prev_argc, prev_argv); 8777c478bd9Sstevel@tonic-gate } else { 8787c478bd9Sstevel@tonic-gate rem = sock; 8797c478bd9Sstevel@tonic-gate session_key = &cred->keyblock; 8807c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 8817c478bd9Sstevel@tonic-gate status = krb5_auth_con_getlocalsubkey( 8827c478bd9Sstevel@tonic-gate bsd_context, auth_context, 8837c478bd9Sstevel@tonic-gate &session_key); 8847c478bd9Sstevel@tonic-gate if (status) { 885e800c2e3SMilan Jurik com_err("rcp", status, 886e800c2e3SMilan Jurik "determining " 8877c478bd9Sstevel@tonic-gate "subkey for session"); 8887c478bd9Sstevel@tonic-gate exit(1); 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate if (!session_key) { 891e800c2e3SMilan Jurik com_err("rcp", 0, 892e800c2e3SMilan Jurik "no subkey negotiated" 8937c478bd9Sstevel@tonic-gate " for connection"); 8947c478bd9Sstevel@tonic-gate exit(1); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate eblock.crypto_entry = session_key->enctype; 8987c478bd9Sstevel@tonic-gate eblock.key = (krb5_keyblock *)session_key; 8997c478bd9Sstevel@tonic-gate 900e800c2e3SMilan Jurik init_encrypt(encrypt_flag, bsd_context, 901e800c2e3SMilan Jurik kcmd_proto, 9027c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, 9037c478bd9Sstevel@tonic-gate &eblock); 9047c478bd9Sstevel@tonic-gate if (encrypt_flag > 0) { 9057c478bd9Sstevel@tonic-gate char *s = gettext("This rcp " 9067c478bd9Sstevel@tonic-gate "session is using DES " 9077c478bd9Sstevel@tonic-gate "encryption for all " 9087c478bd9Sstevel@tonic-gate "data transmissions." 9097c478bd9Sstevel@tonic-gate "\r\n"); 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate (void) write(2, s, strlen(s)); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate } 9147c478bd9Sstevel@tonic-gate 9157c478bd9Sstevel@tonic-gate } 9167c478bd9Sstevel@tonic-gate else 9177c478bd9Sstevel@tonic-gate { 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* 9207c478bd9Sstevel@tonic-gate * ACL support: try to find out if the remote site is 9217c478bd9Sstevel@tonic-gate * running acl cognizant version of rcp. 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate aclflag = 1; 924fa9e4066Sahrens acl_aclflag = 1; 9257c478bd9Sstevel@tonic-gate 926e800c2e3SMilan Jurik (void) snprintf(bp, buffersize, "%s -Zf %s", cmd_sunw, 927e800c2e3SMilan Jurik src); 9287c478bd9Sstevel@tonic-gate rem = rcmd_af(&host, portnumber, pwd->pw_name, suser, 9297c478bd9Sstevel@tonic-gate bp, 0, AF_INET6); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate if (rem < 0) { 9327c478bd9Sstevel@tonic-gate ++errs; 9337c478bd9Sstevel@tonic-gate continue; 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate 9367c478bd9Sstevel@tonic-gate /* 9377c478bd9Sstevel@tonic-gate * The remote system is supposed to send an ok response. 938e800c2e3SMilan Jurik * If there are any data other than "ok", it must be 939e800c2e3SMilan Jurik * error messages from the remote system. We can assume 940e800c2e3SMilan Jurik * the remote system is running non-acl version rcp. 9417c478bd9Sstevel@tonic-gate */ 9427c478bd9Sstevel@tonic-gate if (read(rem, &resp, sizeof (resp)) != sizeof (resp)) 9437c478bd9Sstevel@tonic-gate lostconn(); 944e800c2e3SMilan Jurik 9457c478bd9Sstevel@tonic-gate if (resp != 0) { 946fa9e4066Sahrens 947fa9e4066Sahrens /* 948fa9e4066Sahrens * Try again without ace_acl support 949fa9e4066Sahrens */ 950fa9e4066Sahrens acl_aclflag = 0; 951fa9e4066Sahrens (void) snprintf(bp, buffersize, "%s -f %s", 952fa9e4066Sahrens cmd_sunw, src); 953e800c2e3SMilan Jurik (void) close(rem); 954e800c2e3SMilan Jurik rem = rcmd_af(&host, portnumber, pwd->pw_name, 955e800c2e3SMilan Jurik suser, bp, 0, AF_INET6); 956fa9e4066Sahrens 957fa9e4066Sahrens if (rem < 0) { 958fa9e4066Sahrens ++errs; 959fa9e4066Sahrens continue; 960fa9e4066Sahrens } 961fa9e4066Sahrens 962e800c2e3SMilan Jurik if (read(rem, &resp, 963e800c2e3SMilan Jurik sizeof (resp)) != sizeof (resp)) 964fa9e4066Sahrens lostconn(); 965fa9e4066Sahrens 966e800c2e3SMilan Jurik if (resp != 0) { 9677c478bd9Sstevel@tonic-gate /* 9687c478bd9Sstevel@tonic-gate * NOT ok: 969e800c2e3SMilan Jurik * The other side is running non-acl 970e800c2e3SMilan Jurik * rcp. Try again with normal stuff. 9717c478bd9Sstevel@tonic-gate */ 9727c478bd9Sstevel@tonic-gate aclflag = 0; 973e800c2e3SMilan Jurik (void) snprintf(bp, buffersize, 974e800c2e3SMilan Jurik "%s -f %s", cmd, src); 9757c478bd9Sstevel@tonic-gate (void) close(rem); 9767c478bd9Sstevel@tonic-gate host = lhost; 977e800c2e3SMilan Jurik rem = rcmd_af(&host, portnumber, 978e800c2e3SMilan Jurik pwd->pw_name, suser, bp, 0, 979e800c2e3SMilan Jurik AF_INET6); 9807c478bd9Sstevel@tonic-gate if (rem < 0) { 9817c478bd9Sstevel@tonic-gate ++errs; 9827c478bd9Sstevel@tonic-gate continue; 9837c478bd9Sstevel@tonic-gate } 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate } 986e800c2e3SMilan Jurik } 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate sink(1, argv + argc - 1); 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate (void) close(rem); 9917c478bd9Sstevel@tonic-gate rem = -1; 9927c478bd9Sstevel@tonic-gate } 9937c478bd9Sstevel@tonic-gate } 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate static void 9977c478bd9Sstevel@tonic-gate verifydir(char *cp) 9987c478bd9Sstevel@tonic-gate { 9997c478bd9Sstevel@tonic-gate struct stat stb; 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate if (stat(cp, &stb) >= 0) { 10027c478bd9Sstevel@tonic-gate if ((stb.st_mode & S_IFMT) == S_IFDIR) 10037c478bd9Sstevel@tonic-gate return; 10047c478bd9Sstevel@tonic-gate errno = ENOTDIR; 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate error("rcp: %s: %s.\n", cp, strerror(errno)); 10077c478bd9Sstevel@tonic-gate exit(1); 10087c478bd9Sstevel@tonic-gate } 10097c478bd9Sstevel@tonic-gate 10107c478bd9Sstevel@tonic-gate static char * 10117c478bd9Sstevel@tonic-gate colon(char *cp) 10127c478bd9Sstevel@tonic-gate { 10137c478bd9Sstevel@tonic-gate boolean_t is_bracket_open = B_FALSE; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate for (; *cp; ++cp) { 10167c478bd9Sstevel@tonic-gate if (*cp == '[') 10177c478bd9Sstevel@tonic-gate is_bracket_open = B_TRUE; 10187c478bd9Sstevel@tonic-gate else if (*cp == ']') 10197c478bd9Sstevel@tonic-gate is_bracket_open = B_FALSE; 10207c478bd9Sstevel@tonic-gate else if (*cp == ':' && !is_bracket_open) 10217c478bd9Sstevel@tonic-gate return (cp); 10227c478bd9Sstevel@tonic-gate else if (*cp == '/') 10237c478bd9Sstevel@tonic-gate return (0); 10247c478bd9Sstevel@tonic-gate } 10257c478bd9Sstevel@tonic-gate return (0); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate 10287c478bd9Sstevel@tonic-gate static int 10297c478bd9Sstevel@tonic-gate okname(char *cp0) 10307c478bd9Sstevel@tonic-gate { 10317c478bd9Sstevel@tonic-gate register char *cp = cp0; 10327c478bd9Sstevel@tonic-gate register int c; 10337c478bd9Sstevel@tonic-gate 10347c478bd9Sstevel@tonic-gate do { 10357c478bd9Sstevel@tonic-gate c = *cp; 10367c478bd9Sstevel@tonic-gate if (c & 0200) 10377c478bd9Sstevel@tonic-gate goto bad; 10387c478bd9Sstevel@tonic-gate if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 10397c478bd9Sstevel@tonic-gate goto bad; 10407c478bd9Sstevel@tonic-gate } while (*++cp); 10417c478bd9Sstevel@tonic-gate return (1); 10427c478bd9Sstevel@tonic-gate bad: 10437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: invalid user name %s\n", cp0); 10447c478bd9Sstevel@tonic-gate return (0); 10457c478bd9Sstevel@tonic-gate } 10467c478bd9Sstevel@tonic-gate 10477c478bd9Sstevel@tonic-gate 10487c478bd9Sstevel@tonic-gate static char * 10497c478bd9Sstevel@tonic-gate removebrackets(char *str) 10507c478bd9Sstevel@tonic-gate { 10517c478bd9Sstevel@tonic-gate char *newstr = str; 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate if ((str[0] == '[') && (str[strlen(str) - 1] == ']')) { 10547c478bd9Sstevel@tonic-gate newstr = str + 1; 10557c478bd9Sstevel@tonic-gate str[strlen(str) - 1] = '\0'; 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate return (newstr); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate static int 106140164e4fSsn199410 susystem(char *path, char **arglist) 10627c478bd9Sstevel@tonic-gate { 10637c478bd9Sstevel@tonic-gate int status, pid, w; 10647c478bd9Sstevel@tonic-gate register void (*istat)(), (*qstat)(); 10657c478bd9Sstevel@tonic-gate int pfds[2]; 10667c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 10677c478bd9Sstevel@tonic-gate int cnt; 10687c478bd9Sstevel@tonic-gate boolean_t seen_stderr_traffic; 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate /* 10717c478bd9Sstevel@tonic-gate * Due to the fact that rcp uses rsh to copy between 2 remote 10727c478bd9Sstevel@tonic-gate * machines, rsh doesn't return the exit status of the remote 10737c478bd9Sstevel@tonic-gate * command, and we can't modify the rcmd protocol used by rsh 10747c478bd9Sstevel@tonic-gate * (for interoperability reasons) we use the hack of using any 10757c478bd9Sstevel@tonic-gate * output on stderr as indication that an error occurred and 10767c478bd9Sstevel@tonic-gate * that we should return a non-zero error code. 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate 10797c478bd9Sstevel@tonic-gate if (pipe(pfds) == -1) { 10807c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Couldn't create pipe: %s\n", 10817c478bd9Sstevel@tonic-gate strerror(errno)); 10827c478bd9Sstevel@tonic-gate return (-1); 10837c478bd9Sstevel@tonic-gate } 10847c478bd9Sstevel@tonic-gate 10857c478bd9Sstevel@tonic-gate if ((pid = vfork()) < 0) { 10867c478bd9Sstevel@tonic-gate (void) close(pfds[0]); 10877c478bd9Sstevel@tonic-gate (void) close(pfds[1]); 10887c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Couldn't fork child process: %s\n", 10897c478bd9Sstevel@tonic-gate strerror(errno)); 10907c478bd9Sstevel@tonic-gate return (-1); 10917c478bd9Sstevel@tonic-gate } else if (pid == 0) { 10927c478bd9Sstevel@tonic-gate /* 10937c478bd9Sstevel@tonic-gate * Child. 10947c478bd9Sstevel@tonic-gate */ 10957c478bd9Sstevel@tonic-gate (void) close(pfds[0]); 10967c478bd9Sstevel@tonic-gate /* 10977c478bd9Sstevel@tonic-gate * Send stderr messages down the pipe so that we can detect 10987c478bd9Sstevel@tonic-gate * them in the parent process. 10997c478bd9Sstevel@tonic-gate */ 11007c478bd9Sstevel@tonic-gate if (pfds[1] != STDERR_FILENO) { 11017c478bd9Sstevel@tonic-gate (void) dup2(pfds[1], STDERR_FILENO); 11027c478bd9Sstevel@tonic-gate (void) close(pfds[1]); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate /* 11057c478bd9Sstevel@tonic-gate * This shell does not inherit the additional privilege 11067c478bd9Sstevel@tonic-gate * we have in our Permitted set. 11077c478bd9Sstevel@tonic-gate */ 110840164e4fSsn199410 (void) execv(path, arglist); 11097c478bd9Sstevel@tonic-gate _exit(127); 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate /* 11127c478bd9Sstevel@tonic-gate * Parent. 11137c478bd9Sstevel@tonic-gate */ 11147c478bd9Sstevel@tonic-gate istat = signal(SIGINT, SIG_IGN); 11157c478bd9Sstevel@tonic-gate qstat = signal(SIGQUIT, SIG_IGN); 11167c478bd9Sstevel@tonic-gate 11177c478bd9Sstevel@tonic-gate (void) close(pfds[1]); 11187c478bd9Sstevel@tonic-gate seen_stderr_traffic = B_FALSE; 11197c478bd9Sstevel@tonic-gate while ((cnt = read(pfds[0], buf, sizeof (buf))) > 0) { 11207c478bd9Sstevel@tonic-gate /* 11217c478bd9Sstevel@tonic-gate * If any data is read from the pipe the child process 11227c478bd9Sstevel@tonic-gate * has output something on stderr so we set the boolean 11237c478bd9Sstevel@tonic-gate * 'seen_stderr_traffic' to true, which will cause the 11247c478bd9Sstevel@tonic-gate * function to return -1. 11257c478bd9Sstevel@tonic-gate */ 11267c478bd9Sstevel@tonic-gate (void) write(STDERR_FILENO, buf, cnt); 11277c478bd9Sstevel@tonic-gate seen_stderr_traffic = B_TRUE; 11287c478bd9Sstevel@tonic-gate } 11297c478bd9Sstevel@tonic-gate (void) close(pfds[0]); 11307c478bd9Sstevel@tonic-gate while ((w = wait(&status)) != pid && w != -1) 11317c478bd9Sstevel@tonic-gate ; 11327c478bd9Sstevel@tonic-gate if (w == -1) 11337c478bd9Sstevel@tonic-gate status = -1; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate (void) signal(SIGINT, istat); 11367c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, qstat); 11377c478bd9Sstevel@tonic-gate 11387c478bd9Sstevel@tonic-gate return (seen_stderr_traffic ? -1 : status); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate static void 11427c478bd9Sstevel@tonic-gate source(int argc, char *argv[]) 11437c478bd9Sstevel@tonic-gate { 11447c478bd9Sstevel@tonic-gate struct stat stb; 11457c478bd9Sstevel@tonic-gate static BUF buffer; 11467c478bd9Sstevel@tonic-gate BUF *bp; 11477c478bd9Sstevel@tonic-gate int x, readerr, f, amt; 11487c478bd9Sstevel@tonic-gate char *last, *name, buf[RCP_BUFSIZE]; 11497c478bd9Sstevel@tonic-gate off_t off, size, i; 11507c478bd9Sstevel@tonic-gate ssize_t cnt; 11516d2b079bSjs198686 struct linger lingerbuf; 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate for (x = 0; x < argc; x++) { 11547c478bd9Sstevel@tonic-gate name = argv[x]; 11557c478bd9Sstevel@tonic-gate if ((f = open(name, O_RDONLY, 0)) < 0) { 11567c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, strerror(errno)); 11577c478bd9Sstevel@tonic-gate continue; 11587c478bd9Sstevel@tonic-gate } 11597c478bd9Sstevel@tonic-gate if (fstat(f, &stb) < 0) 11607c478bd9Sstevel@tonic-gate goto notreg; 11617c478bd9Sstevel@tonic-gate switch (stb.st_mode&S_IFMT) { 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate case S_IFREG: 11647c478bd9Sstevel@tonic-gate break; 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate case S_IFDIR: 11677c478bd9Sstevel@tonic-gate if (iamrecursive) { 11687c478bd9Sstevel@tonic-gate (void) close(f); 11697c478bd9Sstevel@tonic-gate rsource(name, &stb); 11707c478bd9Sstevel@tonic-gate continue; 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 11737c478bd9Sstevel@tonic-gate default: 11747c478bd9Sstevel@tonic-gate notreg: 11757c478bd9Sstevel@tonic-gate (void) close(f); 11767c478bd9Sstevel@tonic-gate error("rcp: %s: not a plain file\n", name); 11777c478bd9Sstevel@tonic-gate continue; 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate last = rindex(name, '/'); 11807c478bd9Sstevel@tonic-gate if (last == 0) 11817c478bd9Sstevel@tonic-gate last = name; 11827c478bd9Sstevel@tonic-gate else 11837c478bd9Sstevel@tonic-gate last++; 11847c478bd9Sstevel@tonic-gate if (pflag) { 11857c478bd9Sstevel@tonic-gate time_t mtime, atime; 11867c478bd9Sstevel@tonic-gate time_t now; 11877c478bd9Sstevel@tonic-gate 11887c478bd9Sstevel@tonic-gate /* 11897c478bd9Sstevel@tonic-gate * Make it compatible with possible future 11907c478bd9Sstevel@tonic-gate * versions expecting microseconds. 11917c478bd9Sstevel@tonic-gate */ 11927c478bd9Sstevel@tonic-gate mtime = stb.st_mtime; 11937c478bd9Sstevel@tonic-gate atime = stb.st_atime; 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate if ((mtime < 0) || (atime < 0)) { 11967c478bd9Sstevel@tonic-gate now = time(NULL); 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate if (mtime < 0) { 11997c478bd9Sstevel@tonic-gate mtime = now; 12007c478bd9Sstevel@tonic-gate error("negative modification time on " 12017c478bd9Sstevel@tonic-gate "%s; not preserving\n", name); 12027c478bd9Sstevel@tonic-gate } 12037c478bd9Sstevel@tonic-gate if (atime < 0) { 12047c478bd9Sstevel@tonic-gate atime = now; 12057c478bd9Sstevel@tonic-gate error("negative access time on " 12067c478bd9Sstevel@tonic-gate "%s; not preserving\n", name); 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate } 12097c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "T%ld 0 %ld 0\n", 12107c478bd9Sstevel@tonic-gate mtime, atime); 12117c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 12127c478bd9Sstevel@tonic-gate if (response() < 0) { 12137c478bd9Sstevel@tonic-gate (void) close(f); 12147c478bd9Sstevel@tonic-gate continue; 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate } 12177c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "C%04o %lld %s\n", 12187c478bd9Sstevel@tonic-gate (uint_t)(stb.st_mode & 07777), (longlong_t)stb.st_size, 12197c478bd9Sstevel@tonic-gate last); 12207c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 12217c478bd9Sstevel@tonic-gate if (response() < 0) { 12227c478bd9Sstevel@tonic-gate (void) close(f); 12237c478bd9Sstevel@tonic-gate continue; 12247c478bd9Sstevel@tonic-gate } 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate /* ACL support: send */ 1227fa9e4066Sahrens if (aclflag | acl_aclflag) { 12287c478bd9Sstevel@tonic-gate /* get acl from f and send it over */ 12297c478bd9Sstevel@tonic-gate if (sendacl(f) == ACL_FAIL) { 12307c478bd9Sstevel@tonic-gate (void) close(f); 12317c478bd9Sstevel@tonic-gate continue; 12327c478bd9Sstevel@tonic-gate } 12337c478bd9Sstevel@tonic-gate } 12347c478bd9Sstevel@tonic-gate if ((krb5auth_flag > 0) || (iamremote == 1)) { 12357c478bd9Sstevel@tonic-gate bp = allocbuf(&buffer, f, RCP_BUFSIZE); 12367c478bd9Sstevel@tonic-gate if (bp == NULLBUF) { 12377c478bd9Sstevel@tonic-gate (void) close(f); 12387c478bd9Sstevel@tonic-gate continue; 12397c478bd9Sstevel@tonic-gate } 12407c478bd9Sstevel@tonic-gate readerr = 0; 12417c478bd9Sstevel@tonic-gate for (i = 0; i < stb.st_size; i += bp->cnt) { 12427c478bd9Sstevel@tonic-gate amt = bp->cnt; 12437c478bd9Sstevel@tonic-gate if (i + amt > stb.st_size) 12447c478bd9Sstevel@tonic-gate amt = stb.st_size - i; 12457c478bd9Sstevel@tonic-gate if (readerr == 0 && 12467c478bd9Sstevel@tonic-gate read(f, bp->buf, amt) != amt) 12477c478bd9Sstevel@tonic-gate readerr = errno; 12487c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, bp->buf, amt); 12497c478bd9Sstevel@tonic-gate } 12507c478bd9Sstevel@tonic-gate (void) close(f); 12517c478bd9Sstevel@tonic-gate if (readerr == 0) 12527c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 12537c478bd9Sstevel@tonic-gate else 12547c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, 12557c478bd9Sstevel@tonic-gate error_message(readerr)); 12567c478bd9Sstevel@tonic-gate } else { 12577c478bd9Sstevel@tonic-gate cnt = off = 0; 12587c478bd9Sstevel@tonic-gate size = stb.st_size; 12597c478bd9Sstevel@tonic-gate while (size != 0) { 12607c478bd9Sstevel@tonic-gate amt = MIN(size, SENDFILE_SIZE); 12617c478bd9Sstevel@tonic-gate cnt = sendfile(rem, f, &off, amt); 12629760e1c4Sblu if (cnt == -1) { 12639760e1c4Sblu if (errno == EINTR) { 12649760e1c4Sblu continue; 12659760e1c4Sblu } else { 12667c478bd9Sstevel@tonic-gate break; 12679760e1c4Sblu } 12689760e1c4Sblu } 12696d2b079bSjs198686 if (cnt == 0) 12706d2b079bSjs198686 break; 12717c478bd9Sstevel@tonic-gate size -= cnt; 12727c478bd9Sstevel@tonic-gate } 12736d2b079bSjs198686 if (cnt < 0) { 12747c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, strerror(errno)); 12756d2b079bSjs198686 } else if (cnt == 0 && size != 0) { 12766d2b079bSjs198686 error("rcp: %s: unexpected end of file\n", 12776d2b079bSjs198686 name); 12786d2b079bSjs198686 lingerbuf.l_onoff = 1; 12796d2b079bSjs198686 lingerbuf.l_linger = 0; 12806d2b079bSjs198686 (void) setsockopt(rem, SOL_SOCKET, SO_LINGER, 12816d2b079bSjs198686 &lingerbuf, sizeof (lingerbuf)); 12826d2b079bSjs198686 /* 12836d2b079bSjs198686 * When response() (see below) is invoked it 12846d2b079bSjs198686 * tries to read data from closed handle which 12856d2b079bSjs198686 * triggers error and lostconn() function. 12866d2b079bSjs198686 * lostconn() terminates the program with 12876d2b079bSjs198686 * appropriate message. 12886d2b079bSjs198686 */ 12896d2b079bSjs198686 (void) close(rem); 12906d2b079bSjs198686 rem = -1; 12917c478bd9Sstevel@tonic-gate } else { 12927c478bd9Sstevel@tonic-gate (void) write(rem, "", 1); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate (void) close(f); 12957c478bd9Sstevel@tonic-gate } 12967c478bd9Sstevel@tonic-gate (void) response(); 12977c478bd9Sstevel@tonic-gate } 12987c478bd9Sstevel@tonic-gate } 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate 13017c478bd9Sstevel@tonic-gate static void 13027c478bd9Sstevel@tonic-gate rsource(char *name, struct stat *statp) 13037c478bd9Sstevel@tonic-gate { 13047c478bd9Sstevel@tonic-gate DIR *d; 13057c478bd9Sstevel@tonic-gate struct dirent *dp; 13067c478bd9Sstevel@tonic-gate char *last, *vect[1]; 13077c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate if (!(d = opendir(name))) { 13107c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, strerror(errno)); 13117c478bd9Sstevel@tonic-gate return; 13127c478bd9Sstevel@tonic-gate } 13137c478bd9Sstevel@tonic-gate last = rindex(name, '/'); 13147c478bd9Sstevel@tonic-gate if (last == 0) 13157c478bd9Sstevel@tonic-gate last = name; 13167c478bd9Sstevel@tonic-gate else 13177c478bd9Sstevel@tonic-gate last++; 13187c478bd9Sstevel@tonic-gate if (pflag) { 13197c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "T%ld 0 %ld 0\n", 13207c478bd9Sstevel@tonic-gate statp->st_mtime, statp->st_atime); 13217c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, path, strlen(path)); 13227c478bd9Sstevel@tonic-gate if (response() < 0) { 13237c478bd9Sstevel@tonic-gate (void) closedir(d); 13247c478bd9Sstevel@tonic-gate return; 13257c478bd9Sstevel@tonic-gate } 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "D%04o %d %s\n", 13287c478bd9Sstevel@tonic-gate (uint_t)(statp->st_mode & 07777), 0, last); 13297c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, path, strlen(path)); 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate /* acl support for directory */ 13327c478bd9Sstevel@tonic-gate if (aclflag) { 13337c478bd9Sstevel@tonic-gate /* get acl from f and send it over */ 13347c478bd9Sstevel@tonic-gate if (sendacl(d->dd_fd) == ACL_FAIL) { 13357c478bd9Sstevel@tonic-gate (void) closedir(d); 13367c478bd9Sstevel@tonic-gate return; 13377c478bd9Sstevel@tonic-gate } 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate if (response() < 0) { 13417c478bd9Sstevel@tonic-gate (void) closedir(d); 13427c478bd9Sstevel@tonic-gate return; 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate 13457c478bd9Sstevel@tonic-gate while (dp = readdir(d)) { 13467c478bd9Sstevel@tonic-gate if (dp->d_ino == 0) 13477c478bd9Sstevel@tonic-gate continue; 13487c478bd9Sstevel@tonic-gate if ((strcmp(dp->d_name, ".") == 0) || 13497c478bd9Sstevel@tonic-gate (strcmp(dp->d_name, "..") == 0)) 13507c478bd9Sstevel@tonic-gate continue; 13517c478bd9Sstevel@tonic-gate if ((uint_t)strlen(name) + 1 + strlen(dp->d_name) >= 13527c478bd9Sstevel@tonic-gate MAXPATHLEN - 1) { 13537c478bd9Sstevel@tonic-gate error("%s/%s: name too long.\n", name, dp->d_name); 13547c478bd9Sstevel@tonic-gate continue; 13557c478bd9Sstevel@tonic-gate } 13567c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%s", 13577c478bd9Sstevel@tonic-gate name, dp->d_name); 13587c478bd9Sstevel@tonic-gate vect[0] = path; 13597c478bd9Sstevel@tonic-gate source(1, vect); 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate (void) closedir(d); 13627c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "E\n", 2); 13637c478bd9Sstevel@tonic-gate (void) response(); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate static int 13677c478bd9Sstevel@tonic-gate response(void) 13687c478bd9Sstevel@tonic-gate { 13697c478bd9Sstevel@tonic-gate register char *cp; 13707c478bd9Sstevel@tonic-gate char ch, resp, rbuf[RCP_BUFSIZE]; 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate if (desrcpread(rem, &resp, 1) != 1) 13737c478bd9Sstevel@tonic-gate lostconn(); 13747c478bd9Sstevel@tonic-gate cp = rbuf; 13757c478bd9Sstevel@tonic-gate switch (resp) { 13767c478bd9Sstevel@tonic-gate case 0: /* ok */ 13777c478bd9Sstevel@tonic-gate return (0); 13787c478bd9Sstevel@tonic-gate default: 13797c478bd9Sstevel@tonic-gate *cp++ = resp; 13807c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 13817c478bd9Sstevel@tonic-gate case 1: /* error, followed by err msg */ 13827c478bd9Sstevel@tonic-gate case 2: /* fatal error, "" */ 13837c478bd9Sstevel@tonic-gate do { 13847c478bd9Sstevel@tonic-gate if (desrcpread(rem, &ch, sizeof (ch)) != sizeof (ch)) 13857c478bd9Sstevel@tonic-gate lostconn(); 13867c478bd9Sstevel@tonic-gate *cp++ = ch; 13877c478bd9Sstevel@tonic-gate } while (cp < &rbuf[RCP_BUFSIZE] && ch != '\n'); 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate if (!iamremote) 13907c478bd9Sstevel@tonic-gate (void) write(STDERR_FILENO, rbuf, cp - rbuf); 13917c478bd9Sstevel@tonic-gate ++errs; 13927c478bd9Sstevel@tonic-gate if (resp == 1) 13937c478bd9Sstevel@tonic-gate return (-1); 13947c478bd9Sstevel@tonic-gate exit(1); 13957c478bd9Sstevel@tonic-gate } 13967c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 13977c478bd9Sstevel@tonic-gate } 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate static void 14007c478bd9Sstevel@tonic-gate lostconn(void) 14017c478bd9Sstevel@tonic-gate { 14027c478bd9Sstevel@tonic-gate if (!iamremote) 14037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: lost connection\n"); 14047c478bd9Sstevel@tonic-gate exit(1); 14057c478bd9Sstevel@tonic-gate } 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate 14087c478bd9Sstevel@tonic-gate static void 14097c478bd9Sstevel@tonic-gate sink(int argc, char *argv[]) 14107c478bd9Sstevel@tonic-gate { 14117c478bd9Sstevel@tonic-gate char *cp; 14127c478bd9Sstevel@tonic-gate static BUF buffer; 14137c478bd9Sstevel@tonic-gate struct stat stb; 14147c478bd9Sstevel@tonic-gate struct timeval tv[2]; 14157c478bd9Sstevel@tonic-gate BUF *bp; 14167c478bd9Sstevel@tonic-gate off_t i, j; 14177c478bd9Sstevel@tonic-gate char ch, *targ, *why; 14187c478bd9Sstevel@tonic-gate int amt, count, exists, first, mask, mode; 14197c478bd9Sstevel@tonic-gate off_t size; 14207c478bd9Sstevel@tonic-gate int ofd, setimes, targisdir, wrerr; 14217c478bd9Sstevel@tonic-gate char *np, *vect[1], buf[RCP_BUFSIZE]; 14227c478bd9Sstevel@tonic-gate char *namebuf = NULL; 14237c478bd9Sstevel@tonic-gate size_t namebuf_sz = 0; 14247c478bd9Sstevel@tonic-gate size_t need; 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate #define atime tv[0] 14277c478bd9Sstevel@tonic-gate #define mtime tv[1] 14287c478bd9Sstevel@tonic-gate #define SCREWUP(str) { why = str; goto screwup; } 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate setimes = targisdir = 0; 14317c478bd9Sstevel@tonic-gate mask = umask(0); 14327c478bd9Sstevel@tonic-gate if (!pflag) 14337c478bd9Sstevel@tonic-gate (void) umask(mask); 14347c478bd9Sstevel@tonic-gate if (argc != 1) { 14357c478bd9Sstevel@tonic-gate error("rcp: ambiguous target\n"); 14367c478bd9Sstevel@tonic-gate exit(1); 14377c478bd9Sstevel@tonic-gate } 14387c478bd9Sstevel@tonic-gate targ = *argv; 14397c478bd9Sstevel@tonic-gate if (targetshouldbedirectory) 14407c478bd9Sstevel@tonic-gate verifydir(targ); 14417c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 14427c478bd9Sstevel@tonic-gate 14437c478bd9Sstevel@tonic-gate if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 14447c478bd9Sstevel@tonic-gate targisdir = 1; 14457c478bd9Sstevel@tonic-gate for (first = 1; ; first = 0) { 14467c478bd9Sstevel@tonic-gate cp = buf; 14477c478bd9Sstevel@tonic-gate if (desrcpread(rem, cp, 1) <= 0) { 14487c478bd9Sstevel@tonic-gate if (namebuf != NULL) 14497c478bd9Sstevel@tonic-gate free(namebuf); 14507c478bd9Sstevel@tonic-gate return; 14517c478bd9Sstevel@tonic-gate } 14527c478bd9Sstevel@tonic-gate 14537c478bd9Sstevel@tonic-gate if (*cp++ == '\n') 14547c478bd9Sstevel@tonic-gate SCREWUP("unexpected <newline>"); 14557c478bd9Sstevel@tonic-gate do { 14567c478bd9Sstevel@tonic-gate if (desrcpread(rem, &ch, sizeof (ch)) != sizeof (ch)) 14577c478bd9Sstevel@tonic-gate SCREWUP("lost connection"); 14587c478bd9Sstevel@tonic-gate *cp++ = ch; 14597c478bd9Sstevel@tonic-gate } while (cp < &buf[RCP_BUFSIZE - 1] && ch != '\n'); 14607c478bd9Sstevel@tonic-gate *cp = 0; 14617c478bd9Sstevel@tonic-gate 14627c478bd9Sstevel@tonic-gate if (buf[0] == '\01' || buf[0] == '\02') { 14637c478bd9Sstevel@tonic-gate if (iamremote == 0) 14647c478bd9Sstevel@tonic-gate (void) write(STDERR_FILENO, buf + 1, 14657c478bd9Sstevel@tonic-gate strlen(buf + 1)); 14667c478bd9Sstevel@tonic-gate if (buf[0] == '\02') 14677c478bd9Sstevel@tonic-gate exit(1); 14687c478bd9Sstevel@tonic-gate errs++; 14697c478bd9Sstevel@tonic-gate continue; 14707c478bd9Sstevel@tonic-gate } 14717c478bd9Sstevel@tonic-gate if (buf[0] == 'E') { 14727c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 14737c478bd9Sstevel@tonic-gate if (namebuf != NULL) 14747c478bd9Sstevel@tonic-gate free(namebuf); 14757c478bd9Sstevel@tonic-gate return; 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate 14787c478bd9Sstevel@tonic-gate if (ch == '\n') 14797c478bd9Sstevel@tonic-gate *--cp = 0; 14807c478bd9Sstevel@tonic-gate cp = buf; 14817c478bd9Sstevel@tonic-gate if (*cp == 'T') { 14827c478bd9Sstevel@tonic-gate setimes++; 14837c478bd9Sstevel@tonic-gate cp++; 14847c478bd9Sstevel@tonic-gate mtime.tv_sec = strtol(cp, &cp, 0); 14857c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 14867c478bd9Sstevel@tonic-gate SCREWUP("mtime.sec not delimited"); 14877c478bd9Sstevel@tonic-gate mtime.tv_usec = strtol(cp, &cp, 0); 14887c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 14897c478bd9Sstevel@tonic-gate SCREWUP("mtime.usec not delimited"); 14907c478bd9Sstevel@tonic-gate atime.tv_sec = strtol(cp, &cp, 0); 14917c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 14927c478bd9Sstevel@tonic-gate SCREWUP("atime.sec not delimited"); 14937c478bd9Sstevel@tonic-gate atime.tv_usec = strtol(cp, &cp, 0); 14947c478bd9Sstevel@tonic-gate if (*cp++ != '\0') 14957c478bd9Sstevel@tonic-gate SCREWUP("atime.usec not delimited"); 14967c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 14977c478bd9Sstevel@tonic-gate continue; 14987c478bd9Sstevel@tonic-gate } 14997c478bd9Sstevel@tonic-gate if (*cp != 'C' && *cp != 'D') { 15007c478bd9Sstevel@tonic-gate /* 15017c478bd9Sstevel@tonic-gate * Check for the case "rcp remote:foo\* local:bar". 15027c478bd9Sstevel@tonic-gate * In this case, the line "No match." can be returned 15037c478bd9Sstevel@tonic-gate * by the shell before the rcp command on the remote is 15047c478bd9Sstevel@tonic-gate * executed so the ^Aerror_message convention isn't 15057c478bd9Sstevel@tonic-gate * followed. 15067c478bd9Sstevel@tonic-gate */ 15077c478bd9Sstevel@tonic-gate if (first) { 15087c478bd9Sstevel@tonic-gate error("%s\n", cp); 15097c478bd9Sstevel@tonic-gate exit(1); 15107c478bd9Sstevel@tonic-gate } 1511*ad8ef92aSMilan Jurik SCREWUP("expected control record") 15127c478bd9Sstevel@tonic-gate } 15137c478bd9Sstevel@tonic-gate mode = 0; 15147c478bd9Sstevel@tonic-gate for (++cp; cp < buf + 5; cp++) { 15157c478bd9Sstevel@tonic-gate if (*cp < '0' || *cp > '7') 15167c478bd9Sstevel@tonic-gate SCREWUP("bad mode"); 15177c478bd9Sstevel@tonic-gate mode = (mode << 3) | (*cp - '0'); 15187c478bd9Sstevel@tonic-gate } 15197c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 15207c478bd9Sstevel@tonic-gate SCREWUP("mode not delimited"); 15217c478bd9Sstevel@tonic-gate size = 0; 15227c478bd9Sstevel@tonic-gate while (isdigit(*cp)) 15237c478bd9Sstevel@tonic-gate size = size * 10 + (*cp++ - '0'); 15247c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 15257c478bd9Sstevel@tonic-gate SCREWUP("size not delimited"); 15267c478bd9Sstevel@tonic-gate if (targisdir) { 15277c478bd9Sstevel@tonic-gate need = strlen(targ) + sizeof ("/") + strlen(cp); 15287c478bd9Sstevel@tonic-gate if (need > namebuf_sz) { 1529e800c2e3SMilan Jurik if ((namebuf = realloc(namebuf, need)) == 1530e800c2e3SMilan Jurik NULL) { 15317c478bd9Sstevel@tonic-gate error("rcp: out of memory\n"); 15327c478bd9Sstevel@tonic-gate exit(1); 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate namebuf_sz = need; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate (void) snprintf(namebuf, need, "%s%s%s", targ, 15377c478bd9Sstevel@tonic-gate *targ ? "/" : "", cp); 15387c478bd9Sstevel@tonic-gate np = namebuf; 15397c478bd9Sstevel@tonic-gate } else { 15407c478bd9Sstevel@tonic-gate np = targ; 15417c478bd9Sstevel@tonic-gate } 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate exists = stat(np, &stb) == 0; 15447c478bd9Sstevel@tonic-gate if (buf[0] == 'D') { 15457c478bd9Sstevel@tonic-gate if (exists) { 15467c478bd9Sstevel@tonic-gate if ((stb.st_mode&S_IFMT) != S_IFDIR) { 1547fa9e4066Sahrens if (aclflag | acl_aclflag) { 15487c478bd9Sstevel@tonic-gate /* 15497c478bd9Sstevel@tonic-gate * consume acl in the pipe 15507c478bd9Sstevel@tonic-gate * fd = -1 to indicate the 15517c478bd9Sstevel@tonic-gate * special case 15527c478bd9Sstevel@tonic-gate */ 15537c478bd9Sstevel@tonic-gate if (recvacl(-1, exists, pflag) 15547c478bd9Sstevel@tonic-gate == ACL_FAIL) { 15557c478bd9Sstevel@tonic-gate goto bad; 15567c478bd9Sstevel@tonic-gate } 15577c478bd9Sstevel@tonic-gate } 15587c478bd9Sstevel@tonic-gate errno = ENOTDIR; 15597c478bd9Sstevel@tonic-gate goto bad; 15607c478bd9Sstevel@tonic-gate } 15617c478bd9Sstevel@tonic-gate if (pflag) 15627c478bd9Sstevel@tonic-gate (void) chmod(np, mode); 15637c478bd9Sstevel@tonic-gate } else if (mkdir(np, mode) < 0) { 15647c478bd9Sstevel@tonic-gate if (aclflag) { 15657c478bd9Sstevel@tonic-gate /* consume acl in the pipe */ 15667c478bd9Sstevel@tonic-gate (void) recvacl(-1, exists, pflag); 15677c478bd9Sstevel@tonic-gate } 15687c478bd9Sstevel@tonic-gate goto bad; 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* acl support for directories */ 1572fa9e4066Sahrens if (aclflag | acl_aclflag) { 15737c478bd9Sstevel@tonic-gate int dfd; 15747c478bd9Sstevel@tonic-gate 15757c478bd9Sstevel@tonic-gate if ((dfd = open(np, O_RDONLY)) == -1) 15767c478bd9Sstevel@tonic-gate goto bad; 15777c478bd9Sstevel@tonic-gate 15787c478bd9Sstevel@tonic-gate /* get acl and set it to ofd */ 15797c478bd9Sstevel@tonic-gate if (recvacl(dfd, exists, pflag) == ACL_FAIL) { 15807c478bd9Sstevel@tonic-gate (void) close(dfd); 15817c478bd9Sstevel@tonic-gate if (!exists) 15827c478bd9Sstevel@tonic-gate (void) rmdir(np); 15837c478bd9Sstevel@tonic-gate goto bad; 15847c478bd9Sstevel@tonic-gate } 15857c478bd9Sstevel@tonic-gate (void) close(dfd); 15867c478bd9Sstevel@tonic-gate } 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate vect[0] = np; 15897c478bd9Sstevel@tonic-gate sink(1, vect); 15907c478bd9Sstevel@tonic-gate if (setimes) { 15917c478bd9Sstevel@tonic-gate setimes = 0; 15927c478bd9Sstevel@tonic-gate if (utimes(np, tv) < 0) 1593e800c2e3SMilan Jurik error("rcp: can't set " 1594e800c2e3SMilan Jurik "times on %s: %s\n", 15957c478bd9Sstevel@tonic-gate np, strerror(errno)); 15967c478bd9Sstevel@tonic-gate } 15977c478bd9Sstevel@tonic-gate continue; 15987c478bd9Sstevel@tonic-gate } 15997c478bd9Sstevel@tonic-gate 16007c478bd9Sstevel@tonic-gate if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 16017c478bd9Sstevel@tonic-gate bad: 16027c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", np, strerror(errno)); 16037c478bd9Sstevel@tonic-gate continue; 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate 16067c478bd9Sstevel@tonic-gate /* 16077c478bd9Sstevel@tonic-gate * If the output file exists we have to force zflag off 16087c478bd9Sstevel@tonic-gate * to avoid erroneously seeking past old data. 16097c478bd9Sstevel@tonic-gate */ 16107c478bd9Sstevel@tonic-gate zopen(ofd, zflag && !exists); 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate if (exists && pflag) 16137c478bd9Sstevel@tonic-gate (void) fchmod(ofd, mode); 16147c478bd9Sstevel@tonic-gate 16157c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 16167c478bd9Sstevel@tonic-gate 16177c478bd9Sstevel@tonic-gate /* 16187c478bd9Sstevel@tonic-gate * ACL support: receiving 16197c478bd9Sstevel@tonic-gate */ 1620fa9e4066Sahrens if (aclflag | acl_aclflag) { 16217c478bd9Sstevel@tonic-gate /* get acl and set it to ofd */ 16227c478bd9Sstevel@tonic-gate if (recvacl(ofd, exists, pflag) == ACL_FAIL) { 16237c478bd9Sstevel@tonic-gate (void) close(ofd); 16247c478bd9Sstevel@tonic-gate if (!exists) 16257c478bd9Sstevel@tonic-gate (void) unlink(np); 16267c478bd9Sstevel@tonic-gate continue; 16277c478bd9Sstevel@tonic-gate } 16287c478bd9Sstevel@tonic-gate } 16297c478bd9Sstevel@tonic-gate 16307c478bd9Sstevel@tonic-gate if ((bp = allocbuf(&buffer, ofd, RCP_BUFSIZE)) == 0) { 16317c478bd9Sstevel@tonic-gate (void) close(ofd); 16327c478bd9Sstevel@tonic-gate continue; 16337c478bd9Sstevel@tonic-gate } 16347c478bd9Sstevel@tonic-gate cp = bp->buf; 16357c478bd9Sstevel@tonic-gate count = 0; 16367c478bd9Sstevel@tonic-gate wrerr = 0; 16377c478bd9Sstevel@tonic-gate for (i = 0; i < size; i += RCP_BUFSIZE) { 16387c478bd9Sstevel@tonic-gate amt = RCP_BUFSIZE; 16397c478bd9Sstevel@tonic-gate if (i + amt > size) 16407c478bd9Sstevel@tonic-gate amt = size - i; 16417c478bd9Sstevel@tonic-gate count += amt; 16427c478bd9Sstevel@tonic-gate do { 16437c478bd9Sstevel@tonic-gate j = desrcpread(rem, cp, amt); 16447c478bd9Sstevel@tonic-gate if (j <= 0) { 16457c478bd9Sstevel@tonic-gate int sverrno = errno; 16467c478bd9Sstevel@tonic-gate 16477c478bd9Sstevel@tonic-gate /* 16487c478bd9Sstevel@tonic-gate * Connection to supplier lost. 16497c478bd9Sstevel@tonic-gate * Truncate file to correspond 16507c478bd9Sstevel@tonic-gate * to amount already transferred. 16517c478bd9Sstevel@tonic-gate * 16527c478bd9Sstevel@tonic-gate * Note that we must call ftruncate() 16537c478bd9Sstevel@tonic-gate * before any call to error() (which 16547c478bd9Sstevel@tonic-gate * might result in a SIGPIPE and 16557c478bd9Sstevel@tonic-gate * sudden death before we have a chance 16567c478bd9Sstevel@tonic-gate * to correct the file's size). 16577c478bd9Sstevel@tonic-gate */ 16587c478bd9Sstevel@tonic-gate size = lseek(ofd, 0, SEEK_CUR); 16597c478bd9Sstevel@tonic-gate if ((ftruncate(ofd, size) == -1) && 16607c478bd9Sstevel@tonic-gate (errno != EINVAL) && 16617c478bd9Sstevel@tonic-gate (errno != EACCES)) 16627c478bd9Sstevel@tonic-gate #define TRUNCERR "rcp: can't truncate %s: %s\n" 16637c478bd9Sstevel@tonic-gate error(TRUNCERR, np, 16647c478bd9Sstevel@tonic-gate strerror(errno)); 16657c478bd9Sstevel@tonic-gate error("rcp: %s\n", 16667c478bd9Sstevel@tonic-gate j ? strerror(sverrno) : 16677c478bd9Sstevel@tonic-gate "dropped connection"); 16687c478bd9Sstevel@tonic-gate (void) close(ofd); 16697c478bd9Sstevel@tonic-gate exit(1); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate amt -= j; 16727c478bd9Sstevel@tonic-gate cp += j; 16737c478bd9Sstevel@tonic-gate } while (amt > 0); 16747c478bd9Sstevel@tonic-gate if (count == bp->cnt) { 16757c478bd9Sstevel@tonic-gate cp = bp->buf; 16767c478bd9Sstevel@tonic-gate if (wrerr == 0 && 16777c478bd9Sstevel@tonic-gate zwrite(ofd, cp, count) < 0) 16787c478bd9Sstevel@tonic-gate wrerr++; 16797c478bd9Sstevel@tonic-gate count = 0; 16807c478bd9Sstevel@tonic-gate } 16817c478bd9Sstevel@tonic-gate } 16827c478bd9Sstevel@tonic-gate if (count != 0 && wrerr == 0 && 16837c478bd9Sstevel@tonic-gate zwrite(ofd, bp->buf, count) < 0) 16847c478bd9Sstevel@tonic-gate wrerr++; 16857c478bd9Sstevel@tonic-gate if (zclose(ofd) < 0) 16867c478bd9Sstevel@tonic-gate wrerr++; 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate if ((ftruncate(ofd, size) == -1) && (errno != EINVAL) && 16897c478bd9Sstevel@tonic-gate (errno != EACCES)) { 16907c478bd9Sstevel@tonic-gate error(TRUNCERR, np, strerror(errno)); 16917c478bd9Sstevel@tonic-gate } 16927c478bd9Sstevel@tonic-gate (void) close(ofd); 16937c478bd9Sstevel@tonic-gate (void) response(); 16947c478bd9Sstevel@tonic-gate if (setimes) { 16957c478bd9Sstevel@tonic-gate setimes = 0; 16967c478bd9Sstevel@tonic-gate if (utimes(np, tv) < 0) 16977c478bd9Sstevel@tonic-gate error("rcp: can't set times on %s: %s\n", 16987c478bd9Sstevel@tonic-gate np, strerror(errno)); 16997c478bd9Sstevel@tonic-gate } 17007c478bd9Sstevel@tonic-gate if (wrerr) 17017c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", np, strerror(errno)); 17027c478bd9Sstevel@tonic-gate else 17037c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate screwup: 17067c478bd9Sstevel@tonic-gate error("rcp: protocol screwup: %s\n", why); 17077c478bd9Sstevel@tonic-gate exit(1); 17087c478bd9Sstevel@tonic-gate } 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate #ifndef roundup 17117c478bd9Sstevel@tonic-gate #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 17127c478bd9Sstevel@tonic-gate #endif /* !roundup */ 17137c478bd9Sstevel@tonic-gate 17147c478bd9Sstevel@tonic-gate static BUF * 17157c478bd9Sstevel@tonic-gate allocbuf(BUF *bp, int fd, int blksize) 17167c478bd9Sstevel@tonic-gate { 17177c478bd9Sstevel@tonic-gate struct stat stb; 17187c478bd9Sstevel@tonic-gate int size; 17197c478bd9Sstevel@tonic-gate 17207c478bd9Sstevel@tonic-gate if (fstat(fd, &stb) < 0) { 17217c478bd9Sstevel@tonic-gate error("rcp: fstat: %s\n", strerror(errno)); 17227c478bd9Sstevel@tonic-gate return (0); 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate size = roundup(stb.st_blksize, blksize); 17257c478bd9Sstevel@tonic-gate if (size == 0) 17267c478bd9Sstevel@tonic-gate size = blksize; 17277c478bd9Sstevel@tonic-gate if (bp->cnt < size) { 17287c478bd9Sstevel@tonic-gate if (bp->buf != 0) 17297c478bd9Sstevel@tonic-gate free(bp->buf); 17307c478bd9Sstevel@tonic-gate bp->buf = (char *)malloc((uint_t)size); 17317c478bd9Sstevel@tonic-gate if (!bp->buf) { 17327c478bd9Sstevel@tonic-gate error("rcp: malloc: out of memory\n"); 17337c478bd9Sstevel@tonic-gate return (0); 17347c478bd9Sstevel@tonic-gate } 17357c478bd9Sstevel@tonic-gate } 17367c478bd9Sstevel@tonic-gate bp->cnt = size; 17377c478bd9Sstevel@tonic-gate return (bp); 17387c478bd9Sstevel@tonic-gate } 17397c478bd9Sstevel@tonic-gate 17407c478bd9Sstevel@tonic-gate static void 17417c478bd9Sstevel@tonic-gate usage(void) 17427c478bd9Sstevel@tonic-gate { 17437c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: \t%s\t%s", gettext("Usage"), 17447c478bd9Sstevel@tonic-gate gettext("\trcp [-p] [-a] [-x] [-k realm] [-PN / -PO] " 17457c478bd9Sstevel@tonic-gate #ifdef DEBUG 17467c478bd9Sstevel@tonic-gate "[-D port] " 17477c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 17487c478bd9Sstevel@tonic-gate "f1 f2; or:\n"), 17497c478bd9Sstevel@tonic-gate gettext("\trcp [-r] [-p] [-a] [-x] " 17507c478bd9Sstevel@tonic-gate #ifdef DEBUG 17517c478bd9Sstevel@tonic-gate "[-D port] " 17527c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 17537c478bd9Sstevel@tonic-gate "[-k realm] [-PN / -PO] f1...fn d2\n")); 17547c478bd9Sstevel@tonic-gate exit(1); 17557c478bd9Sstevel@tonic-gate } 17567c478bd9Sstevel@tonic-gate 17577c478bd9Sstevel@tonic-gate 17587c478bd9Sstevel@tonic-gate /* 17597c478bd9Sstevel@tonic-gate * sparse file support 17607c478bd9Sstevel@tonic-gate */ 17617c478bd9Sstevel@tonic-gate 17627c478bd9Sstevel@tonic-gate static off_t zbsize; 17637c478bd9Sstevel@tonic-gate static off_t zlastseek; 17647c478bd9Sstevel@tonic-gate 17657c478bd9Sstevel@tonic-gate /* is it ok to try to create holes? */ 17667c478bd9Sstevel@tonic-gate static void 17677c478bd9Sstevel@tonic-gate zopen(int fd, int flag) 17687c478bd9Sstevel@tonic-gate { 17697c478bd9Sstevel@tonic-gate struct stat st; 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate zbsize = 0; 17727c478bd9Sstevel@tonic-gate zlastseek = 0; 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate if (flag && 17757c478bd9Sstevel@tonic-gate fstat(fd, &st) == 0 && 17767c478bd9Sstevel@tonic-gate (st.st_mode & S_IFMT) == S_IFREG) 17777c478bd9Sstevel@tonic-gate zbsize = st.st_blksize; 17787c478bd9Sstevel@tonic-gate } 17797c478bd9Sstevel@tonic-gate 17807c478bd9Sstevel@tonic-gate /* write and/or seek */ 17817c478bd9Sstevel@tonic-gate static int 17827c478bd9Sstevel@tonic-gate zwrite(int fd, char *buf, int nbytes) 17837c478bd9Sstevel@tonic-gate { 17847c478bd9Sstevel@tonic-gate off_t block = zbsize ? zbsize : nbytes; 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate do { 17877c478bd9Sstevel@tonic-gate if (block > nbytes) 17887c478bd9Sstevel@tonic-gate block = nbytes; 17897c478bd9Sstevel@tonic-gate nbytes -= block; 17907c478bd9Sstevel@tonic-gate 17917c478bd9Sstevel@tonic-gate if (!zbsize || notzero(buf, block)) { 17927c478bd9Sstevel@tonic-gate register int n, count = block; 17937c478bd9Sstevel@tonic-gate 17947c478bd9Sstevel@tonic-gate do { 17957c478bd9Sstevel@tonic-gate if ((n = write(fd, buf, count)) < 0) 17967c478bd9Sstevel@tonic-gate return (-1); 17977c478bd9Sstevel@tonic-gate buf += n; 17987c478bd9Sstevel@tonic-gate } while ((count -= n) > 0); 17997c478bd9Sstevel@tonic-gate zlastseek = 0; 18007c478bd9Sstevel@tonic-gate } else { 18017c478bd9Sstevel@tonic-gate if (lseek(fd, (off_t)block, SEEK_CUR) < 0) 18027c478bd9Sstevel@tonic-gate return (-1); 18037c478bd9Sstevel@tonic-gate buf += block; 18047c478bd9Sstevel@tonic-gate zlastseek = 1; 18057c478bd9Sstevel@tonic-gate } 18067c478bd9Sstevel@tonic-gate } while (nbytes > 0); 18077c478bd9Sstevel@tonic-gate 18087c478bd9Sstevel@tonic-gate return (0); 18097c478bd9Sstevel@tonic-gate } 18107c478bd9Sstevel@tonic-gate 18117c478bd9Sstevel@tonic-gate /* write last byte of file if necessary */ 18127c478bd9Sstevel@tonic-gate static int 18137c478bd9Sstevel@tonic-gate zclose(int fd) 18147c478bd9Sstevel@tonic-gate { 18157c478bd9Sstevel@tonic-gate zbsize = 0; 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate if (zlastseek && (lseek(fd, (off_t)-1, SEEK_CUR) < 0 || 18187c478bd9Sstevel@tonic-gate zwrite(fd, "", 1) < 0)) 18197c478bd9Sstevel@tonic-gate return (-1); 18207c478bd9Sstevel@tonic-gate else 18217c478bd9Sstevel@tonic-gate return (0); 18227c478bd9Sstevel@tonic-gate } 18237c478bd9Sstevel@tonic-gate 18247c478bd9Sstevel@tonic-gate /* return true if buffer is not all zeros */ 18257c478bd9Sstevel@tonic-gate static int 18267c478bd9Sstevel@tonic-gate notzero(char *p, int n) 18277c478bd9Sstevel@tonic-gate { 18287c478bd9Sstevel@tonic-gate register int result = 0; 18297c478bd9Sstevel@tonic-gate 18307c478bd9Sstevel@tonic-gate while ((int)p & 3 && --n >= 0) 18317c478bd9Sstevel@tonic-gate result |= *p++; 18327c478bd9Sstevel@tonic-gate 18337c478bd9Sstevel@tonic-gate while ((n -= 4 * sizeof (int)) >= 0) { 18347c478bd9Sstevel@tonic-gate /* LINTED */ 18357c478bd9Sstevel@tonic-gate result |= ((int *)p)[0]; 18367c478bd9Sstevel@tonic-gate /* LINTED */ 18377c478bd9Sstevel@tonic-gate result |= ((int *)p)[1]; 18387c478bd9Sstevel@tonic-gate /* LINTED */ 18397c478bd9Sstevel@tonic-gate result |= ((int *)p)[2]; 18407c478bd9Sstevel@tonic-gate /* LINTED */ 18417c478bd9Sstevel@tonic-gate result |= ((int *)p)[3]; 18427c478bd9Sstevel@tonic-gate if (result) 18437c478bd9Sstevel@tonic-gate return (result); 18447c478bd9Sstevel@tonic-gate p += 4 * sizeof (int); 18457c478bd9Sstevel@tonic-gate } 18467c478bd9Sstevel@tonic-gate n += 4 * sizeof (int); 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate while (--n >= 0) 18497c478bd9Sstevel@tonic-gate result |= *p++; 18507c478bd9Sstevel@tonic-gate 18517c478bd9Sstevel@tonic-gate return (result); 18527c478bd9Sstevel@tonic-gate } 18537c478bd9Sstevel@tonic-gate 18547c478bd9Sstevel@tonic-gate /* 18557c478bd9Sstevel@tonic-gate * New functions to support ACLs 18567c478bd9Sstevel@tonic-gate */ 18577c478bd9Sstevel@tonic-gate 18587c478bd9Sstevel@tonic-gate /* 18597c478bd9Sstevel@tonic-gate * Get acl from f and send it over. 18607c478bd9Sstevel@tonic-gate * ACL record includes acl entry count, acl text length, and acl text. 18617c478bd9Sstevel@tonic-gate */ 18627c478bd9Sstevel@tonic-gate static int 18637c478bd9Sstevel@tonic-gate sendacl(int f) 18647c478bd9Sstevel@tonic-gate { 18657c478bd9Sstevel@tonic-gate int aclcnt; 18667c478bd9Sstevel@tonic-gate char *acltext; 18677c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 1868fa9e4066Sahrens acl_t *aclp; 1869fa9e4066Sahrens char acltype; 1870fa9e4066Sahrens int aclerror; 1871fa9e4066Sahrens int trivial; 18727c478bd9Sstevel@tonic-gate 1873fa9e4066Sahrens 1874fa9e4066Sahrens aclerror = facl_get(f, ACL_NO_TRIVIAL, &aclp); 1875fa9e4066Sahrens if (aclerror != 0) { 1876fa9e4066Sahrens error("can't retrieve ACL: %s \n", acl_strerror(aclerror)); 18777c478bd9Sstevel@tonic-gate return (ACL_FAIL); 18787c478bd9Sstevel@tonic-gate } 18797c478bd9Sstevel@tonic-gate 1880fa9e4066Sahrens /* 1881fa9e4066Sahrens * if acl type is not ACLENT_T and were operating in acl_aclflag == 0 1882fa9e4066Sahrens * then don't do the malloc and facl(fd, getcntcmd,...); 1883fa9e4066Sahrens * since the remote side doesn't support alternate style ACL's. 1884fa9e4066Sahrens */ 1885fa9e4066Sahrens 1886fa9e4066Sahrens if (aclp && (acl_type(aclp) != ACLENT_T) && (acl_aclflag == 0)) { 1887fa9e4066Sahrens aclcnt = MIN_ACL_ENTRIES; 1888fa9e4066Sahrens acltype = 'A'; 1889fa9e4066Sahrens trivial = ACL_IS_TRIVIAL; 1890fa9e4066Sahrens } else { 1891fa9e4066Sahrens 1892fa9e4066Sahrens aclcnt = (aclp != NULL) ? acl_cnt(aclp) : 0; 1893fa9e4066Sahrens 1894fa9e4066Sahrens if (aclp) { 1895fa9e4066Sahrens acltype = (acl_type(aclp) != ACLENT_T) ? 'Z' : 'A'; 1896fa9e4066Sahrens aclcnt = acl_cnt(aclp); 1897fa9e4066Sahrens trivial = (acl_flags(aclp) & ACL_IS_TRIVIAL); 1898fa9e4066Sahrens } else { 1899fa9e4066Sahrens acltype = 'A'; 1900fa9e4066Sahrens aclcnt = MIN_ACL_ENTRIES; 1901fa9e4066Sahrens trivial = ACL_IS_TRIVIAL; 1902fa9e4066Sahrens } 1903fa9e4066Sahrens 1904fa9e4066Sahrens } 1905fa9e4066Sahrens 19067c478bd9Sstevel@tonic-gate /* send the acl count over */ 1907fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%c%d\n", acltype, aclcnt); 19087c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 19097c478bd9Sstevel@tonic-gate 1910fa9e4066Sahrens /* 1911fa9e4066Sahrens * only send acl when we have an aclp, which would 1912fa9e4066Sahrens * imply its not trivial. 1913fa9e4066Sahrens */ 1914fa9e4066Sahrens if (aclp && (trivial != ACL_IS_TRIVIAL)) { 19155a5eeccaSmarks acltext = acl_totext(aclp, 0); 19167c478bd9Sstevel@tonic-gate if (acltext == NULL) { 19177c478bd9Sstevel@tonic-gate error("rcp: failed to convert to text\n"); 1918fa9e4066Sahrens acl_free(aclp); 19197c478bd9Sstevel@tonic-gate return (ACL_FAIL); 19207c478bd9Sstevel@tonic-gate } 19217c478bd9Sstevel@tonic-gate 19227c478bd9Sstevel@tonic-gate /* send ACLs over: send the length first */ 1923fa9e4066Sahrens (void) snprintf(buf, sizeof (buf), "%c%d\n", 1924fa9e4066Sahrens acltype, strlen(acltext)); 19257c478bd9Sstevel@tonic-gate 19267c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 19277c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, acltext, strlen(acltext)); 19287c478bd9Sstevel@tonic-gate free(acltext); 1929fa9e4066Sahrens if (response() < 0) { 1930fa9e4066Sahrens acl_free(aclp); 19317c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1932fa9e4066Sahrens } 19337c478bd9Sstevel@tonic-gate 19347c478bd9Sstevel@tonic-gate } 1935fa9e4066Sahrens 1936fa9e4066Sahrens if (aclp) 1937fa9e4066Sahrens acl_free(aclp); 19387c478bd9Sstevel@tonic-gate return (ACL_OK); 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate 19417c478bd9Sstevel@tonic-gate /* 19427c478bd9Sstevel@tonic-gate * Use this routine to get acl entry count and acl text size (in bytes) 19437c478bd9Sstevel@tonic-gate */ 19447c478bd9Sstevel@tonic-gate static int 1945fa9e4066Sahrens getaclinfo(int *cnt, int *acltype) 19467c478bd9Sstevel@tonic-gate { 19477c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 19487c478bd9Sstevel@tonic-gate char *cp; 19497c478bd9Sstevel@tonic-gate char ch; 19507c478bd9Sstevel@tonic-gate 19517c478bd9Sstevel@tonic-gate /* get acl count */ 19527c478bd9Sstevel@tonic-gate cp = buf; 19537c478bd9Sstevel@tonic-gate if (desrcpread(rem, cp, 1) <= 0) 19547c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1955fa9e4066Sahrens 1956fa9e4066Sahrens switch (*cp++) { 1957fa9e4066Sahrens case 'A': 1958fa9e4066Sahrens *acltype = 0; 1959fa9e4066Sahrens break; 1960fa9e4066Sahrens case 'Z': 1961fa9e4066Sahrens *acltype = 1; 1962fa9e4066Sahrens break; 1963fa9e4066Sahrens default: 19647c478bd9Sstevel@tonic-gate error("rcp: expect an ACL record, but got %c\n", *cp); 19657c478bd9Sstevel@tonic-gate return (ACL_FAIL); 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate do { 19687c478bd9Sstevel@tonic-gate if (desrcpread(rem, &ch, sizeof (ch)) != sizeof (ch)) { 19697c478bd9Sstevel@tonic-gate error("rcp: lost connection ..\n"); 19707c478bd9Sstevel@tonic-gate return (ACL_FAIL); 19717c478bd9Sstevel@tonic-gate } 19727c478bd9Sstevel@tonic-gate *cp++ = ch; 19737c478bd9Sstevel@tonic-gate } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 19747c478bd9Sstevel@tonic-gate if (ch != '\n') { 19757c478bd9Sstevel@tonic-gate error("rcp: ACL record corrupted \n"); 19767c478bd9Sstevel@tonic-gate return (ACL_FAIL); 19777c478bd9Sstevel@tonic-gate } 19787c478bd9Sstevel@tonic-gate cp = &buf[1]; 19797c478bd9Sstevel@tonic-gate *cnt = strtol(cp, &cp, 0); 19807c478bd9Sstevel@tonic-gate if (*cp != '\n') { 19817c478bd9Sstevel@tonic-gate error("rcp: ACL record corrupted \n"); 19827c478bd9Sstevel@tonic-gate return (ACL_FAIL); 19837c478bd9Sstevel@tonic-gate } 19847c478bd9Sstevel@tonic-gate return (ACL_OK); 19857c478bd9Sstevel@tonic-gate } 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate 19887c478bd9Sstevel@tonic-gate /* 19897c478bd9Sstevel@tonic-gate * Receive acl from the pipe and set it to f 19907c478bd9Sstevel@tonic-gate */ 19917c478bd9Sstevel@tonic-gate static int 19927c478bd9Sstevel@tonic-gate recvacl(int f, int exists, int preserve) 19937c478bd9Sstevel@tonic-gate { 19947c478bd9Sstevel@tonic-gate int aclcnt; /* acl entry count */ 19957c478bd9Sstevel@tonic-gate int aclsize; /* acl text length */ 19967c478bd9Sstevel@tonic-gate int j; 19977c478bd9Sstevel@tonic-gate char *tp; 19987c478bd9Sstevel@tonic-gate char *acltext; /* external format */ 1999fa9e4066Sahrens acl_t *aclp; 2000fa9e4066Sahrens int acltype; 2001fa9e4066Sahrens int min_entries; 2002fa9e4066Sahrens int aclerror; 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate /* get acl count */ 2005fa9e4066Sahrens if (getaclinfo(&aclcnt, &acltype) != ACL_OK) 20067c478bd9Sstevel@tonic-gate return (ACL_FAIL); 20077c478bd9Sstevel@tonic-gate 2008fa9e4066Sahrens if (acltype == 0) { 2009fa9e4066Sahrens min_entries = MIN_ACL_ENTRIES; 2010fa9e4066Sahrens } else { 2011fa9e4066Sahrens min_entries = 1; 2012fa9e4066Sahrens } 2013fa9e4066Sahrens 2014fa9e4066Sahrens if (aclcnt > min_entries) { 20157c478bd9Sstevel@tonic-gate /* get acl text size */ 2016fa9e4066Sahrens if (getaclinfo(&aclsize, &acltype) != ACL_OK) 20177c478bd9Sstevel@tonic-gate return (ACL_FAIL); 20187c478bd9Sstevel@tonic-gate if ((acltext = malloc(aclsize + 1)) == NULL) { 20197c478bd9Sstevel@tonic-gate error("rcp: cant allocate memory: %d\n", aclsize); 20207c478bd9Sstevel@tonic-gate return (ACL_FAIL); 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate 20237c478bd9Sstevel@tonic-gate tp = acltext; 20247c478bd9Sstevel@tonic-gate do { 20257c478bd9Sstevel@tonic-gate j = desrcpread(rem, tp, aclsize); 20267c478bd9Sstevel@tonic-gate if (j <= 0) { 20277c478bd9Sstevel@tonic-gate error("rcp: %s\n", j ? strerror(errno) : 20287c478bd9Sstevel@tonic-gate "dropped connection"); 20297c478bd9Sstevel@tonic-gate exit(1); 20307c478bd9Sstevel@tonic-gate } 20317c478bd9Sstevel@tonic-gate aclsize -= j; 20327c478bd9Sstevel@tonic-gate tp += j; 20337c478bd9Sstevel@tonic-gate } while (aclsize > 0); 20347c478bd9Sstevel@tonic-gate *tp = '\0'; 20357c478bd9Sstevel@tonic-gate 20367c478bd9Sstevel@tonic-gate if (preserve || !exists) { 2037fa9e4066Sahrens aclerror = acl_fromtext(acltext, &aclp); 2038fa9e4066Sahrens if (aclerror != 0) { 2039fa9e4066Sahrens error("rcp: failed to parse acl : %s\n", 2040fa9e4066Sahrens acl_strerror(aclerror)); 2041da3b6814Smp204432 free(acltext); 20427c478bd9Sstevel@tonic-gate return (ACL_FAIL); 20437c478bd9Sstevel@tonic-gate } 2044fa9e4066Sahrens 20457c478bd9Sstevel@tonic-gate if (f != -1) { 2046fa9e4066Sahrens if (facl_set(f, aclp) < 0) { 20477c478bd9Sstevel@tonic-gate error("rcp: failed to set acl\n"); 2048da3b6814Smp204432 acl_free(aclp); 2049da3b6814Smp204432 free(acltext); 20507c478bd9Sstevel@tonic-gate return (ACL_FAIL); 20517c478bd9Sstevel@tonic-gate } 20527c478bd9Sstevel@tonic-gate } 20537c478bd9Sstevel@tonic-gate /* -1 means that just consume the data in the pipe */ 2054fa9e4066Sahrens acl_free(aclp); 20557c478bd9Sstevel@tonic-gate } 20567c478bd9Sstevel@tonic-gate free(acltext); 20577c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 20587c478bd9Sstevel@tonic-gate } 20597c478bd9Sstevel@tonic-gate return (ACL_OK); 20607c478bd9Sstevel@tonic-gate } 20617c478bd9Sstevel@tonic-gate 20627c478bd9Sstevel@tonic-gate 20637c478bd9Sstevel@tonic-gate static char * 20647c478bd9Sstevel@tonic-gate search_char(unsigned char *cp, unsigned char chr) 20657c478bd9Sstevel@tonic-gate { 20667c478bd9Sstevel@tonic-gate int len; 20677c478bd9Sstevel@tonic-gate 20687c478bd9Sstevel@tonic-gate while (*cp) { 20697c478bd9Sstevel@tonic-gate if (*cp == chr) 20707c478bd9Sstevel@tonic-gate return ((char *)cp); 20717c478bd9Sstevel@tonic-gate if ((len = mblen((char *)cp, MB_CUR_MAX)) <= 0) 20727c478bd9Sstevel@tonic-gate len = 1; 20737c478bd9Sstevel@tonic-gate cp += len; 20747c478bd9Sstevel@tonic-gate } 20757c478bd9Sstevel@tonic-gate return (0); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate static int 20807c478bd9Sstevel@tonic-gate desrcpread(int fd, char *buf, int len) 20817c478bd9Sstevel@tonic-gate { 20827c478bd9Sstevel@tonic-gate return ((int)desread(fd, buf, len, 0)); 20837c478bd9Sstevel@tonic-gate } 20847c478bd9Sstevel@tonic-gate 20857c478bd9Sstevel@tonic-gate static int 20867c478bd9Sstevel@tonic-gate desrcpwrite(int fd, char *buf, int len) 20877c478bd9Sstevel@tonic-gate { 20887c478bd9Sstevel@tonic-gate /* 20897c478bd9Sstevel@tonic-gate * Note that rcp depends on the same file descriptor being both 20907c478bd9Sstevel@tonic-gate * input and output to the remote side. This is bogus, especially 20917c478bd9Sstevel@tonic-gate * when rcp is being run by a rsh that pipes. Fix it here because 20927c478bd9Sstevel@tonic-gate * it would require significantly more work in other places. 20937c478bd9Sstevel@tonic-gate * --hartmans 1/96 20947c478bd9Sstevel@tonic-gate */ 20957c478bd9Sstevel@tonic-gate 20967c478bd9Sstevel@tonic-gate if (fd == 0) 20977c478bd9Sstevel@tonic-gate fd = 1; 20987c478bd9Sstevel@tonic-gate return ((int)deswrite(fd, buf, len, 0)); 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate 21017c478bd9Sstevel@tonic-gate static char ** 21027c478bd9Sstevel@tonic-gate save_argv(int argc, char **argv) 21037c478bd9Sstevel@tonic-gate { 21047c478bd9Sstevel@tonic-gate int i; 21057c478bd9Sstevel@tonic-gate 21067c478bd9Sstevel@tonic-gate char **local_argv = (char **)calloc((unsigned)argc + 1, 21077c478bd9Sstevel@tonic-gate (unsigned)sizeof (char *)); 21087c478bd9Sstevel@tonic-gate 21097c478bd9Sstevel@tonic-gate /* 21107c478bd9Sstevel@tonic-gate * allocate an extra pointer, so that it is initialized to NULL and 21117c478bd9Sstevel@tonic-gate * execv() will work 21127c478bd9Sstevel@tonic-gate */ 21137c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 21147c478bd9Sstevel@tonic-gate local_argv[i] = strsave(argv[i]); 21157c478bd9Sstevel@tonic-gate } 21167c478bd9Sstevel@tonic-gate 21177c478bd9Sstevel@tonic-gate return (local_argv); 21187c478bd9Sstevel@tonic-gate } 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate #define SIZEOF_INADDR sizeof (struct in_addr) 21217c478bd9Sstevel@tonic-gate 21227c478bd9Sstevel@tonic-gate static void 21237c478bd9Sstevel@tonic-gate answer_auth(char *config_file, char *ccache_file) 21247c478bd9Sstevel@tonic-gate { 21257c478bd9Sstevel@tonic-gate krb5_data pname_data, msg; 21267c478bd9Sstevel@tonic-gate krb5_creds creds, *new_creds; 21277c478bd9Sstevel@tonic-gate krb5_ccache cc; 21287c478bd9Sstevel@tonic-gate krb5_auth_context auth_context = NULL; 21297c478bd9Sstevel@tonic-gate 21307c478bd9Sstevel@tonic-gate if (config_file) { 21317c478bd9Sstevel@tonic-gate const char *filenames[2]; 21327c478bd9Sstevel@tonic-gate 21337c478bd9Sstevel@tonic-gate filenames[1] = NULL; 21347c478bd9Sstevel@tonic-gate filenames[0] = config_file; 21357c478bd9Sstevel@tonic-gate if (krb5_set_config_files(bsd_context, filenames)) 21367c478bd9Sstevel@tonic-gate exit(1); 21377c478bd9Sstevel@tonic-gate } 21387c478bd9Sstevel@tonic-gate (void) memset((char *)&creds, 0, sizeof (creds)); 21397c478bd9Sstevel@tonic-gate 21407c478bd9Sstevel@tonic-gate if (krb5_read_message(bsd_context, (krb5_pointer) &rem, &pname_data)) 21417c478bd9Sstevel@tonic-gate exit(1); 21427c478bd9Sstevel@tonic-gate 21437c478bd9Sstevel@tonic-gate if (krb5_read_message(bsd_context, (krb5_pointer) &rem, 21447c478bd9Sstevel@tonic-gate &creds.second_ticket)) 21457c478bd9Sstevel@tonic-gate exit(1); 21467c478bd9Sstevel@tonic-gate 21477c478bd9Sstevel@tonic-gate if (ccache_file == NULL) { 21487c478bd9Sstevel@tonic-gate if (krb5_cc_default(bsd_context, &cc)) 21497c478bd9Sstevel@tonic-gate exit(1); 21507c478bd9Sstevel@tonic-gate } else { 21517c478bd9Sstevel@tonic-gate if (krb5_cc_resolve(bsd_context, ccache_file, &cc)) 21527c478bd9Sstevel@tonic-gate exit(1); 21537c478bd9Sstevel@tonic-gate } 21547c478bd9Sstevel@tonic-gate 21557c478bd9Sstevel@tonic-gate if (krb5_cc_get_principal(bsd_context, cc, &creds.client)) 21567c478bd9Sstevel@tonic-gate exit(1); 21577c478bd9Sstevel@tonic-gate 21587c478bd9Sstevel@tonic-gate if (krb5_parse_name(bsd_context, pname_data.data, &creds.server)) 21597c478bd9Sstevel@tonic-gate exit(1); 21607c478bd9Sstevel@tonic-gate 21617c478bd9Sstevel@tonic-gate krb5_xfree(pname_data.data); 21627c478bd9Sstevel@tonic-gate if (krb5_get_credentials(bsd_context, KRB5_GC_USER_USER, cc, &creds, 21637c478bd9Sstevel@tonic-gate &new_creds)) 21647c478bd9Sstevel@tonic-gate exit(1); 21657c478bd9Sstevel@tonic-gate 21667c478bd9Sstevel@tonic-gate if (krb5_mk_req_extended(bsd_context, &auth_context, 21677c478bd9Sstevel@tonic-gate AP_OPTS_USE_SESSION_KEY, NULL, new_creds, &msg)) 21687c478bd9Sstevel@tonic-gate exit(1); 21697c478bd9Sstevel@tonic-gate 21707c478bd9Sstevel@tonic-gate if (krb5_write_message(bsd_context, (krb5_pointer) & rem, &msg)) { 21717c478bd9Sstevel@tonic-gate krb5_xfree(msg.data); 21727c478bd9Sstevel@tonic-gate exit(1); 21737c478bd9Sstevel@tonic-gate } 21747c478bd9Sstevel@tonic-gate /* setup eblock for des_read and write */ 21750b4fd3b1SSurya Prakki (void) krb5_copy_keyblock(bsd_context, 21760b4fd3b1SSurya Prakki &new_creds->keyblock, &session_key); 21777c478bd9Sstevel@tonic-gate 21787c478bd9Sstevel@tonic-gate /* OK process key */ 21797c478bd9Sstevel@tonic-gate eblock.crypto_entry = session_key->enctype; 21807c478bd9Sstevel@tonic-gate eblock.key = (krb5_keyblock *)session_key; 21817c478bd9Sstevel@tonic-gate 21827c478bd9Sstevel@tonic-gate init_encrypt(encrypt_flag, bsd_context, KCMD_OLD_PROTOCOL, 21837c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, &eblock); 21847c478bd9Sstevel@tonic-gate /* cleanup */ 21857c478bd9Sstevel@tonic-gate krb5_free_cred_contents(bsd_context, &creds); 21867c478bd9Sstevel@tonic-gate krb5_free_creds(bsd_context, new_creds); 21877c478bd9Sstevel@tonic-gate krb5_xfree(msg.data); 21887c478bd9Sstevel@tonic-gate } 21897c478bd9Sstevel@tonic-gate 21907c478bd9Sstevel@tonic-gate 21917c478bd9Sstevel@tonic-gate static void 21927c478bd9Sstevel@tonic-gate try_normal_rcp(int cur_argc, char **cur_argv) 21937c478bd9Sstevel@tonic-gate { 21947c478bd9Sstevel@tonic-gate char *target; 21957c478bd9Sstevel@tonic-gate 21967c478bd9Sstevel@tonic-gate /* 21977c478bd9Sstevel@tonic-gate * Reset all KRB5 relevant flags and set the 21987c478bd9Sstevel@tonic-gate * cmd-buffer so that normal rcp works 21997c478bd9Sstevel@tonic-gate */ 22007c478bd9Sstevel@tonic-gate krb5auth_flag = encrypt_flag = encrypt_done = 0; 22017c478bd9Sstevel@tonic-gate cmd = cmd_orig; 22027c478bd9Sstevel@tonic-gate cmd_sunw = cmd_sunw_orig; 22037c478bd9Sstevel@tonic-gate 22047c478bd9Sstevel@tonic-gate if (cur_argc < 2) 22057c478bd9Sstevel@tonic-gate usage(); 22067c478bd9Sstevel@tonic-gate 22077c478bd9Sstevel@tonic-gate if (cur_argc > 2) 22087c478bd9Sstevel@tonic-gate targetshouldbedirectory = 1; 22097c478bd9Sstevel@tonic-gate 22107c478bd9Sstevel@tonic-gate rem = -1; 22117c478bd9Sstevel@tonic-gate 22127c478bd9Sstevel@tonic-gate prev_argc = cur_argc; 22137c478bd9Sstevel@tonic-gate prev_argv = save_argv(cur_argc, cur_argv); 22147c478bd9Sstevel@tonic-gate 22157c478bd9Sstevel@tonic-gate (void) init_service(krb5auth_flag); 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate if (target = colon(cur_argv[cur_argc - 1])) { 22187c478bd9Sstevel@tonic-gate toremote(target, cur_argc, cur_argv); 22197c478bd9Sstevel@tonic-gate } else { 22207c478bd9Sstevel@tonic-gate tolocal(cur_argc, cur_argv); 22217c478bd9Sstevel@tonic-gate if (targetshouldbedirectory) 22227c478bd9Sstevel@tonic-gate verifydir(cur_argv[cur_argc - 1]); 22237c478bd9Sstevel@tonic-gate } 22247c478bd9Sstevel@tonic-gate exit(errs); 22257c478bd9Sstevel@tonic-gate /* NOTREACHED */ 22267c478bd9Sstevel@tonic-gate } 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate 22297c478bd9Sstevel@tonic-gate static int 22307c478bd9Sstevel@tonic-gate init_service(int krb5flag) 22317c478bd9Sstevel@tonic-gate { 22327c478bd9Sstevel@tonic-gate struct servent *sp; 22337c478bd9Sstevel@tonic-gate boolean_t success = B_FALSE; 22347c478bd9Sstevel@tonic-gate 22357c478bd9Sstevel@tonic-gate if (krb5flag > 0) { 22367c478bd9Sstevel@tonic-gate sp = getservbyname("kshell", "tcp"); 22377c478bd9Sstevel@tonic-gate if (sp == NULL) { 22387c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 22397c478bd9Sstevel@tonic-gate gettext("rcp: kshell/tcp: unknown service.\n" 22407c478bd9Sstevel@tonic-gate "trying normal shell/tcp service\n")); 22417c478bd9Sstevel@tonic-gate } else { 22427c478bd9Sstevel@tonic-gate portnumber = sp->s_port; 22437c478bd9Sstevel@tonic-gate success = B_TRUE; 22447c478bd9Sstevel@tonic-gate } 22457c478bd9Sstevel@tonic-gate } else { 22467c478bd9Sstevel@tonic-gate portnumber = htons(IPPORT_CMDSERVER); 22477c478bd9Sstevel@tonic-gate success = B_TRUE; 22487c478bd9Sstevel@tonic-gate } 22497c478bd9Sstevel@tonic-gate return (success); 22507c478bd9Sstevel@tonic-gate } 22517c478bd9Sstevel@tonic-gate 22527c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 22537c478bd9Sstevel@tonic-gate static void 22547c478bd9Sstevel@tonic-gate error(char *fmt, ...) 22557c478bd9Sstevel@tonic-gate { 22567c478bd9Sstevel@tonic-gate va_list ap; 22577c478bd9Sstevel@tonic-gate char buf[RCP_BUFSIZE]; 22587c478bd9Sstevel@tonic-gate char *cp = buf; 22597c478bd9Sstevel@tonic-gate 22607c478bd9Sstevel@tonic-gate va_start(ap, fmt); 22617c478bd9Sstevel@tonic-gate errs++; 22627c478bd9Sstevel@tonic-gate *cp++ = 1; 22637c478bd9Sstevel@tonic-gate (void) vsnprintf(cp, sizeof (buf) - 1, fmt, ap); 22647c478bd9Sstevel@tonic-gate va_end(ap); 22657c478bd9Sstevel@tonic-gate 22667c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 22677c478bd9Sstevel@tonic-gate if (iamremote == 0) 22687c478bd9Sstevel@tonic-gate (void) write(2, buf + 1, strlen(buf + 1)); 22697c478bd9Sstevel@tonic-gate } 227040164e4fSsn199410 227140164e4fSsn199410 static void 227240164e4fSsn199410 addargs(char **arglist, ...) 227340164e4fSsn199410 { 227440164e4fSsn199410 va_list ap; 227540164e4fSsn199410 int i = 0; 227640164e4fSsn199410 char *pm; 227740164e4fSsn199410 227840164e4fSsn199410 va_start(ap, arglist); 227940164e4fSsn199410 while (i < MAXARGS && (pm = va_arg(ap, char *)) != NULL) 228040164e4fSsn199410 if (strcmp(pm, "")) 228140164e4fSsn199410 arglist[i++] = pm; 228240164e4fSsn199410 arglist[i] = NULL; 228340164e4fSsn199410 va_end(ap); 228440164e4fSsn199410 } 2285