1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 7*7c478bd9Sstevel@tonic-gate 8*7c478bd9Sstevel@tonic-gate /* 9*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983 The Regents of the University of California. 10*7c478bd9Sstevel@tonic-gate * All rights reserved. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 13*7c478bd9Sstevel@tonic-gate * provided that the above copyright notice and this paragraph are 14*7c478bd9Sstevel@tonic-gate * duplicated in all such forms and that any documentation, 15*7c478bd9Sstevel@tonic-gate * advertising materials, and other materials related to such 16*7c478bd9Sstevel@tonic-gate * distribution and use acknowledge that the software was developed 17*7c478bd9Sstevel@tonic-gate * by the University of California, Berkeley. The name of the 18*7c478bd9Sstevel@tonic-gate * University may not be used to endorse or promote products derived 19*7c478bd9Sstevel@tonic-gate * from this software without specific prior written permission. 20*7c478bd9Sstevel@tonic-gate * 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate 23*7c478bd9Sstevel@tonic-gate #define _FILE_OFFSET_BITS 64 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate /* 26*7c478bd9Sstevel@tonic-gate * rcp 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate #include <sys/param.h> 29*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/ioctl.h> 34*7c478bd9Sstevel@tonic-gate #include <sys/acl.h> 35*7c478bd9Sstevel@tonic-gate #include <dirent.h> 36*7c478bd9Sstevel@tonic-gate #include <signal.h> 37*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 38*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 39*7c478bd9Sstevel@tonic-gate #include <pwd.h> 40*7c478bd9Sstevel@tonic-gate #include <netdb.h> 41*7c478bd9Sstevel@tonic-gate #include <wchar.h> 42*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 43*7c478bd9Sstevel@tonic-gate #include <errno.h> 44*7c478bd9Sstevel@tonic-gate #include <locale.h> 45*7c478bd9Sstevel@tonic-gate #include <strings.h> 46*7c478bd9Sstevel@tonic-gate #include <stdio.h> 47*7c478bd9Sstevel@tonic-gate #include <ctype.h> 48*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 49*7c478bd9Sstevel@tonic-gate #include <unistd.h> 50*7c478bd9Sstevel@tonic-gate #include <limits.h> 51*7c478bd9Sstevel@tonic-gate #include <priv_utils.h> 52*7c478bd9Sstevel@tonic-gate #include <sys/sendfile.h> 53*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 54*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 55*7c478bd9Sstevel@tonic-gate 56*7c478bd9Sstevel@tonic-gate /* 57*7c478bd9Sstevel@tonic-gate * It seems like Berkeley got these from pathnames.h? 58*7c478bd9Sstevel@tonic-gate */ 59*7c478bd9Sstevel@tonic-gate #define _PATH_RSH "/usr/bin/rsh" 60*7c478bd9Sstevel@tonic-gate #define _PATH_CP "/usr/bin/cp" 61*7c478bd9Sstevel@tonic-gate #define _PATH_BSHELL "/usr/bin/sh" 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #define ACL_FAIL 1 64*7c478bd9Sstevel@tonic-gate #define ACL_OK 0 65*7c478bd9Sstevel@tonic-gate #define RCP_BUFSIZE (64 * 1024) 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate #define RCP_ACL "/usr/lib/sunw,rcp" 68*7c478bd9Sstevel@tonic-gate /* see PSARC/1993/004/opinion */ 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate typedef struct _buf { 71*7c478bd9Sstevel@tonic-gate int cnt; 72*7c478bd9Sstevel@tonic-gate char *buf; 73*7c478bd9Sstevel@tonic-gate } BUF; 74*7c478bd9Sstevel@tonic-gate 75*7c478bd9Sstevel@tonic-gate static char *cmd_sunw; 76*7c478bd9Sstevel@tonic-gate static struct passwd *pwd; 77*7c478bd9Sstevel@tonic-gate static int errs; 78*7c478bd9Sstevel@tonic-gate static int pflag; 79*7c478bd9Sstevel@tonic-gate static uid_t userid; 80*7c478bd9Sstevel@tonic-gate static int rem; 81*7c478bd9Sstevel@tonic-gate static int zflag; 82*7c478bd9Sstevel@tonic-gate static int iamremote; 83*7c478bd9Sstevel@tonic-gate static int iamrecursive; 84*7c478bd9Sstevel@tonic-gate static int targetshouldbedirectory; 85*7c478bd9Sstevel@tonic-gate static int aclflag; 86*7c478bd9Sstevel@tonic-gate static int retval = 0; 87*7c478bd9Sstevel@tonic-gate static int portnumber = 0; 88*7c478bd9Sstevel@tonic-gate 89*7c478bd9Sstevel@tonic-gate static void lostconn(void); 90*7c478bd9Sstevel@tonic-gate static char *search_char(unsigned char *, unsigned char); 91*7c478bd9Sstevel@tonic-gate static char *removebrackets(char *); 92*7c478bd9Sstevel@tonic-gate static char *colon(char *); 93*7c478bd9Sstevel@tonic-gate static int response(void); 94*7c478bd9Sstevel@tonic-gate static void usage(void); 95*7c478bd9Sstevel@tonic-gate static void source(int, char **); 96*7c478bd9Sstevel@tonic-gate static void sink(int, char **); 97*7c478bd9Sstevel@tonic-gate static void toremote(char *, int, char **); 98*7c478bd9Sstevel@tonic-gate static void tolocal(int, char **); 99*7c478bd9Sstevel@tonic-gate static void verifydir(char *); 100*7c478bd9Sstevel@tonic-gate static int okname(char *); 101*7c478bd9Sstevel@tonic-gate static int susystem(char *); 102*7c478bd9Sstevel@tonic-gate static void rsource(char *, struct stat *); 103*7c478bd9Sstevel@tonic-gate static int sendacl(int); 104*7c478bd9Sstevel@tonic-gate static int recvacl(int, int, int); 105*7c478bd9Sstevel@tonic-gate static int zwrite(int, char *, int); 106*7c478bd9Sstevel@tonic-gate static void zopen(int, int); 107*7c478bd9Sstevel@tonic-gate static int zclose(int); 108*7c478bd9Sstevel@tonic-gate static int notzero(char *, int); 109*7c478bd9Sstevel@tonic-gate static BUF *allocbuf(BUF *, int, int); 110*7c478bd9Sstevel@tonic-gate static void error(char *fmt, ...); 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * As a 32 bit application, we can only transfer (2gb - 1) i.e 0x7FFFFFFF 114*7c478bd9Sstevel@tonic-gate * bytes of data. We would like the size to be aligned to the nearest 115*7c478bd9Sstevel@tonic-gate * MAXBOFFSET (8192) boundary for optimal performance. 116*7c478bd9Sstevel@tonic-gate */ 117*7c478bd9Sstevel@tonic-gate #define SENDFILE_SIZE 0x7FFFE000 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate #include <k5-int.h> 120*7c478bd9Sstevel@tonic-gate #include <profile/prof_int.h> 121*7c478bd9Sstevel@tonic-gate #include <com_err.h> 122*7c478bd9Sstevel@tonic-gate #include <kcmd.h> 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate #define NULLBUF (BUF *) 0 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate static int sock; 127*7c478bd9Sstevel@tonic-gate static char *cmd, *cmd_orig, *cmd_sunw_orig; 128*7c478bd9Sstevel@tonic-gate static char *krb_realm = NULL; 129*7c478bd9Sstevel@tonic-gate static char *krb_cache = NULL; 130*7c478bd9Sstevel@tonic-gate static char *krb_config = NULL; 131*7c478bd9Sstevel@tonic-gate static char des_inbuf[2 * RCP_BUFSIZE]; 132*7c478bd9Sstevel@tonic-gate /* needs to be > largest read size */ 133*7c478bd9Sstevel@tonic-gate static char des_outbuf[2 * RCP_BUFSIZE]; 134*7c478bd9Sstevel@tonic-gate /* needs to be > largest write size */ 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate static krb5_data desinbuf, desoutbuf; 137*7c478bd9Sstevel@tonic-gate static krb5_encrypt_block eblock; /* eblock for encrypt/decrypt */ 138*7c478bd9Sstevel@tonic-gate static krb5_keyblock *session_key; /* static key for session */ 139*7c478bd9Sstevel@tonic-gate static krb5_context bsd_context; 140*7c478bd9Sstevel@tonic-gate static krb5_auth_context auth_context; 141*7c478bd9Sstevel@tonic-gate static krb5_flags authopts; 142*7c478bd9Sstevel@tonic-gate static krb5_error_code status; 143*7c478bd9Sstevel@tonic-gate 144*7c478bd9Sstevel@tonic-gate static void try_normal_rcp(int, char **); 145*7c478bd9Sstevel@tonic-gate static int init_service(int); 146*7c478bd9Sstevel@tonic-gate static char **save_argv(int, char **); 147*7c478bd9Sstevel@tonic-gate static void answer_auth(char *, char *); 148*7c478bd9Sstevel@tonic-gate static int desrcpwrite(int, char *, int); 149*7c478bd9Sstevel@tonic-gate static int desrcpread(int, char *, int); 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate /* 152*7c478bd9Sstevel@tonic-gate * Not sure why these two don't have their own header file declarations, but 153*7c478bd9Sstevel@tonic-gate * lint complains about absent declarations so place some here. Sigh. 154*7c478bd9Sstevel@tonic-gate */ 155*7c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_boolean(profile_t, char **, 156*7c478bd9Sstevel@tonic-gate profile_options_boolean *); 157*7c478bd9Sstevel@tonic-gate extern errcode_t profile_get_options_string(profile_t, char **, 158*7c478bd9Sstevel@tonic-gate profile_option_strings *); 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate static int krb5auth_flag = 0; /* Flag set, when KERBEROS is enabled */ 161*7c478bd9Sstevel@tonic-gate static int encrypt_flag = 0; /* Flag set, when encryption is enabled */ 162*7c478bd9Sstevel@tonic-gate static int encrypt_done = 0; /* Flag set, if "-x" is specified */ 163*7c478bd9Sstevel@tonic-gate static enum kcmd_proto kcmd_proto = KCMD_NEW_PROTOCOL; 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate /* Flag set, if -PN / -PO is specified */ 166*7c478bd9Sstevel@tonic-gate static boolean_t rcmdoption_done = B_FALSE; 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate static profile_options_boolean option[] = { 169*7c478bd9Sstevel@tonic-gate { "encrypt", &encrypt_flag, 0 }, 170*7c478bd9Sstevel@tonic-gate { NULL, NULL, 0 } 171*7c478bd9Sstevel@tonic-gate }; 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate static char *rcmdproto = NULL; 174*7c478bd9Sstevel@tonic-gate static profile_option_strings rcmdversion[] = { 175*7c478bd9Sstevel@tonic-gate { "rcmd_protocol", &rcmdproto, 0 }, 176*7c478bd9Sstevel@tonic-gate { NULL, NULL, 0 } 177*7c478bd9Sstevel@tonic-gate }; 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate static char *realmdef[] = { "realms", NULL, "rcp", NULL }; 180*7c478bd9Sstevel@tonic-gate static char *appdef[] = { "appdefaults", "rcp", NULL }; 181*7c478bd9Sstevel@tonic-gate static char **prev_argv; 182*7c478bd9Sstevel@tonic-gate static int prev_argc; 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate int 185*7c478bd9Sstevel@tonic-gate main(int argc, char *argv[]) 186*7c478bd9Sstevel@tonic-gate { 187*7c478bd9Sstevel@tonic-gate int ch, fflag, tflag; 188*7c478bd9Sstevel@tonic-gate char *targ; 189*7c478bd9Sstevel@tonic-gate size_t cmdsiz; 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate if (strcmp(argv[0], RCP_ACL) == 0) 194*7c478bd9Sstevel@tonic-gate aclflag = 1; 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate if (!(pwd = getpwuid(userid = getuid()))) { 197*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: unknown user %d.\n", 198*7c478bd9Sstevel@tonic-gate (uint_t)userid); 199*7c478bd9Sstevel@tonic-gate return (1); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate 202*7c478bd9Sstevel@tonic-gate fflag = tflag = 0; 203*7c478bd9Sstevel@tonic-gate while ((ch = getopt(argc, argv, "axdfprtz:D:k:P:")) != EOF) { 204*7c478bd9Sstevel@tonic-gate switch (ch) { 205*7c478bd9Sstevel@tonic-gate case 'd': 206*7c478bd9Sstevel@tonic-gate targetshouldbedirectory = 1; 207*7c478bd9Sstevel@tonic-gate break; 208*7c478bd9Sstevel@tonic-gate case 'f': /* "from" */ 209*7c478bd9Sstevel@tonic-gate fflag = 1; 210*7c478bd9Sstevel@tonic-gate if (aclflag) 211*7c478bd9Sstevel@tonic-gate /* ok response */ 212*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 213*7c478bd9Sstevel@tonic-gate break; 214*7c478bd9Sstevel@tonic-gate case 'p': /* preserve access/mod times */ 215*7c478bd9Sstevel@tonic-gate ++pflag; 216*7c478bd9Sstevel@tonic-gate break; 217*7c478bd9Sstevel@tonic-gate case 'r': 218*7c478bd9Sstevel@tonic-gate ++iamrecursive; 219*7c478bd9Sstevel@tonic-gate break; 220*7c478bd9Sstevel@tonic-gate case 't': /* "to" */ 221*7c478bd9Sstevel@tonic-gate tflag = 1; 222*7c478bd9Sstevel@tonic-gate break; 223*7c478bd9Sstevel@tonic-gate case 'x': 224*7c478bd9Sstevel@tonic-gate if (!krb5_privacy_allowed()) { 225*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: " 226*7c478bd9Sstevel@tonic-gate "Encryption not supported.\n")); 227*7c478bd9Sstevel@tonic-gate return (1); 228*7c478bd9Sstevel@tonic-gate } 229*7c478bd9Sstevel@tonic-gate encrypt_flag++; 230*7c478bd9Sstevel@tonic-gate krb5auth_flag++; 231*7c478bd9Sstevel@tonic-gate encrypt_done++; 232*7c478bd9Sstevel@tonic-gate break; 233*7c478bd9Sstevel@tonic-gate case 'k': 234*7c478bd9Sstevel@tonic-gate if ((krb_realm = (char *)strdup(optarg)) == NULL) { 235*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp:" 236*7c478bd9Sstevel@tonic-gate " Cannot malloc.\n")); 237*7c478bd9Sstevel@tonic-gate return (1); 238*7c478bd9Sstevel@tonic-gate } 239*7c478bd9Sstevel@tonic-gate krb5auth_flag++; 240*7c478bd9Sstevel@tonic-gate break; 241*7c478bd9Sstevel@tonic-gate case 'P': 242*7c478bd9Sstevel@tonic-gate if (strncmp(optarg, "O", 1) == 0) { 243*7c478bd9Sstevel@tonic-gate if (rcmdoption_done == B_TRUE) { 244*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: " 245*7c478bd9Sstevel@tonic-gate "Only one of -PN and -PO " 246*7c478bd9Sstevel@tonic-gate "allowed.\n")); 247*7c478bd9Sstevel@tonic-gate usage(); 248*7c478bd9Sstevel@tonic-gate } 249*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 250*7c478bd9Sstevel@tonic-gate rcmdoption_done = B_TRUE; 251*7c478bd9Sstevel@tonic-gate } else if (strncmp(optarg, "N", 1) == 0) { 252*7c478bd9Sstevel@tonic-gate if (rcmdoption_done == B_TRUE) { 253*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: " 254*7c478bd9Sstevel@tonic-gate "Only one of -PN and -PO " 255*7c478bd9Sstevel@tonic-gate "allowed.\n")); 256*7c478bd9Sstevel@tonic-gate usage(); 257*7c478bd9Sstevel@tonic-gate } 258*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 259*7c478bd9Sstevel@tonic-gate rcmdoption_done = B_TRUE; 260*7c478bd9Sstevel@tonic-gate } else { 261*7c478bd9Sstevel@tonic-gate usage(); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate krb5auth_flag++; 264*7c478bd9Sstevel@tonic-gate break; 265*7c478bd9Sstevel@tonic-gate case 'a': 266*7c478bd9Sstevel@tonic-gate krb5auth_flag++; 267*7c478bd9Sstevel@tonic-gate break; 268*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 269*7c478bd9Sstevel@tonic-gate case 'D': 270*7c478bd9Sstevel@tonic-gate portnumber = htons(atoi(optarg)); 271*7c478bd9Sstevel@tonic-gate krb5auth_flag++; 272*7c478bd9Sstevel@tonic-gate break; 273*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 274*7c478bd9Sstevel@tonic-gate case '?': 275*7c478bd9Sstevel@tonic-gate default: 276*7c478bd9Sstevel@tonic-gate usage(); 277*7c478bd9Sstevel@tonic-gate } 278*7c478bd9Sstevel@tonic-gate } 279*7c478bd9Sstevel@tonic-gate argc -= optind; 280*7c478bd9Sstevel@tonic-gate argv += optind; 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 283*7c478bd9Sstevel@tonic-gate status = krb5_init_context(&bsd_context); 284*7c478bd9Sstevel@tonic-gate if (status) { 285*7c478bd9Sstevel@tonic-gate com_err("rcp", status, 286*7c478bd9Sstevel@tonic-gate gettext("while initializing krb5")); 287*7c478bd9Sstevel@tonic-gate return (1); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * Set up buffers for desread and deswrite. 292*7c478bd9Sstevel@tonic-gate */ 293*7c478bd9Sstevel@tonic-gate desinbuf.data = des_inbuf; 294*7c478bd9Sstevel@tonic-gate desoutbuf.data = des_outbuf; 295*7c478bd9Sstevel@tonic-gate desinbuf.length = sizeof (des_inbuf); 296*7c478bd9Sstevel@tonic-gate desoutbuf.length = sizeof (des_outbuf); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate if (fflag || tflag) 300*7c478bd9Sstevel@tonic-gate if (encrypt_flag > 0) 301*7c478bd9Sstevel@tonic-gate (void) answer_auth(krb_config, krb_cache); 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if (fflag) { 304*7c478bd9Sstevel@tonic-gate iamremote = 1; 305*7c478bd9Sstevel@tonic-gate (void) response(); 306*7c478bd9Sstevel@tonic-gate (void) setuid(userid); 307*7c478bd9Sstevel@tonic-gate source(argc, argv); 308*7c478bd9Sstevel@tonic-gate return (errs); 309*7c478bd9Sstevel@tonic-gate } 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate if (tflag) { 312*7c478bd9Sstevel@tonic-gate iamremote = 1; 313*7c478bd9Sstevel@tonic-gate (void) setuid(userid); 314*7c478bd9Sstevel@tonic-gate sink(argc, argv); 315*7c478bd9Sstevel@tonic-gate return (errs); 316*7c478bd9Sstevel@tonic-gate } 317*7c478bd9Sstevel@tonic-gate 318*7c478bd9Sstevel@tonic-gate if (argc < 2) 319*7c478bd9Sstevel@tonic-gate usage(); 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate /* This will make "rcmd_af()" magically get the proper privilege */ 322*7c478bd9Sstevel@tonic-gate if (__init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL) == -1) { 323*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: must be set-uid root\n"); 324*7c478bd9Sstevel@tonic-gate exit(1); 325*7c478bd9Sstevel@tonic-gate } 326*7c478bd9Sstevel@tonic-gate 327*7c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 328*7c478bd9Sstevel@tonic-gate /* 329*7c478bd9Sstevel@tonic-gate * Get our local realm to look up local realm options. 330*7c478bd9Sstevel@tonic-gate */ 331*7c478bd9Sstevel@tonic-gate status = krb5_get_default_realm(bsd_context, &realmdef[1]); 332*7c478bd9Sstevel@tonic-gate if (status) { 333*7c478bd9Sstevel@tonic-gate com_err("rcp", status, 334*7c478bd9Sstevel@tonic-gate gettext("while getting default realm")); 335*7c478bd9Sstevel@tonic-gate return (1); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate /* 338*7c478bd9Sstevel@tonic-gate * See if encryption should be done for this realm 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, realmdef, 341*7c478bd9Sstevel@tonic-gate option); 342*7c478bd9Sstevel@tonic-gate /* 343*7c478bd9Sstevel@tonic-gate * Check the appdefaults section 344*7c478bd9Sstevel@tonic-gate */ 345*7c478bd9Sstevel@tonic-gate profile_get_options_boolean(bsd_context->profile, appdef, 346*7c478bd9Sstevel@tonic-gate option); 347*7c478bd9Sstevel@tonic-gate profile_get_options_string(bsd_context->profile, appdef, 348*7c478bd9Sstevel@tonic-gate rcmdversion); 349*7c478bd9Sstevel@tonic-gate if ((encrypt_done > 0) || (encrypt_flag > 0)) { 350*7c478bd9Sstevel@tonic-gate if (krb5_privacy_allowed() == TRUE) { 351*7c478bd9Sstevel@tonic-gate encrypt_flag++; 352*7c478bd9Sstevel@tonic-gate } else { 353*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Encryption" 354*7c478bd9Sstevel@tonic-gate " not supported.\n")); 355*7c478bd9Sstevel@tonic-gate return (1); 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate } 358*7c478bd9Sstevel@tonic-gate 359*7c478bd9Sstevel@tonic-gate if ((rcmdoption_done == B_FALSE) && (rcmdproto != NULL)) { 360*7c478bd9Sstevel@tonic-gate if (strncmp(rcmdproto, "rcmdv2", 6) == 0) { 361*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_NEW_PROTOCOL; 362*7c478bd9Sstevel@tonic-gate } else if (strncmp(rcmdproto, "rcmdv1", 6) == 0) { 363*7c478bd9Sstevel@tonic-gate kcmd_proto = KCMD_OLD_PROTOCOL; 364*7c478bd9Sstevel@tonic-gate } else { 365*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Unrecognized " 366*7c478bd9Sstevel@tonic-gate "KCMD protocol (%s)"), rcmdproto); 367*7c478bd9Sstevel@tonic-gate return (1); 368*7c478bd9Sstevel@tonic-gate } 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate } 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (argc > 2) 373*7c478bd9Sstevel@tonic-gate targetshouldbedirectory = 1; 374*7c478bd9Sstevel@tonic-gate 375*7c478bd9Sstevel@tonic-gate rem = -1; 376*7c478bd9Sstevel@tonic-gate 377*7c478bd9Sstevel@tonic-gate if (portnumber == 0) { 378*7c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 379*7c478bd9Sstevel@tonic-gate retval = init_service(krb5auth_flag); 380*7c478bd9Sstevel@tonic-gate if (!retval) { 381*7c478bd9Sstevel@tonic-gate /* 382*7c478bd9Sstevel@tonic-gate * Connecting to the kshell service failed, 383*7c478bd9Sstevel@tonic-gate * fallback to normal rcp & reset KRB5 flags. 384*7c478bd9Sstevel@tonic-gate */ 385*7c478bd9Sstevel@tonic-gate krb5auth_flag = encrypt_flag = 0; 386*7c478bd9Sstevel@tonic-gate encrypt_done = 0; 387*7c478bd9Sstevel@tonic-gate (void) init_service(krb5auth_flag); 388*7c478bd9Sstevel@tonic-gate } 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate else 391*7c478bd9Sstevel@tonic-gate (void) init_service(krb5auth_flag); 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 395*7c478bd9Sstevel@tonic-gate if (retval || krb5auth_flag) { 396*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Kerberized rcp session, " 397*7c478bd9Sstevel@tonic-gate "port %d in use "), portnumber); 398*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_OLD_PROTOCOL) 399*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("[kcmd ver.1]\n")); 400*7c478bd9Sstevel@tonic-gate else 401*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("[kcmd ver.2]\n")); 402*7c478bd9Sstevel@tonic-gate } else { 403*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("Normal rcp session, port %d " 404*7c478bd9Sstevel@tonic-gate "in use.\n"), portnumber); 405*7c478bd9Sstevel@tonic-gate } 406*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 409*7c478bd9Sstevel@tonic-gate /* 410*7c478bd9Sstevel@tonic-gate * We calculate here a buffer size that can be used in the 411*7c478bd9Sstevel@tonic-gate * allocation of the three buffers cmd, cmd_orig and 412*7c478bd9Sstevel@tonic-gate * cmd_sunw_orig that are used to hold different incantations 413*7c478bd9Sstevel@tonic-gate * of rcp. 414*7c478bd9Sstevel@tonic-gate */ 415*7c478bd9Sstevel@tonic-gate cmdsiz = MAX(sizeof ("-x rcp -r -p -d -k ") + 416*7c478bd9Sstevel@tonic-gate strlen(krb_realm != NULL ? krb_realm : ""), 417*7c478bd9Sstevel@tonic-gate sizeof (RCP_ACL " -r -p -z -d")); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (((cmd = (char *)malloc(cmdsiz)) == NULL) || 420*7c478bd9Sstevel@tonic-gate ((cmd_sunw_orig = (char *)malloc(cmdsiz)) == NULL) || 421*7c478bd9Sstevel@tonic-gate ((cmd_orig = (char *)malloc(cmdsiz)) == NULL)) { 422*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Cannot " 423*7c478bd9Sstevel@tonic-gate "malloc.\n")); 424*7c478bd9Sstevel@tonic-gate return (1); 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate 427*7c478bd9Sstevel@tonic-gate (void) snprintf(cmd, cmdsiz, "%srcp %s%s%s%s%s", 428*7c478bd9Sstevel@tonic-gate encrypt_flag ? "-x " : "", 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", pflag ? " -p" : "", 431*7c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : "", 432*7c478bd9Sstevel@tonic-gate krb_realm != NULL ? " -k " : "", 433*7c478bd9Sstevel@tonic-gate krb_realm != NULL ? krb_realm : ""); 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate /* 436*7c478bd9Sstevel@tonic-gate * We would use cmd-orig as the 'cmd-buffer' if kerberized 437*7c478bd9Sstevel@tonic-gate * rcp fails, in which case we fallback to normal rcp. We also 438*7c478bd9Sstevel@tonic-gate * save argc & argv for the same purpose 439*7c478bd9Sstevel@tonic-gate */ 440*7c478bd9Sstevel@tonic-gate (void) snprintf(cmd_orig, cmdsiz, "rcp%s%s%s%s", 441*7c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 442*7c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 443*7c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 444*7c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate (void) snprintf(cmd_sunw_orig, cmdsiz, "%s%s%s%s%s", RCP_ACL, 447*7c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 448*7c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 449*7c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 450*7c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 451*7c478bd9Sstevel@tonic-gate 452*7c478bd9Sstevel@tonic-gate prev_argc = argc; 453*7c478bd9Sstevel@tonic-gate prev_argv = save_argv(argc, argv); 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate } else { 456*7c478bd9Sstevel@tonic-gate cmdsiz = sizeof ("rcp -r -p -z -d"); 457*7c478bd9Sstevel@tonic-gate if (((cmd = (char *)malloc(cmdsiz)) == NULL)) { 458*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Cannot " 459*7c478bd9Sstevel@tonic-gate "malloc.\n")); 460*7c478bd9Sstevel@tonic-gate return (1); 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate 463*7c478bd9Sstevel@tonic-gate (void) snprintf(cmd, cmdsiz, "rcp%s%s%s%s", 464*7c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 465*7c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 466*7c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 467*7c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 468*7c478bd9Sstevel@tonic-gate } 469*7c478bd9Sstevel@tonic-gate 470*7c478bd9Sstevel@tonic-gate cmdsiz = sizeof (RCP_ACL " -r -p -z -d"); 471*7c478bd9Sstevel@tonic-gate if ((cmd_sunw = (char *)malloc(cmdsiz)) == NULL) { 472*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: Cannot malloc.\n")); 473*7c478bd9Sstevel@tonic-gate return (1); 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate (void) snprintf(cmd_sunw, cmdsiz, "%s%s%s%s%s", RCP_ACL, 477*7c478bd9Sstevel@tonic-gate iamrecursive ? " -r" : "", 478*7c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 479*7c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 480*7c478bd9Sstevel@tonic-gate targetshouldbedirectory ? " -d" : ""); 481*7c478bd9Sstevel@tonic-gate 482*7c478bd9Sstevel@tonic-gate (void) signal(SIGPIPE, (void (*)(int))lostconn); 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate if (targ = colon(argv[argc - 1])) 485*7c478bd9Sstevel@tonic-gate toremote(targ, argc, argv); 486*7c478bd9Sstevel@tonic-gate else { 487*7c478bd9Sstevel@tonic-gate tolocal(argc, argv); 488*7c478bd9Sstevel@tonic-gate if (targetshouldbedirectory) 489*7c478bd9Sstevel@tonic-gate verifydir(argv[argc - 1]); 490*7c478bd9Sstevel@tonic-gate } 491*7c478bd9Sstevel@tonic-gate 492*7c478bd9Sstevel@tonic-gate return (errs > 0 ? EXIT_FAILURE : EXIT_SUCCESS); 493*7c478bd9Sstevel@tonic-gate } 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate static void 497*7c478bd9Sstevel@tonic-gate toremote(char *targ, int argc, char *argv[]) 498*7c478bd9Sstevel@tonic-gate { 499*7c478bd9Sstevel@tonic-gate int i; 500*7c478bd9Sstevel@tonic-gate char *host, *src, *suser, *thost, *tuser; 501*7c478bd9Sstevel@tonic-gate char resp; 502*7c478bd9Sstevel@tonic-gate size_t buffersize; 503*7c478bd9Sstevel@tonic-gate char bp[RCP_BUFSIZE]; 504*7c478bd9Sstevel@tonic-gate krb5_creds *cred; 505*7c478bd9Sstevel@tonic-gate buffersize = RCP_BUFSIZE; 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate *targ++ = 0; 508*7c478bd9Sstevel@tonic-gate if (*targ == 0) 509*7c478bd9Sstevel@tonic-gate targ = "."; 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate if (thost = search_char((unsigned char *)argv[argc - 1], '@')) { 512*7c478bd9Sstevel@tonic-gate *thost++ = 0; 513*7c478bd9Sstevel@tonic-gate tuser = argv[argc - 1]; 514*7c478bd9Sstevel@tonic-gate if (*tuser == '\0') 515*7c478bd9Sstevel@tonic-gate tuser = NULL; 516*7c478bd9Sstevel@tonic-gate else if (!okname(tuser)) 517*7c478bd9Sstevel@tonic-gate exit(1); 518*7c478bd9Sstevel@tonic-gate } else { 519*7c478bd9Sstevel@tonic-gate thost = argv[argc - 1]; 520*7c478bd9Sstevel@tonic-gate tuser = NULL; 521*7c478bd9Sstevel@tonic-gate } 522*7c478bd9Sstevel@tonic-gate thost = removebrackets(thost); 523*7c478bd9Sstevel@tonic-gate 524*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc - 1; i++) { 525*7c478bd9Sstevel@tonic-gate src = colon(argv[i]); 526*7c478bd9Sstevel@tonic-gate if (src) { /* remote to remote */ 527*7c478bd9Sstevel@tonic-gate *src++ = 0; 528*7c478bd9Sstevel@tonic-gate if (*src == 0) 529*7c478bd9Sstevel@tonic-gate src = "."; 530*7c478bd9Sstevel@tonic-gate host = search_char((unsigned char *)argv[i], '@'); 531*7c478bd9Sstevel@tonic-gate if (host) { 532*7c478bd9Sstevel@tonic-gate *host++ = 0; 533*7c478bd9Sstevel@tonic-gate host = removebrackets(host); 534*7c478bd9Sstevel@tonic-gate suser = argv[i]; 535*7c478bd9Sstevel@tonic-gate if (*suser == '\0') { 536*7c478bd9Sstevel@tonic-gate suser = pwd->pw_name; 537*7c478bd9Sstevel@tonic-gate } else if (!okname(suser)) { 538*7c478bd9Sstevel@tonic-gate errs++; 539*7c478bd9Sstevel@tonic-gate continue; 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, 542*7c478bd9Sstevel@tonic-gate "%s %s -l %s -n %s %s '%s%s%s:%s'", 543*7c478bd9Sstevel@tonic-gate _PATH_RSH, host, suser, cmd, src, 544*7c478bd9Sstevel@tonic-gate tuser ? tuser : "", tuser ? "@" : "", 545*7c478bd9Sstevel@tonic-gate thost, targ); 546*7c478bd9Sstevel@tonic-gate } else { 547*7c478bd9Sstevel@tonic-gate host = removebrackets(argv[i]); 548*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, 549*7c478bd9Sstevel@tonic-gate "%s %s -n %s %s '%s%s%s:%s'", 550*7c478bd9Sstevel@tonic-gate _PATH_RSH, host, cmd, src, 551*7c478bd9Sstevel@tonic-gate tuser ? tuser : "", tuser ? "@" : "", 552*7c478bd9Sstevel@tonic-gate thost, targ); 553*7c478bd9Sstevel@tonic-gate } 554*7c478bd9Sstevel@tonic-gate if (susystem(bp) == -1) 555*7c478bd9Sstevel@tonic-gate errs++; 556*7c478bd9Sstevel@tonic-gate } else { /* local to remote */ 557*7c478bd9Sstevel@tonic-gate if (rem == -1) { 558*7c478bd9Sstevel@tonic-gate host = thost; 559*7c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 560*7c478bd9Sstevel@tonic-gate 561*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, 562*7c478bd9Sstevel@tonic-gate "%s -t %s", cmd, targ); 563*7c478bd9Sstevel@tonic-gate authopts = AP_OPTS_MUTUAL_REQUIRED; 564*7c478bd9Sstevel@tonic-gate status = kcmd(&sock, &host, 565*7c478bd9Sstevel@tonic-gate portnumber, 566*7c478bd9Sstevel@tonic-gate pwd->pw_name, 567*7c478bd9Sstevel@tonic-gate tuser ? tuser : 568*7c478bd9Sstevel@tonic-gate pwd->pw_name, 569*7c478bd9Sstevel@tonic-gate bp, 570*7c478bd9Sstevel@tonic-gate 0, 571*7c478bd9Sstevel@tonic-gate "host", 572*7c478bd9Sstevel@tonic-gate krb_realm, 573*7c478bd9Sstevel@tonic-gate bsd_context, 574*7c478bd9Sstevel@tonic-gate &auth_context, 575*7c478bd9Sstevel@tonic-gate &cred, 576*7c478bd9Sstevel@tonic-gate 0, /* No seq # */ 577*7c478bd9Sstevel@tonic-gate 0, /* No server seq # */ 578*7c478bd9Sstevel@tonic-gate authopts, 579*7c478bd9Sstevel@tonic-gate 0, /* Not any port # */ 580*7c478bd9Sstevel@tonic-gate &kcmd_proto); 581*7c478bd9Sstevel@tonic-gate if (status) { 582*7c478bd9Sstevel@tonic-gate /* 583*7c478bd9Sstevel@tonic-gate * If new protocol requested, we dont 584*7c478bd9Sstevel@tonic-gate * fallback to less secure ones. 585*7c478bd9Sstevel@tonic-gate */ 586*7c478bd9Sstevel@tonic-gate 587*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 588*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 589*7c478bd9Sstevel@tonic-gate gettext("rcp: kcmdv2 " 590*7c478bd9Sstevel@tonic-gate "to host %s failed - %s" 591*7c478bd9Sstevel@tonic-gate "\nFallback to normal " 592*7c478bd9Sstevel@tonic-gate "rcp denied."), host, 593*7c478bd9Sstevel@tonic-gate error_message(status)); 594*7c478bd9Sstevel@tonic-gate exit(1); 595*7c478bd9Sstevel@tonic-gate } 596*7c478bd9Sstevel@tonic-gate if (status != -1) { 597*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 598*7c478bd9Sstevel@tonic-gate gettext("rcp: kcmd to host " 599*7c478bd9Sstevel@tonic-gate "%s failed - %s,\n" 600*7c478bd9Sstevel@tonic-gate "trying normal rcp...\n\n"), 601*7c478bd9Sstevel@tonic-gate host, error_message(status)); 602*7c478bd9Sstevel@tonic-gate } else { 603*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 604*7c478bd9Sstevel@tonic-gate gettext("trying normal" 605*7c478bd9Sstevel@tonic-gate " rcp...\n")); 606*7c478bd9Sstevel@tonic-gate } 607*7c478bd9Sstevel@tonic-gate /* 608*7c478bd9Sstevel@tonic-gate * kcmd() failed, so we have to 609*7c478bd9Sstevel@tonic-gate * fallback to normal rcp 610*7c478bd9Sstevel@tonic-gate */ 611*7c478bd9Sstevel@tonic-gate try_normal_rcp(prev_argc, prev_argv); 612*7c478bd9Sstevel@tonic-gate } else { 613*7c478bd9Sstevel@tonic-gate rem = sock; 614*7c478bd9Sstevel@tonic-gate session_key = &cred->keyblock; 615*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 616*7c478bd9Sstevel@tonic-gate /* CSTYLED */ 617*7c478bd9Sstevel@tonic-gate status = krb5_auth_con_getlocalsubkey(bsd_context, auth_context, &session_key); 618*7c478bd9Sstevel@tonic-gate if (status) { 619*7c478bd9Sstevel@tonic-gate com_err("rcp", status, 620*7c478bd9Sstevel@tonic-gate "determining " 621*7c478bd9Sstevel@tonic-gate "subkey for " 622*7c478bd9Sstevel@tonic-gate "session"); 623*7c478bd9Sstevel@tonic-gate exit(1); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate if (!session_key) { 626*7c478bd9Sstevel@tonic-gate com_err("rcp", 0, 627*7c478bd9Sstevel@tonic-gate "no subkey " 628*7c478bd9Sstevel@tonic-gate "negotiated for" 629*7c478bd9Sstevel@tonic-gate " connection"); 630*7c478bd9Sstevel@tonic-gate exit(1); 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate } 633*7c478bd9Sstevel@tonic-gate eblock.crypto_entry = 634*7c478bd9Sstevel@tonic-gate session_key->enctype; 635*7c478bd9Sstevel@tonic-gate eblock.key = 636*7c478bd9Sstevel@tonic-gate (krb5_keyblock *)session_key; 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate init_encrypt(encrypt_flag, 639*7c478bd9Sstevel@tonic-gate bsd_context, kcmd_proto, 640*7c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, 641*7c478bd9Sstevel@tonic-gate &eblock); 642*7c478bd9Sstevel@tonic-gate if (encrypt_flag > 0) { 643*7c478bd9Sstevel@tonic-gate char *s = gettext("This rcp " 644*7c478bd9Sstevel@tonic-gate "session is using " 645*7c478bd9Sstevel@tonic-gate "encryption for all " 646*7c478bd9Sstevel@tonic-gate "data transmissions." 647*7c478bd9Sstevel@tonic-gate "\r\n"); 648*7c478bd9Sstevel@tonic-gate 649*7c478bd9Sstevel@tonic-gate (void) write(2, s, strlen(s)); 650*7c478bd9Sstevel@tonic-gate } 651*7c478bd9Sstevel@tonic-gate } 652*7c478bd9Sstevel@tonic-gate if (response() < 0) 653*7c478bd9Sstevel@tonic-gate exit(1); 654*7c478bd9Sstevel@tonic-gate 655*7c478bd9Sstevel@tonic-gate } 656*7c478bd9Sstevel@tonic-gate else 657*7c478bd9Sstevel@tonic-gate { 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* 660*7c478bd9Sstevel@tonic-gate * ACL support: try to find out if the remote 661*7c478bd9Sstevel@tonic-gate * site is running acl cognizant version of 662*7c478bd9Sstevel@tonic-gate * rcp. A special binary name is used for this 663*7c478bd9Sstevel@tonic-gate * purpose. 664*7c478bd9Sstevel@tonic-gate */ 665*7c478bd9Sstevel@tonic-gate aclflag = 1; 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, "%s -t %s", 668*7c478bd9Sstevel@tonic-gate cmd_sunw, targ); 669*7c478bd9Sstevel@tonic-gate rem = rcmd_af(&host, portnumber, pwd->pw_name, 670*7c478bd9Sstevel@tonic-gate tuser ? tuser : pwd->pw_name, 671*7c478bd9Sstevel@tonic-gate bp, 0, AF_INET6); 672*7c478bd9Sstevel@tonic-gate if (rem < 0) 673*7c478bd9Sstevel@tonic-gate exit(1); 674*7c478bd9Sstevel@tonic-gate 675*7c478bd9Sstevel@tonic-gate /* 676*7c478bd9Sstevel@tonic-gate * This is similar to routine response(). 677*7c478bd9Sstevel@tonic-gate * If response is not ok, treat the other 678*7c478bd9Sstevel@tonic-gate * side as non-acl rcp. 679*7c478bd9Sstevel@tonic-gate */ 680*7c478bd9Sstevel@tonic-gate if (read(rem, &resp, sizeof (resp)) 681*7c478bd9Sstevel@tonic-gate != sizeof (resp)) 682*7c478bd9Sstevel@tonic-gate lostconn(); 683*7c478bd9Sstevel@tonic-gate if (resp != 0) { 684*7c478bd9Sstevel@tonic-gate /* 685*7c478bd9Sstevel@tonic-gate * Not OK: 686*7c478bd9Sstevel@tonic-gate * The other side is running 687*7c478bd9Sstevel@tonic-gate * non-acl rcp. Try again with 688*7c478bd9Sstevel@tonic-gate * normal stuff 689*7c478bd9Sstevel@tonic-gate */ 690*7c478bd9Sstevel@tonic-gate aclflag = 0; 691*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, 692*7c478bd9Sstevel@tonic-gate "%s -t %s", cmd, targ); 693*7c478bd9Sstevel@tonic-gate (void) close(rem); 694*7c478bd9Sstevel@tonic-gate host = thost; 695*7c478bd9Sstevel@tonic-gate rem = rcmd_af(&host, portnumber, 696*7c478bd9Sstevel@tonic-gate pwd->pw_name, 697*7c478bd9Sstevel@tonic-gate tuser ? tuser : 698*7c478bd9Sstevel@tonic-gate pwd->pw_name, bp, 0, 699*7c478bd9Sstevel@tonic-gate AF_INET6); 700*7c478bd9Sstevel@tonic-gate if (rem < 0) 701*7c478bd9Sstevel@tonic-gate exit(1); 702*7c478bd9Sstevel@tonic-gate if (response() < 0) 703*7c478bd9Sstevel@tonic-gate exit(1); 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate /* everything should be fine now */ 706*7c478bd9Sstevel@tonic-gate (void) setuid(userid); 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate } 709*7c478bd9Sstevel@tonic-gate 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate source(1, argv + i); 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate } 714*7c478bd9Sstevel@tonic-gate } 715*7c478bd9Sstevel@tonic-gate 716*7c478bd9Sstevel@tonic-gate static void 717*7c478bd9Sstevel@tonic-gate tolocal(int argc, char *argv[]) 718*7c478bd9Sstevel@tonic-gate { 719*7c478bd9Sstevel@tonic-gate int i; 720*7c478bd9Sstevel@tonic-gate char *host, *src, *suser, *lhost; 721*7c478bd9Sstevel@tonic-gate char resp; 722*7c478bd9Sstevel@tonic-gate size_t buffersize; 723*7c478bd9Sstevel@tonic-gate char bp[RCP_BUFSIZE]; 724*7c478bd9Sstevel@tonic-gate krb5_creds *cred; 725*7c478bd9Sstevel@tonic-gate buffersize = RCP_BUFSIZE; 726*7c478bd9Sstevel@tonic-gate 727*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc - 1; i++) { 728*7c478bd9Sstevel@tonic-gate if (!(src = colon(argv[i]))) { /* local to local */ 729*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, "%s%s%s%s %s %s", 730*7c478bd9Sstevel@tonic-gate _PATH_CP, iamrecursive ? " -r" : "", 731*7c478bd9Sstevel@tonic-gate pflag ? " -p" : "", 732*7c478bd9Sstevel@tonic-gate zflag ? " -z" : "", 733*7c478bd9Sstevel@tonic-gate argv[i], argv[argc - 1]); 734*7c478bd9Sstevel@tonic-gate if (susystem(bp) == -1) 735*7c478bd9Sstevel@tonic-gate errs++; 736*7c478bd9Sstevel@tonic-gate continue; 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate *src++ = 0; 739*7c478bd9Sstevel@tonic-gate if (*src == 0) 740*7c478bd9Sstevel@tonic-gate src = "."; 741*7c478bd9Sstevel@tonic-gate host = search_char((unsigned char *)argv[i], '@'); 742*7c478bd9Sstevel@tonic-gate if (host) { 743*7c478bd9Sstevel@tonic-gate *host++ = 0; 744*7c478bd9Sstevel@tonic-gate suser = argv[i]; 745*7c478bd9Sstevel@tonic-gate if (*suser == '\0') { 746*7c478bd9Sstevel@tonic-gate suser = pwd->pw_name; 747*7c478bd9Sstevel@tonic-gate } else if (!okname(suser)) { 748*7c478bd9Sstevel@tonic-gate errs++; 749*7c478bd9Sstevel@tonic-gate continue; 750*7c478bd9Sstevel@tonic-gate } 751*7c478bd9Sstevel@tonic-gate } else { 752*7c478bd9Sstevel@tonic-gate host = argv[i]; 753*7c478bd9Sstevel@tonic-gate suser = pwd->pw_name; 754*7c478bd9Sstevel@tonic-gate } 755*7c478bd9Sstevel@tonic-gate host = removebrackets(host); 756*7c478bd9Sstevel@tonic-gate lhost = host; 757*7c478bd9Sstevel@tonic-gate if (krb5auth_flag > 0) { 758*7c478bd9Sstevel@tonic-gate 759*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, "%s -f %s", cmd, src); 760*7c478bd9Sstevel@tonic-gate authopts = AP_OPTS_MUTUAL_REQUIRED; 761*7c478bd9Sstevel@tonic-gate status = kcmd(&sock, &host, 762*7c478bd9Sstevel@tonic-gate portnumber, 763*7c478bd9Sstevel@tonic-gate pwd->pw_name, suser, 764*7c478bd9Sstevel@tonic-gate bp, 765*7c478bd9Sstevel@tonic-gate 0, /* &rfd2 */ 766*7c478bd9Sstevel@tonic-gate "host", 767*7c478bd9Sstevel@tonic-gate krb_realm, 768*7c478bd9Sstevel@tonic-gate bsd_context, 769*7c478bd9Sstevel@tonic-gate &auth_context, 770*7c478bd9Sstevel@tonic-gate &cred, 771*7c478bd9Sstevel@tonic-gate 0, /* No seq # */ 772*7c478bd9Sstevel@tonic-gate 0, /* No server seq # */ 773*7c478bd9Sstevel@tonic-gate authopts, 774*7c478bd9Sstevel@tonic-gate 1, /* Not any port # */ 775*7c478bd9Sstevel@tonic-gate &kcmd_proto); 776*7c478bd9Sstevel@tonic-gate if (status) { 777*7c478bd9Sstevel@tonic-gate /* 778*7c478bd9Sstevel@tonic-gate * If new protocol requested, we dont 779*7c478bd9Sstevel@tonic-gate * fallback to less secure ones. 780*7c478bd9Sstevel@tonic-gate */ 781*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 782*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: kcmdv2 " 783*7c478bd9Sstevel@tonic-gate "to host %s failed - %s\n" 784*7c478bd9Sstevel@tonic-gate "Fallback to normal rcp denied."), 785*7c478bd9Sstevel@tonic-gate host, error_message(status)); 786*7c478bd9Sstevel@tonic-gate exit(1); 787*7c478bd9Sstevel@tonic-gate } 788*7c478bd9Sstevel@tonic-gate if (status != -1) { 789*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, gettext("rcp: kcmd " 790*7c478bd9Sstevel@tonic-gate "to host %s failed - %s,\n" 791*7c478bd9Sstevel@tonic-gate "trying normal rcp...\n\n"), 792*7c478bd9Sstevel@tonic-gate host, error_message(status)); 793*7c478bd9Sstevel@tonic-gate } else { 794*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 795*7c478bd9Sstevel@tonic-gate gettext("trying normal rcp...\n")); 796*7c478bd9Sstevel@tonic-gate } 797*7c478bd9Sstevel@tonic-gate /* 798*7c478bd9Sstevel@tonic-gate * kcmd() failed, so we have to 799*7c478bd9Sstevel@tonic-gate * fallback to normal rcp 800*7c478bd9Sstevel@tonic-gate */ 801*7c478bd9Sstevel@tonic-gate try_normal_rcp(prev_argc, prev_argv); 802*7c478bd9Sstevel@tonic-gate } else { 803*7c478bd9Sstevel@tonic-gate rem = sock; 804*7c478bd9Sstevel@tonic-gate session_key = &cred->keyblock; 805*7c478bd9Sstevel@tonic-gate if (kcmd_proto == KCMD_NEW_PROTOCOL) { 806*7c478bd9Sstevel@tonic-gate status = krb5_auth_con_getlocalsubkey( 807*7c478bd9Sstevel@tonic-gate bsd_context, auth_context, 808*7c478bd9Sstevel@tonic-gate &session_key); 809*7c478bd9Sstevel@tonic-gate if (status) { 810*7c478bd9Sstevel@tonic-gate com_err("rcp", status, "determining " 811*7c478bd9Sstevel@tonic-gate "subkey for session"); 812*7c478bd9Sstevel@tonic-gate exit(1); 813*7c478bd9Sstevel@tonic-gate } 814*7c478bd9Sstevel@tonic-gate if (!session_key) { 815*7c478bd9Sstevel@tonic-gate com_err("rcp", 0, "no subkey negotiated" 816*7c478bd9Sstevel@tonic-gate " for connection"); 817*7c478bd9Sstevel@tonic-gate exit(1); 818*7c478bd9Sstevel@tonic-gate } 819*7c478bd9Sstevel@tonic-gate } 820*7c478bd9Sstevel@tonic-gate eblock.crypto_entry = session_key->enctype; 821*7c478bd9Sstevel@tonic-gate eblock.key = (krb5_keyblock *)session_key; 822*7c478bd9Sstevel@tonic-gate 823*7c478bd9Sstevel@tonic-gate init_encrypt(encrypt_flag, bsd_context, kcmd_proto, 824*7c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, 825*7c478bd9Sstevel@tonic-gate &eblock); 826*7c478bd9Sstevel@tonic-gate if (encrypt_flag > 0) { 827*7c478bd9Sstevel@tonic-gate char *s = gettext("This rcp " 828*7c478bd9Sstevel@tonic-gate "session is using DES " 829*7c478bd9Sstevel@tonic-gate "encryption for all " 830*7c478bd9Sstevel@tonic-gate "data transmissions." 831*7c478bd9Sstevel@tonic-gate "\r\n"); 832*7c478bd9Sstevel@tonic-gate 833*7c478bd9Sstevel@tonic-gate (void) write(2, s, strlen(s)); 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate } 836*7c478bd9Sstevel@tonic-gate 837*7c478bd9Sstevel@tonic-gate } 838*7c478bd9Sstevel@tonic-gate else 839*7c478bd9Sstevel@tonic-gate { 840*7c478bd9Sstevel@tonic-gate 841*7c478bd9Sstevel@tonic-gate /* 842*7c478bd9Sstevel@tonic-gate * ACL support: try to find out if the remote site is 843*7c478bd9Sstevel@tonic-gate * running acl cognizant version of rcp. 844*7c478bd9Sstevel@tonic-gate */ 845*7c478bd9Sstevel@tonic-gate aclflag = 1; 846*7c478bd9Sstevel@tonic-gate 847*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, "%s -f %s", cmd_sunw, src); 848*7c478bd9Sstevel@tonic-gate rem = rcmd_af(&host, portnumber, pwd->pw_name, suser, 849*7c478bd9Sstevel@tonic-gate bp, 0, AF_INET6); 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate if (rem < 0) { 852*7c478bd9Sstevel@tonic-gate ++errs; 853*7c478bd9Sstevel@tonic-gate continue; 854*7c478bd9Sstevel@tonic-gate } 855*7c478bd9Sstevel@tonic-gate 856*7c478bd9Sstevel@tonic-gate /* 857*7c478bd9Sstevel@tonic-gate * The remote system is supposed to send an ok response. 858*7c478bd9Sstevel@tonic-gate * If there are any data other than "ok", it must be error 859*7c478bd9Sstevel@tonic-gate * messages from the remote system. We can assume the 860*7c478bd9Sstevel@tonic-gate * remote system is running non-acl version rcp. 861*7c478bd9Sstevel@tonic-gate */ 862*7c478bd9Sstevel@tonic-gate if (read(rem, &resp, sizeof (resp)) != sizeof (resp)) 863*7c478bd9Sstevel@tonic-gate lostconn(); 864*7c478bd9Sstevel@tonic-gate if (resp != 0) { 865*7c478bd9Sstevel@tonic-gate /* 866*7c478bd9Sstevel@tonic-gate * NOT ok: 867*7c478bd9Sstevel@tonic-gate * The other side is running non-acl rcp. 868*7c478bd9Sstevel@tonic-gate * Try again with normal stuff 869*7c478bd9Sstevel@tonic-gate */ 870*7c478bd9Sstevel@tonic-gate aclflag = 0; 871*7c478bd9Sstevel@tonic-gate (void) snprintf(bp, buffersize, "%s -f %s", cmd, src); 872*7c478bd9Sstevel@tonic-gate (void) close(rem); 873*7c478bd9Sstevel@tonic-gate host = lhost; 874*7c478bd9Sstevel@tonic-gate rem = rcmd_af(&host, portnumber, pwd->pw_name, 875*7c478bd9Sstevel@tonic-gate suser, bp, 0, AF_INET6); 876*7c478bd9Sstevel@tonic-gate if (rem < 0) { 877*7c478bd9Sstevel@tonic-gate ++errs; 878*7c478bd9Sstevel@tonic-gate continue; 879*7c478bd9Sstevel@tonic-gate } 880*7c478bd9Sstevel@tonic-gate } 881*7c478bd9Sstevel@tonic-gate } 882*7c478bd9Sstevel@tonic-gate 883*7c478bd9Sstevel@tonic-gate sink(1, argv + argc - 1); 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate (void) close(rem); 886*7c478bd9Sstevel@tonic-gate rem = -1; 887*7c478bd9Sstevel@tonic-gate } 888*7c478bd9Sstevel@tonic-gate } 889*7c478bd9Sstevel@tonic-gate 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate static void 892*7c478bd9Sstevel@tonic-gate verifydir(char *cp) 893*7c478bd9Sstevel@tonic-gate { 894*7c478bd9Sstevel@tonic-gate struct stat stb; 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (stat(cp, &stb) >= 0) { 897*7c478bd9Sstevel@tonic-gate if ((stb.st_mode & S_IFMT) == S_IFDIR) 898*7c478bd9Sstevel@tonic-gate return; 899*7c478bd9Sstevel@tonic-gate errno = ENOTDIR; 900*7c478bd9Sstevel@tonic-gate } 901*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s.\n", cp, strerror(errno)); 902*7c478bd9Sstevel@tonic-gate exit(1); 903*7c478bd9Sstevel@tonic-gate } 904*7c478bd9Sstevel@tonic-gate 905*7c478bd9Sstevel@tonic-gate static char * 906*7c478bd9Sstevel@tonic-gate colon(char *cp) 907*7c478bd9Sstevel@tonic-gate { 908*7c478bd9Sstevel@tonic-gate boolean_t is_bracket_open = B_FALSE; 909*7c478bd9Sstevel@tonic-gate 910*7c478bd9Sstevel@tonic-gate for (; *cp; ++cp) { 911*7c478bd9Sstevel@tonic-gate if (*cp == '[') 912*7c478bd9Sstevel@tonic-gate is_bracket_open = B_TRUE; 913*7c478bd9Sstevel@tonic-gate else if (*cp == ']') 914*7c478bd9Sstevel@tonic-gate is_bracket_open = B_FALSE; 915*7c478bd9Sstevel@tonic-gate else if (*cp == ':' && !is_bracket_open) 916*7c478bd9Sstevel@tonic-gate return (cp); 917*7c478bd9Sstevel@tonic-gate else if (*cp == '/') 918*7c478bd9Sstevel@tonic-gate return (0); 919*7c478bd9Sstevel@tonic-gate } 920*7c478bd9Sstevel@tonic-gate return (0); 921*7c478bd9Sstevel@tonic-gate } 922*7c478bd9Sstevel@tonic-gate 923*7c478bd9Sstevel@tonic-gate static int 924*7c478bd9Sstevel@tonic-gate okname(char *cp0) 925*7c478bd9Sstevel@tonic-gate { 926*7c478bd9Sstevel@tonic-gate register char *cp = cp0; 927*7c478bd9Sstevel@tonic-gate register int c; 928*7c478bd9Sstevel@tonic-gate 929*7c478bd9Sstevel@tonic-gate do { 930*7c478bd9Sstevel@tonic-gate c = *cp; 931*7c478bd9Sstevel@tonic-gate if (c & 0200) 932*7c478bd9Sstevel@tonic-gate goto bad; 933*7c478bd9Sstevel@tonic-gate if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 934*7c478bd9Sstevel@tonic-gate goto bad; 935*7c478bd9Sstevel@tonic-gate } while (*++cp); 936*7c478bd9Sstevel@tonic-gate return (1); 937*7c478bd9Sstevel@tonic-gate bad: 938*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: invalid user name %s\n", cp0); 939*7c478bd9Sstevel@tonic-gate return (0); 940*7c478bd9Sstevel@tonic-gate } 941*7c478bd9Sstevel@tonic-gate 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate static char * 944*7c478bd9Sstevel@tonic-gate removebrackets(char *str) 945*7c478bd9Sstevel@tonic-gate { 946*7c478bd9Sstevel@tonic-gate char *newstr = str; 947*7c478bd9Sstevel@tonic-gate 948*7c478bd9Sstevel@tonic-gate if ((str[0] == '[') && (str[strlen(str) - 1] == ']')) { 949*7c478bd9Sstevel@tonic-gate newstr = str + 1; 950*7c478bd9Sstevel@tonic-gate str[strlen(str) - 1] = '\0'; 951*7c478bd9Sstevel@tonic-gate } 952*7c478bd9Sstevel@tonic-gate return (newstr); 953*7c478bd9Sstevel@tonic-gate } 954*7c478bd9Sstevel@tonic-gate 955*7c478bd9Sstevel@tonic-gate static int 956*7c478bd9Sstevel@tonic-gate susystem(char *s) 957*7c478bd9Sstevel@tonic-gate { 958*7c478bd9Sstevel@tonic-gate int status, pid, w; 959*7c478bd9Sstevel@tonic-gate register void (*istat)(), (*qstat)(); 960*7c478bd9Sstevel@tonic-gate int pfds[2]; 961*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 962*7c478bd9Sstevel@tonic-gate int cnt; 963*7c478bd9Sstevel@tonic-gate boolean_t seen_stderr_traffic; 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate /* 966*7c478bd9Sstevel@tonic-gate * Due to the fact that rcp uses rsh to copy between 2 remote 967*7c478bd9Sstevel@tonic-gate * machines, rsh doesn't return the exit status of the remote 968*7c478bd9Sstevel@tonic-gate * command, and we can't modify the rcmd protocol used by rsh 969*7c478bd9Sstevel@tonic-gate * (for interoperability reasons) we use the hack of using any 970*7c478bd9Sstevel@tonic-gate * output on stderr as indication that an error occurred and 971*7c478bd9Sstevel@tonic-gate * that we should return a non-zero error code. 972*7c478bd9Sstevel@tonic-gate */ 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate if (pipe(pfds) == -1) { 975*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Couldn't create pipe: %s\n", 976*7c478bd9Sstevel@tonic-gate strerror(errno)); 977*7c478bd9Sstevel@tonic-gate return (-1); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate if ((pid = vfork()) < 0) { 981*7c478bd9Sstevel@tonic-gate (void) close(pfds[0]); 982*7c478bd9Sstevel@tonic-gate (void) close(pfds[1]); 983*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "Couldn't fork child process: %s\n", 984*7c478bd9Sstevel@tonic-gate strerror(errno)); 985*7c478bd9Sstevel@tonic-gate return (-1); 986*7c478bd9Sstevel@tonic-gate } else if (pid == 0) { 987*7c478bd9Sstevel@tonic-gate /* 988*7c478bd9Sstevel@tonic-gate * Child. 989*7c478bd9Sstevel@tonic-gate */ 990*7c478bd9Sstevel@tonic-gate (void) close(pfds[0]); 991*7c478bd9Sstevel@tonic-gate /* 992*7c478bd9Sstevel@tonic-gate * Send stderr messages down the pipe so that we can detect 993*7c478bd9Sstevel@tonic-gate * them in the parent process. 994*7c478bd9Sstevel@tonic-gate */ 995*7c478bd9Sstevel@tonic-gate if (pfds[1] != STDERR_FILENO) { 996*7c478bd9Sstevel@tonic-gate (void) dup2(pfds[1], STDERR_FILENO); 997*7c478bd9Sstevel@tonic-gate (void) close(pfds[1]); 998*7c478bd9Sstevel@tonic-gate } 999*7c478bd9Sstevel@tonic-gate /* 1000*7c478bd9Sstevel@tonic-gate * This shell does not inherit the additional privilege 1001*7c478bd9Sstevel@tonic-gate * we have in our Permitted set. 1002*7c478bd9Sstevel@tonic-gate */ 1003*7c478bd9Sstevel@tonic-gate (void) execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 1004*7c478bd9Sstevel@tonic-gate _exit(127); 1005*7c478bd9Sstevel@tonic-gate } 1006*7c478bd9Sstevel@tonic-gate /* 1007*7c478bd9Sstevel@tonic-gate * Parent. 1008*7c478bd9Sstevel@tonic-gate */ 1009*7c478bd9Sstevel@tonic-gate istat = signal(SIGINT, SIG_IGN); 1010*7c478bd9Sstevel@tonic-gate qstat = signal(SIGQUIT, SIG_IGN); 1011*7c478bd9Sstevel@tonic-gate 1012*7c478bd9Sstevel@tonic-gate (void) close(pfds[1]); 1013*7c478bd9Sstevel@tonic-gate seen_stderr_traffic = B_FALSE; 1014*7c478bd9Sstevel@tonic-gate while ((cnt = read(pfds[0], buf, sizeof (buf))) > 0) { 1015*7c478bd9Sstevel@tonic-gate /* 1016*7c478bd9Sstevel@tonic-gate * If any data is read from the pipe the child process 1017*7c478bd9Sstevel@tonic-gate * has output something on stderr so we set the boolean 1018*7c478bd9Sstevel@tonic-gate * 'seen_stderr_traffic' to true, which will cause the 1019*7c478bd9Sstevel@tonic-gate * function to return -1. 1020*7c478bd9Sstevel@tonic-gate */ 1021*7c478bd9Sstevel@tonic-gate (void) write(STDERR_FILENO, buf, cnt); 1022*7c478bd9Sstevel@tonic-gate seen_stderr_traffic = B_TRUE; 1023*7c478bd9Sstevel@tonic-gate } 1024*7c478bd9Sstevel@tonic-gate (void) close(pfds[0]); 1025*7c478bd9Sstevel@tonic-gate while ((w = wait(&status)) != pid && w != -1) 1026*7c478bd9Sstevel@tonic-gate ; 1027*7c478bd9Sstevel@tonic-gate if (w == -1) 1028*7c478bd9Sstevel@tonic-gate status = -1; 1029*7c478bd9Sstevel@tonic-gate 1030*7c478bd9Sstevel@tonic-gate (void) signal(SIGINT, istat); 1031*7c478bd9Sstevel@tonic-gate (void) signal(SIGQUIT, qstat); 1032*7c478bd9Sstevel@tonic-gate 1033*7c478bd9Sstevel@tonic-gate return (seen_stderr_traffic ? -1 : status); 1034*7c478bd9Sstevel@tonic-gate } 1035*7c478bd9Sstevel@tonic-gate 1036*7c478bd9Sstevel@tonic-gate static void 1037*7c478bd9Sstevel@tonic-gate source(int argc, char *argv[]) 1038*7c478bd9Sstevel@tonic-gate { 1039*7c478bd9Sstevel@tonic-gate struct stat stb; 1040*7c478bd9Sstevel@tonic-gate static BUF buffer; 1041*7c478bd9Sstevel@tonic-gate BUF *bp; 1042*7c478bd9Sstevel@tonic-gate int x, readerr, f, amt; 1043*7c478bd9Sstevel@tonic-gate char *last, *name, buf[RCP_BUFSIZE]; 1044*7c478bd9Sstevel@tonic-gate off_t off, size, i; 1045*7c478bd9Sstevel@tonic-gate ssize_t cnt; 1046*7c478bd9Sstevel@tonic-gate 1047*7c478bd9Sstevel@tonic-gate for (x = 0; x < argc; x++) { 1048*7c478bd9Sstevel@tonic-gate name = argv[x]; 1049*7c478bd9Sstevel@tonic-gate if ((f = open(name, O_RDONLY, 0)) < 0) { 1050*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, strerror(errno)); 1051*7c478bd9Sstevel@tonic-gate continue; 1052*7c478bd9Sstevel@tonic-gate } 1053*7c478bd9Sstevel@tonic-gate if (fstat(f, &stb) < 0) 1054*7c478bd9Sstevel@tonic-gate goto notreg; 1055*7c478bd9Sstevel@tonic-gate switch (stb.st_mode&S_IFMT) { 1056*7c478bd9Sstevel@tonic-gate 1057*7c478bd9Sstevel@tonic-gate case S_IFREG: 1058*7c478bd9Sstevel@tonic-gate break; 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate case S_IFDIR: 1061*7c478bd9Sstevel@tonic-gate if (iamrecursive) { 1062*7c478bd9Sstevel@tonic-gate (void) close(f); 1063*7c478bd9Sstevel@tonic-gate rsource(name, &stb); 1064*7c478bd9Sstevel@tonic-gate continue; 1065*7c478bd9Sstevel@tonic-gate } 1066*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1067*7c478bd9Sstevel@tonic-gate default: 1068*7c478bd9Sstevel@tonic-gate notreg: 1069*7c478bd9Sstevel@tonic-gate (void) close(f); 1070*7c478bd9Sstevel@tonic-gate error("rcp: %s: not a plain file\n", name); 1071*7c478bd9Sstevel@tonic-gate continue; 1072*7c478bd9Sstevel@tonic-gate } 1073*7c478bd9Sstevel@tonic-gate last = rindex(name, '/'); 1074*7c478bd9Sstevel@tonic-gate if (last == 0) 1075*7c478bd9Sstevel@tonic-gate last = name; 1076*7c478bd9Sstevel@tonic-gate else 1077*7c478bd9Sstevel@tonic-gate last++; 1078*7c478bd9Sstevel@tonic-gate if (pflag) { 1079*7c478bd9Sstevel@tonic-gate time_t mtime, atime; 1080*7c478bd9Sstevel@tonic-gate time_t now; 1081*7c478bd9Sstevel@tonic-gate 1082*7c478bd9Sstevel@tonic-gate /* 1083*7c478bd9Sstevel@tonic-gate * Make it compatible with possible future 1084*7c478bd9Sstevel@tonic-gate * versions expecting microseconds. 1085*7c478bd9Sstevel@tonic-gate */ 1086*7c478bd9Sstevel@tonic-gate mtime = stb.st_mtime; 1087*7c478bd9Sstevel@tonic-gate atime = stb.st_atime; 1088*7c478bd9Sstevel@tonic-gate 1089*7c478bd9Sstevel@tonic-gate if ((mtime < 0) || (atime < 0)) { 1090*7c478bd9Sstevel@tonic-gate now = time(NULL); 1091*7c478bd9Sstevel@tonic-gate 1092*7c478bd9Sstevel@tonic-gate if (mtime < 0) { 1093*7c478bd9Sstevel@tonic-gate mtime = now; 1094*7c478bd9Sstevel@tonic-gate error("negative modification time on " 1095*7c478bd9Sstevel@tonic-gate "%s; not preserving\n", name); 1096*7c478bd9Sstevel@tonic-gate } 1097*7c478bd9Sstevel@tonic-gate if (atime < 0) { 1098*7c478bd9Sstevel@tonic-gate atime = now; 1099*7c478bd9Sstevel@tonic-gate error("negative access time on " 1100*7c478bd9Sstevel@tonic-gate "%s; not preserving\n", name); 1101*7c478bd9Sstevel@tonic-gate } 1102*7c478bd9Sstevel@tonic-gate } 1103*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "T%ld 0 %ld 0\n", 1104*7c478bd9Sstevel@tonic-gate mtime, atime); 1105*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 1106*7c478bd9Sstevel@tonic-gate if (response() < 0) { 1107*7c478bd9Sstevel@tonic-gate (void) close(f); 1108*7c478bd9Sstevel@tonic-gate continue; 1109*7c478bd9Sstevel@tonic-gate } 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "C%04o %lld %s\n", 1112*7c478bd9Sstevel@tonic-gate (uint_t)(stb.st_mode & 07777), (longlong_t)stb.st_size, 1113*7c478bd9Sstevel@tonic-gate last); 1114*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 1115*7c478bd9Sstevel@tonic-gate if (response() < 0) { 1116*7c478bd9Sstevel@tonic-gate (void) close(f); 1117*7c478bd9Sstevel@tonic-gate continue; 1118*7c478bd9Sstevel@tonic-gate } 1119*7c478bd9Sstevel@tonic-gate 1120*7c478bd9Sstevel@tonic-gate /* ACL support: send */ 1121*7c478bd9Sstevel@tonic-gate if (aclflag) { 1122*7c478bd9Sstevel@tonic-gate /* get acl from f and send it over */ 1123*7c478bd9Sstevel@tonic-gate if (sendacl(f) == ACL_FAIL) { 1124*7c478bd9Sstevel@tonic-gate (void) close(f); 1125*7c478bd9Sstevel@tonic-gate continue; 1126*7c478bd9Sstevel@tonic-gate } 1127*7c478bd9Sstevel@tonic-gate } 1128*7c478bd9Sstevel@tonic-gate if ((krb5auth_flag > 0) || (iamremote == 1)) { 1129*7c478bd9Sstevel@tonic-gate bp = allocbuf(&buffer, f, RCP_BUFSIZE); 1130*7c478bd9Sstevel@tonic-gate if (bp == NULLBUF) { 1131*7c478bd9Sstevel@tonic-gate (void) close(f); 1132*7c478bd9Sstevel@tonic-gate continue; 1133*7c478bd9Sstevel@tonic-gate } 1134*7c478bd9Sstevel@tonic-gate readerr = 0; 1135*7c478bd9Sstevel@tonic-gate for (i = 0; i < stb.st_size; i += bp->cnt) { 1136*7c478bd9Sstevel@tonic-gate amt = bp->cnt; 1137*7c478bd9Sstevel@tonic-gate if (i + amt > stb.st_size) 1138*7c478bd9Sstevel@tonic-gate amt = stb.st_size - i; 1139*7c478bd9Sstevel@tonic-gate if (readerr == 0 && 1140*7c478bd9Sstevel@tonic-gate read(f, bp->buf, amt) != amt) 1141*7c478bd9Sstevel@tonic-gate readerr = errno; 1142*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, bp->buf, amt); 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate (void) close(f); 1145*7c478bd9Sstevel@tonic-gate if (readerr == 0) 1146*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1147*7c478bd9Sstevel@tonic-gate else 1148*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, 1149*7c478bd9Sstevel@tonic-gate error_message(readerr)); 1150*7c478bd9Sstevel@tonic-gate } else { 1151*7c478bd9Sstevel@tonic-gate cnt = off = 0; 1152*7c478bd9Sstevel@tonic-gate size = stb.st_size; 1153*7c478bd9Sstevel@tonic-gate while (size != 0) { 1154*7c478bd9Sstevel@tonic-gate amt = MIN(size, SENDFILE_SIZE); 1155*7c478bd9Sstevel@tonic-gate cnt = sendfile(rem, f, &off, amt); 1156*7c478bd9Sstevel@tonic-gate if (cnt == -1) 1157*7c478bd9Sstevel@tonic-gate break; 1158*7c478bd9Sstevel@tonic-gate size -= cnt; 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate if (cnt == -1) { 1161*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, strerror(errno)); 1162*7c478bd9Sstevel@tonic-gate } else { 1163*7c478bd9Sstevel@tonic-gate (void) write(rem, "", 1); 1164*7c478bd9Sstevel@tonic-gate } 1165*7c478bd9Sstevel@tonic-gate (void) close(f); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate (void) response(); 1168*7c478bd9Sstevel@tonic-gate } 1169*7c478bd9Sstevel@tonic-gate } 1170*7c478bd9Sstevel@tonic-gate 1171*7c478bd9Sstevel@tonic-gate 1172*7c478bd9Sstevel@tonic-gate static void 1173*7c478bd9Sstevel@tonic-gate rsource(char *name, struct stat *statp) 1174*7c478bd9Sstevel@tonic-gate { 1175*7c478bd9Sstevel@tonic-gate DIR *d; 1176*7c478bd9Sstevel@tonic-gate struct dirent *dp; 1177*7c478bd9Sstevel@tonic-gate char *last, *vect[1]; 1178*7c478bd9Sstevel@tonic-gate char path[MAXPATHLEN]; 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate if (!(d = opendir(name))) { 1181*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", name, strerror(errno)); 1182*7c478bd9Sstevel@tonic-gate return; 1183*7c478bd9Sstevel@tonic-gate } 1184*7c478bd9Sstevel@tonic-gate last = rindex(name, '/'); 1185*7c478bd9Sstevel@tonic-gate if (last == 0) 1186*7c478bd9Sstevel@tonic-gate last = name; 1187*7c478bd9Sstevel@tonic-gate else 1188*7c478bd9Sstevel@tonic-gate last++; 1189*7c478bd9Sstevel@tonic-gate if (pflag) { 1190*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "T%ld 0 %ld 0\n", 1191*7c478bd9Sstevel@tonic-gate statp->st_mtime, statp->st_atime); 1192*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, path, strlen(path)); 1193*7c478bd9Sstevel@tonic-gate if (response() < 0) { 1194*7c478bd9Sstevel@tonic-gate (void) closedir(d); 1195*7c478bd9Sstevel@tonic-gate return; 1196*7c478bd9Sstevel@tonic-gate } 1197*7c478bd9Sstevel@tonic-gate } 1198*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "D%04o %d %s\n", 1199*7c478bd9Sstevel@tonic-gate (uint_t)(statp->st_mode & 07777), 0, last); 1200*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, path, strlen(path)); 1201*7c478bd9Sstevel@tonic-gate 1202*7c478bd9Sstevel@tonic-gate /* acl support for directory */ 1203*7c478bd9Sstevel@tonic-gate if (aclflag) { 1204*7c478bd9Sstevel@tonic-gate /* get acl from f and send it over */ 1205*7c478bd9Sstevel@tonic-gate if (sendacl(d->dd_fd) == ACL_FAIL) { 1206*7c478bd9Sstevel@tonic-gate (void) closedir(d); 1207*7c478bd9Sstevel@tonic-gate return; 1208*7c478bd9Sstevel@tonic-gate } 1209*7c478bd9Sstevel@tonic-gate } 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate if (response() < 0) { 1212*7c478bd9Sstevel@tonic-gate (void) closedir(d); 1213*7c478bd9Sstevel@tonic-gate return; 1214*7c478bd9Sstevel@tonic-gate } 1215*7c478bd9Sstevel@tonic-gate 1216*7c478bd9Sstevel@tonic-gate while (dp = readdir(d)) { 1217*7c478bd9Sstevel@tonic-gate if (dp->d_ino == 0) 1218*7c478bd9Sstevel@tonic-gate continue; 1219*7c478bd9Sstevel@tonic-gate if ((strcmp(dp->d_name, ".") == 0) || 1220*7c478bd9Sstevel@tonic-gate (strcmp(dp->d_name, "..") == 0)) 1221*7c478bd9Sstevel@tonic-gate continue; 1222*7c478bd9Sstevel@tonic-gate if ((uint_t)strlen(name) + 1 + strlen(dp->d_name) >= 1223*7c478bd9Sstevel@tonic-gate MAXPATHLEN - 1) { 1224*7c478bd9Sstevel@tonic-gate error("%s/%s: name too long.\n", name, dp->d_name); 1225*7c478bd9Sstevel@tonic-gate continue; 1226*7c478bd9Sstevel@tonic-gate } 1227*7c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%s", 1228*7c478bd9Sstevel@tonic-gate name, dp->d_name); 1229*7c478bd9Sstevel@tonic-gate vect[0] = path; 1230*7c478bd9Sstevel@tonic-gate source(1, vect); 1231*7c478bd9Sstevel@tonic-gate } 1232*7c478bd9Sstevel@tonic-gate (void) closedir(d); 1233*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "E\n", 2); 1234*7c478bd9Sstevel@tonic-gate (void) response(); 1235*7c478bd9Sstevel@tonic-gate } 1236*7c478bd9Sstevel@tonic-gate 1237*7c478bd9Sstevel@tonic-gate static int 1238*7c478bd9Sstevel@tonic-gate response(void) 1239*7c478bd9Sstevel@tonic-gate { 1240*7c478bd9Sstevel@tonic-gate register char *cp; 1241*7c478bd9Sstevel@tonic-gate char ch, resp, rbuf[RCP_BUFSIZE]; 1242*7c478bd9Sstevel@tonic-gate 1243*7c478bd9Sstevel@tonic-gate if (desrcpread(rem, &resp, 1) != 1) 1244*7c478bd9Sstevel@tonic-gate lostconn(); 1245*7c478bd9Sstevel@tonic-gate cp = rbuf; 1246*7c478bd9Sstevel@tonic-gate switch (resp) { 1247*7c478bd9Sstevel@tonic-gate case 0: /* ok */ 1248*7c478bd9Sstevel@tonic-gate return (0); 1249*7c478bd9Sstevel@tonic-gate default: 1250*7c478bd9Sstevel@tonic-gate *cp++ = resp; 1251*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1252*7c478bd9Sstevel@tonic-gate case 1: /* error, followed by err msg */ 1253*7c478bd9Sstevel@tonic-gate case 2: /* fatal error, "" */ 1254*7c478bd9Sstevel@tonic-gate do { 1255*7c478bd9Sstevel@tonic-gate if (desrcpread(rem, &ch, sizeof (ch)) != sizeof (ch)) 1256*7c478bd9Sstevel@tonic-gate lostconn(); 1257*7c478bd9Sstevel@tonic-gate *cp++ = ch; 1258*7c478bd9Sstevel@tonic-gate } while (cp < &rbuf[RCP_BUFSIZE] && ch != '\n'); 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate if (!iamremote) 1261*7c478bd9Sstevel@tonic-gate (void) write(STDERR_FILENO, rbuf, cp - rbuf); 1262*7c478bd9Sstevel@tonic-gate ++errs; 1263*7c478bd9Sstevel@tonic-gate if (resp == 1) 1264*7c478bd9Sstevel@tonic-gate return (-1); 1265*7c478bd9Sstevel@tonic-gate exit(1); 1266*7c478bd9Sstevel@tonic-gate } 1267*7c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 1268*7c478bd9Sstevel@tonic-gate } 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate static void 1271*7c478bd9Sstevel@tonic-gate lostconn(void) 1272*7c478bd9Sstevel@tonic-gate { 1273*7c478bd9Sstevel@tonic-gate if (!iamremote) 1274*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "rcp: lost connection\n"); 1275*7c478bd9Sstevel@tonic-gate exit(1); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate 1279*7c478bd9Sstevel@tonic-gate static void 1280*7c478bd9Sstevel@tonic-gate sink(int argc, char *argv[]) 1281*7c478bd9Sstevel@tonic-gate { 1282*7c478bd9Sstevel@tonic-gate char *cp; 1283*7c478bd9Sstevel@tonic-gate static BUF buffer; 1284*7c478bd9Sstevel@tonic-gate struct stat stb; 1285*7c478bd9Sstevel@tonic-gate struct timeval tv[2]; 1286*7c478bd9Sstevel@tonic-gate BUF *bp; 1287*7c478bd9Sstevel@tonic-gate off_t i, j; 1288*7c478bd9Sstevel@tonic-gate char ch, *targ, *why; 1289*7c478bd9Sstevel@tonic-gate int amt, count, exists, first, mask, mode; 1290*7c478bd9Sstevel@tonic-gate off_t size; 1291*7c478bd9Sstevel@tonic-gate int ofd, setimes, targisdir, wrerr; 1292*7c478bd9Sstevel@tonic-gate char *np, *vect[1], buf[RCP_BUFSIZE]; 1293*7c478bd9Sstevel@tonic-gate char *namebuf = NULL; 1294*7c478bd9Sstevel@tonic-gate size_t namebuf_sz = 0; 1295*7c478bd9Sstevel@tonic-gate size_t need; 1296*7c478bd9Sstevel@tonic-gate 1297*7c478bd9Sstevel@tonic-gate #define atime tv[0] 1298*7c478bd9Sstevel@tonic-gate #define mtime tv[1] 1299*7c478bd9Sstevel@tonic-gate #define SCREWUP(str) { why = str; goto screwup; } 1300*7c478bd9Sstevel@tonic-gate 1301*7c478bd9Sstevel@tonic-gate setimes = targisdir = 0; 1302*7c478bd9Sstevel@tonic-gate mask = umask(0); 1303*7c478bd9Sstevel@tonic-gate if (!pflag) 1304*7c478bd9Sstevel@tonic-gate (void) umask(mask); 1305*7c478bd9Sstevel@tonic-gate if (argc != 1) { 1306*7c478bd9Sstevel@tonic-gate error("rcp: ambiguous target\n"); 1307*7c478bd9Sstevel@tonic-gate exit(1); 1308*7c478bd9Sstevel@tonic-gate } 1309*7c478bd9Sstevel@tonic-gate targ = *argv; 1310*7c478bd9Sstevel@tonic-gate if (targetshouldbedirectory) 1311*7c478bd9Sstevel@tonic-gate verifydir(targ); 1312*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1313*7c478bd9Sstevel@tonic-gate 1314*7c478bd9Sstevel@tonic-gate if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 1315*7c478bd9Sstevel@tonic-gate targisdir = 1; 1316*7c478bd9Sstevel@tonic-gate for (first = 1; ; first = 0) { 1317*7c478bd9Sstevel@tonic-gate cp = buf; 1318*7c478bd9Sstevel@tonic-gate if (desrcpread(rem, cp, 1) <= 0) { 1319*7c478bd9Sstevel@tonic-gate if (namebuf != NULL) 1320*7c478bd9Sstevel@tonic-gate free(namebuf); 1321*7c478bd9Sstevel@tonic-gate return; 1322*7c478bd9Sstevel@tonic-gate } 1323*7c478bd9Sstevel@tonic-gate 1324*7c478bd9Sstevel@tonic-gate if (*cp++ == '\n') 1325*7c478bd9Sstevel@tonic-gate SCREWUP("unexpected <newline>"); 1326*7c478bd9Sstevel@tonic-gate do { 1327*7c478bd9Sstevel@tonic-gate if (desrcpread(rem, &ch, sizeof (ch)) != sizeof (ch)) 1328*7c478bd9Sstevel@tonic-gate SCREWUP("lost connection"); 1329*7c478bd9Sstevel@tonic-gate *cp++ = ch; 1330*7c478bd9Sstevel@tonic-gate } while (cp < &buf[RCP_BUFSIZE - 1] && ch != '\n'); 1331*7c478bd9Sstevel@tonic-gate *cp = 0; 1332*7c478bd9Sstevel@tonic-gate 1333*7c478bd9Sstevel@tonic-gate if (buf[0] == '\01' || buf[0] == '\02') { 1334*7c478bd9Sstevel@tonic-gate if (iamremote == 0) 1335*7c478bd9Sstevel@tonic-gate (void) write(STDERR_FILENO, buf + 1, 1336*7c478bd9Sstevel@tonic-gate strlen(buf + 1)); 1337*7c478bd9Sstevel@tonic-gate if (buf[0] == '\02') 1338*7c478bd9Sstevel@tonic-gate exit(1); 1339*7c478bd9Sstevel@tonic-gate errs++; 1340*7c478bd9Sstevel@tonic-gate continue; 1341*7c478bd9Sstevel@tonic-gate } 1342*7c478bd9Sstevel@tonic-gate if (buf[0] == 'E') { 1343*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1344*7c478bd9Sstevel@tonic-gate if (namebuf != NULL) 1345*7c478bd9Sstevel@tonic-gate free(namebuf); 1346*7c478bd9Sstevel@tonic-gate return; 1347*7c478bd9Sstevel@tonic-gate } 1348*7c478bd9Sstevel@tonic-gate 1349*7c478bd9Sstevel@tonic-gate if (ch == '\n') 1350*7c478bd9Sstevel@tonic-gate *--cp = 0; 1351*7c478bd9Sstevel@tonic-gate cp = buf; 1352*7c478bd9Sstevel@tonic-gate if (*cp == 'T') { 1353*7c478bd9Sstevel@tonic-gate setimes++; 1354*7c478bd9Sstevel@tonic-gate cp++; 1355*7c478bd9Sstevel@tonic-gate mtime.tv_sec = strtol(cp, &cp, 0); 1356*7c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 1357*7c478bd9Sstevel@tonic-gate SCREWUP("mtime.sec not delimited"); 1358*7c478bd9Sstevel@tonic-gate mtime.tv_usec = strtol(cp, &cp, 0); 1359*7c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 1360*7c478bd9Sstevel@tonic-gate SCREWUP("mtime.usec not delimited"); 1361*7c478bd9Sstevel@tonic-gate atime.tv_sec = strtol(cp, &cp, 0); 1362*7c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 1363*7c478bd9Sstevel@tonic-gate SCREWUP("atime.sec not delimited"); 1364*7c478bd9Sstevel@tonic-gate atime.tv_usec = strtol(cp, &cp, 0); 1365*7c478bd9Sstevel@tonic-gate if (*cp++ != '\0') 1366*7c478bd9Sstevel@tonic-gate SCREWUP("atime.usec not delimited"); 1367*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1368*7c478bd9Sstevel@tonic-gate continue; 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate if (*cp != 'C' && *cp != 'D') { 1371*7c478bd9Sstevel@tonic-gate /* 1372*7c478bd9Sstevel@tonic-gate * Check for the case "rcp remote:foo\* local:bar". 1373*7c478bd9Sstevel@tonic-gate * In this case, the line "No match." can be returned 1374*7c478bd9Sstevel@tonic-gate * by the shell before the rcp command on the remote is 1375*7c478bd9Sstevel@tonic-gate * executed so the ^Aerror_message convention isn't 1376*7c478bd9Sstevel@tonic-gate * followed. 1377*7c478bd9Sstevel@tonic-gate */ 1378*7c478bd9Sstevel@tonic-gate if (first) { 1379*7c478bd9Sstevel@tonic-gate error("%s\n", cp); 1380*7c478bd9Sstevel@tonic-gate exit(1); 1381*7c478bd9Sstevel@tonic-gate } 1382*7c478bd9Sstevel@tonic-gate SCREWUP("expected control record"); 1383*7c478bd9Sstevel@tonic-gate } 1384*7c478bd9Sstevel@tonic-gate mode = 0; 1385*7c478bd9Sstevel@tonic-gate for (++cp; cp < buf + 5; cp++) { 1386*7c478bd9Sstevel@tonic-gate if (*cp < '0' || *cp > '7') 1387*7c478bd9Sstevel@tonic-gate SCREWUP("bad mode"); 1388*7c478bd9Sstevel@tonic-gate mode = (mode << 3) | (*cp - '0'); 1389*7c478bd9Sstevel@tonic-gate } 1390*7c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 1391*7c478bd9Sstevel@tonic-gate SCREWUP("mode not delimited"); 1392*7c478bd9Sstevel@tonic-gate size = 0; 1393*7c478bd9Sstevel@tonic-gate while (isdigit(*cp)) 1394*7c478bd9Sstevel@tonic-gate size = size * 10 + (*cp++ - '0'); 1395*7c478bd9Sstevel@tonic-gate if (*cp++ != ' ') 1396*7c478bd9Sstevel@tonic-gate SCREWUP("size not delimited"); 1397*7c478bd9Sstevel@tonic-gate if (targisdir) { 1398*7c478bd9Sstevel@tonic-gate need = strlen(targ) + sizeof ("/") + strlen(cp); 1399*7c478bd9Sstevel@tonic-gate if (need > namebuf_sz) { 1400*7c478bd9Sstevel@tonic-gate if ((namebuf = realloc(namebuf, need)) == NULL) { 1401*7c478bd9Sstevel@tonic-gate error("rcp: out of memory\n"); 1402*7c478bd9Sstevel@tonic-gate exit(1); 1403*7c478bd9Sstevel@tonic-gate } 1404*7c478bd9Sstevel@tonic-gate namebuf_sz = need; 1405*7c478bd9Sstevel@tonic-gate } 1406*7c478bd9Sstevel@tonic-gate (void) snprintf(namebuf, need, "%s%s%s", targ, 1407*7c478bd9Sstevel@tonic-gate *targ ? "/" : "", cp); 1408*7c478bd9Sstevel@tonic-gate np = namebuf; 1409*7c478bd9Sstevel@tonic-gate } else { 1410*7c478bd9Sstevel@tonic-gate np = targ; 1411*7c478bd9Sstevel@tonic-gate } 1412*7c478bd9Sstevel@tonic-gate 1413*7c478bd9Sstevel@tonic-gate exists = stat(np, &stb) == 0; 1414*7c478bd9Sstevel@tonic-gate if (buf[0] == 'D') { 1415*7c478bd9Sstevel@tonic-gate if (exists) { 1416*7c478bd9Sstevel@tonic-gate if ((stb.st_mode&S_IFMT) != S_IFDIR) { 1417*7c478bd9Sstevel@tonic-gate if (aclflag) { 1418*7c478bd9Sstevel@tonic-gate /* 1419*7c478bd9Sstevel@tonic-gate * consume acl in the pipe 1420*7c478bd9Sstevel@tonic-gate * fd = -1 to indicate the 1421*7c478bd9Sstevel@tonic-gate * special case 1422*7c478bd9Sstevel@tonic-gate */ 1423*7c478bd9Sstevel@tonic-gate if (recvacl(-1, exists, pflag) 1424*7c478bd9Sstevel@tonic-gate == ACL_FAIL) { 1425*7c478bd9Sstevel@tonic-gate goto bad; 1426*7c478bd9Sstevel@tonic-gate } 1427*7c478bd9Sstevel@tonic-gate } 1428*7c478bd9Sstevel@tonic-gate errno = ENOTDIR; 1429*7c478bd9Sstevel@tonic-gate goto bad; 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate if (pflag) 1432*7c478bd9Sstevel@tonic-gate (void) chmod(np, mode); 1433*7c478bd9Sstevel@tonic-gate } else if (mkdir(np, mode) < 0) { 1434*7c478bd9Sstevel@tonic-gate if (aclflag) { 1435*7c478bd9Sstevel@tonic-gate /* consume acl in the pipe */ 1436*7c478bd9Sstevel@tonic-gate (void) recvacl(-1, exists, pflag); 1437*7c478bd9Sstevel@tonic-gate } 1438*7c478bd9Sstevel@tonic-gate goto bad; 1439*7c478bd9Sstevel@tonic-gate } 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate /* acl support for directories */ 1442*7c478bd9Sstevel@tonic-gate if (aclflag) { 1443*7c478bd9Sstevel@tonic-gate int dfd; 1444*7c478bd9Sstevel@tonic-gate 1445*7c478bd9Sstevel@tonic-gate if ((dfd = open(np, O_RDONLY)) == -1) 1446*7c478bd9Sstevel@tonic-gate goto bad; 1447*7c478bd9Sstevel@tonic-gate 1448*7c478bd9Sstevel@tonic-gate /* get acl and set it to ofd */ 1449*7c478bd9Sstevel@tonic-gate if (recvacl(dfd, exists, pflag) == ACL_FAIL) { 1450*7c478bd9Sstevel@tonic-gate (void) close(dfd); 1451*7c478bd9Sstevel@tonic-gate if (!exists) 1452*7c478bd9Sstevel@tonic-gate (void) rmdir(np); 1453*7c478bd9Sstevel@tonic-gate goto bad; 1454*7c478bd9Sstevel@tonic-gate } 1455*7c478bd9Sstevel@tonic-gate (void) close(dfd); 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate 1458*7c478bd9Sstevel@tonic-gate vect[0] = np; 1459*7c478bd9Sstevel@tonic-gate sink(1, vect); 1460*7c478bd9Sstevel@tonic-gate if (setimes) { 1461*7c478bd9Sstevel@tonic-gate setimes = 0; 1462*7c478bd9Sstevel@tonic-gate if (utimes(np, tv) < 0) 1463*7c478bd9Sstevel@tonic-gate error("rcp: can't set times on %s: %s\n", 1464*7c478bd9Sstevel@tonic-gate np, strerror(errno)); 1465*7c478bd9Sstevel@tonic-gate } 1466*7c478bd9Sstevel@tonic-gate continue; 1467*7c478bd9Sstevel@tonic-gate } 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 1470*7c478bd9Sstevel@tonic-gate bad: 1471*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", np, strerror(errno)); 1472*7c478bd9Sstevel@tonic-gate continue; 1473*7c478bd9Sstevel@tonic-gate } 1474*7c478bd9Sstevel@tonic-gate 1475*7c478bd9Sstevel@tonic-gate /* 1476*7c478bd9Sstevel@tonic-gate * If the output file exists we have to force zflag off 1477*7c478bd9Sstevel@tonic-gate * to avoid erroneously seeking past old data. 1478*7c478bd9Sstevel@tonic-gate */ 1479*7c478bd9Sstevel@tonic-gate zopen(ofd, zflag && !exists); 1480*7c478bd9Sstevel@tonic-gate 1481*7c478bd9Sstevel@tonic-gate if (exists && pflag) 1482*7c478bd9Sstevel@tonic-gate (void) fchmod(ofd, mode); 1483*7c478bd9Sstevel@tonic-gate 1484*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1485*7c478bd9Sstevel@tonic-gate 1486*7c478bd9Sstevel@tonic-gate /* 1487*7c478bd9Sstevel@tonic-gate * ACL support: receiving 1488*7c478bd9Sstevel@tonic-gate */ 1489*7c478bd9Sstevel@tonic-gate if (aclflag) { 1490*7c478bd9Sstevel@tonic-gate /* get acl and set it to ofd */ 1491*7c478bd9Sstevel@tonic-gate if (recvacl(ofd, exists, pflag) == ACL_FAIL) { 1492*7c478bd9Sstevel@tonic-gate (void) close(ofd); 1493*7c478bd9Sstevel@tonic-gate if (!exists) 1494*7c478bd9Sstevel@tonic-gate (void) unlink(np); 1495*7c478bd9Sstevel@tonic-gate continue; 1496*7c478bd9Sstevel@tonic-gate } 1497*7c478bd9Sstevel@tonic-gate } 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate if ((bp = allocbuf(&buffer, ofd, RCP_BUFSIZE)) == 0) { 1500*7c478bd9Sstevel@tonic-gate (void) close(ofd); 1501*7c478bd9Sstevel@tonic-gate continue; 1502*7c478bd9Sstevel@tonic-gate } 1503*7c478bd9Sstevel@tonic-gate cp = bp->buf; 1504*7c478bd9Sstevel@tonic-gate count = 0; 1505*7c478bd9Sstevel@tonic-gate wrerr = 0; 1506*7c478bd9Sstevel@tonic-gate for (i = 0; i < size; i += RCP_BUFSIZE) { 1507*7c478bd9Sstevel@tonic-gate amt = RCP_BUFSIZE; 1508*7c478bd9Sstevel@tonic-gate if (i + amt > size) 1509*7c478bd9Sstevel@tonic-gate amt = size - i; 1510*7c478bd9Sstevel@tonic-gate count += amt; 1511*7c478bd9Sstevel@tonic-gate do { 1512*7c478bd9Sstevel@tonic-gate j = desrcpread(rem, cp, amt); 1513*7c478bd9Sstevel@tonic-gate if (j <= 0) { 1514*7c478bd9Sstevel@tonic-gate int sverrno = errno; 1515*7c478bd9Sstevel@tonic-gate 1516*7c478bd9Sstevel@tonic-gate /* 1517*7c478bd9Sstevel@tonic-gate * Connection to supplier lost. 1518*7c478bd9Sstevel@tonic-gate * Truncate file to correspond 1519*7c478bd9Sstevel@tonic-gate * to amount already transferred. 1520*7c478bd9Sstevel@tonic-gate * 1521*7c478bd9Sstevel@tonic-gate * Note that we must call ftruncate() 1522*7c478bd9Sstevel@tonic-gate * before any call to error() (which 1523*7c478bd9Sstevel@tonic-gate * might result in a SIGPIPE and 1524*7c478bd9Sstevel@tonic-gate * sudden death before we have a chance 1525*7c478bd9Sstevel@tonic-gate * to correct the file's size). 1526*7c478bd9Sstevel@tonic-gate */ 1527*7c478bd9Sstevel@tonic-gate size = lseek(ofd, 0, SEEK_CUR); 1528*7c478bd9Sstevel@tonic-gate if ((ftruncate(ofd, size) == -1) && 1529*7c478bd9Sstevel@tonic-gate (errno != EINVAL) && 1530*7c478bd9Sstevel@tonic-gate (errno != EACCES)) 1531*7c478bd9Sstevel@tonic-gate #define TRUNCERR "rcp: can't truncate %s: %s\n" 1532*7c478bd9Sstevel@tonic-gate error(TRUNCERR, np, 1533*7c478bd9Sstevel@tonic-gate strerror(errno)); 1534*7c478bd9Sstevel@tonic-gate error("rcp: %s\n", 1535*7c478bd9Sstevel@tonic-gate j ? strerror(sverrno) : 1536*7c478bd9Sstevel@tonic-gate "dropped connection"); 1537*7c478bd9Sstevel@tonic-gate (void) close(ofd); 1538*7c478bd9Sstevel@tonic-gate exit(1); 1539*7c478bd9Sstevel@tonic-gate } 1540*7c478bd9Sstevel@tonic-gate amt -= j; 1541*7c478bd9Sstevel@tonic-gate cp += j; 1542*7c478bd9Sstevel@tonic-gate } while (amt > 0); 1543*7c478bd9Sstevel@tonic-gate if (count == bp->cnt) { 1544*7c478bd9Sstevel@tonic-gate cp = bp->buf; 1545*7c478bd9Sstevel@tonic-gate if (wrerr == 0 && 1546*7c478bd9Sstevel@tonic-gate zwrite(ofd, cp, count) < 0) 1547*7c478bd9Sstevel@tonic-gate wrerr++; 1548*7c478bd9Sstevel@tonic-gate count = 0; 1549*7c478bd9Sstevel@tonic-gate } 1550*7c478bd9Sstevel@tonic-gate } 1551*7c478bd9Sstevel@tonic-gate if (count != 0 && wrerr == 0 && 1552*7c478bd9Sstevel@tonic-gate zwrite(ofd, bp->buf, count) < 0) 1553*7c478bd9Sstevel@tonic-gate wrerr++; 1554*7c478bd9Sstevel@tonic-gate if (zclose(ofd) < 0) 1555*7c478bd9Sstevel@tonic-gate wrerr++; 1556*7c478bd9Sstevel@tonic-gate 1557*7c478bd9Sstevel@tonic-gate 1558*7c478bd9Sstevel@tonic-gate if ((ftruncate(ofd, size) == -1) && (errno != EINVAL) && 1559*7c478bd9Sstevel@tonic-gate (errno != EACCES)) { 1560*7c478bd9Sstevel@tonic-gate error(TRUNCERR, np, strerror(errno)); 1561*7c478bd9Sstevel@tonic-gate } 1562*7c478bd9Sstevel@tonic-gate (void) close(ofd); 1563*7c478bd9Sstevel@tonic-gate (void) response(); 1564*7c478bd9Sstevel@tonic-gate if (setimes) { 1565*7c478bd9Sstevel@tonic-gate setimes = 0; 1566*7c478bd9Sstevel@tonic-gate if (utimes(np, tv) < 0) 1567*7c478bd9Sstevel@tonic-gate error("rcp: can't set times on %s: %s\n", 1568*7c478bd9Sstevel@tonic-gate np, strerror(errno)); 1569*7c478bd9Sstevel@tonic-gate } 1570*7c478bd9Sstevel@tonic-gate if (wrerr) 1571*7c478bd9Sstevel@tonic-gate error("rcp: %s: %s\n", np, strerror(errno)); 1572*7c478bd9Sstevel@tonic-gate else 1573*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1574*7c478bd9Sstevel@tonic-gate } 1575*7c478bd9Sstevel@tonic-gate screwup: 1576*7c478bd9Sstevel@tonic-gate error("rcp: protocol screwup: %s\n", why); 1577*7c478bd9Sstevel@tonic-gate exit(1); 1578*7c478bd9Sstevel@tonic-gate } 1579*7c478bd9Sstevel@tonic-gate 1580*7c478bd9Sstevel@tonic-gate #ifndef roundup 1581*7c478bd9Sstevel@tonic-gate #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 1582*7c478bd9Sstevel@tonic-gate #endif /* !roundup */ 1583*7c478bd9Sstevel@tonic-gate 1584*7c478bd9Sstevel@tonic-gate static BUF * 1585*7c478bd9Sstevel@tonic-gate allocbuf(BUF *bp, int fd, int blksize) 1586*7c478bd9Sstevel@tonic-gate { 1587*7c478bd9Sstevel@tonic-gate struct stat stb; 1588*7c478bd9Sstevel@tonic-gate int size; 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate if (fstat(fd, &stb) < 0) { 1591*7c478bd9Sstevel@tonic-gate error("rcp: fstat: %s\n", strerror(errno)); 1592*7c478bd9Sstevel@tonic-gate return (0); 1593*7c478bd9Sstevel@tonic-gate } 1594*7c478bd9Sstevel@tonic-gate size = roundup(stb.st_blksize, blksize); 1595*7c478bd9Sstevel@tonic-gate if (size == 0) 1596*7c478bd9Sstevel@tonic-gate size = blksize; 1597*7c478bd9Sstevel@tonic-gate if (bp->cnt < size) { 1598*7c478bd9Sstevel@tonic-gate if (bp->buf != 0) 1599*7c478bd9Sstevel@tonic-gate free(bp->buf); 1600*7c478bd9Sstevel@tonic-gate bp->buf = (char *)malloc((uint_t)size); 1601*7c478bd9Sstevel@tonic-gate if (!bp->buf) { 1602*7c478bd9Sstevel@tonic-gate error("rcp: malloc: out of memory\n"); 1603*7c478bd9Sstevel@tonic-gate return (0); 1604*7c478bd9Sstevel@tonic-gate } 1605*7c478bd9Sstevel@tonic-gate } 1606*7c478bd9Sstevel@tonic-gate bp->cnt = size; 1607*7c478bd9Sstevel@tonic-gate return (bp); 1608*7c478bd9Sstevel@tonic-gate } 1609*7c478bd9Sstevel@tonic-gate 1610*7c478bd9Sstevel@tonic-gate static void 1611*7c478bd9Sstevel@tonic-gate usage(void) 1612*7c478bd9Sstevel@tonic-gate { 1613*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, "%s: \t%s\t%s", gettext("Usage"), 1614*7c478bd9Sstevel@tonic-gate gettext("\trcp [-p] [-a] [-x] [-k realm] [-PN / -PO] " 1615*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1616*7c478bd9Sstevel@tonic-gate "[-D port] " 1617*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1618*7c478bd9Sstevel@tonic-gate "f1 f2; or:\n"), 1619*7c478bd9Sstevel@tonic-gate gettext("\trcp [-r] [-p] [-a] [-x] " 1620*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 1621*7c478bd9Sstevel@tonic-gate "[-D port] " 1622*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 1623*7c478bd9Sstevel@tonic-gate "[-k realm] [-PN / -PO] f1...fn d2\n")); 1624*7c478bd9Sstevel@tonic-gate exit(1); 1625*7c478bd9Sstevel@tonic-gate } 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate 1628*7c478bd9Sstevel@tonic-gate /* 1629*7c478bd9Sstevel@tonic-gate * sparse file support 1630*7c478bd9Sstevel@tonic-gate */ 1631*7c478bd9Sstevel@tonic-gate 1632*7c478bd9Sstevel@tonic-gate static off_t zbsize; 1633*7c478bd9Sstevel@tonic-gate static off_t zlastseek; 1634*7c478bd9Sstevel@tonic-gate 1635*7c478bd9Sstevel@tonic-gate /* is it ok to try to create holes? */ 1636*7c478bd9Sstevel@tonic-gate static void 1637*7c478bd9Sstevel@tonic-gate zopen(int fd, int flag) 1638*7c478bd9Sstevel@tonic-gate { 1639*7c478bd9Sstevel@tonic-gate struct stat st; 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate zbsize = 0; 1642*7c478bd9Sstevel@tonic-gate zlastseek = 0; 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate if (flag && 1645*7c478bd9Sstevel@tonic-gate fstat(fd, &st) == 0 && 1646*7c478bd9Sstevel@tonic-gate (st.st_mode & S_IFMT) == S_IFREG) 1647*7c478bd9Sstevel@tonic-gate zbsize = st.st_blksize; 1648*7c478bd9Sstevel@tonic-gate } 1649*7c478bd9Sstevel@tonic-gate 1650*7c478bd9Sstevel@tonic-gate /* write and/or seek */ 1651*7c478bd9Sstevel@tonic-gate static int 1652*7c478bd9Sstevel@tonic-gate zwrite(int fd, char *buf, int nbytes) 1653*7c478bd9Sstevel@tonic-gate { 1654*7c478bd9Sstevel@tonic-gate off_t block = zbsize ? zbsize : nbytes; 1655*7c478bd9Sstevel@tonic-gate 1656*7c478bd9Sstevel@tonic-gate do { 1657*7c478bd9Sstevel@tonic-gate if (block > nbytes) 1658*7c478bd9Sstevel@tonic-gate block = nbytes; 1659*7c478bd9Sstevel@tonic-gate nbytes -= block; 1660*7c478bd9Sstevel@tonic-gate 1661*7c478bd9Sstevel@tonic-gate if (!zbsize || notzero(buf, block)) { 1662*7c478bd9Sstevel@tonic-gate register int n, count = block; 1663*7c478bd9Sstevel@tonic-gate 1664*7c478bd9Sstevel@tonic-gate do { 1665*7c478bd9Sstevel@tonic-gate if ((n = write(fd, buf, count)) < 0) 1666*7c478bd9Sstevel@tonic-gate return (-1); 1667*7c478bd9Sstevel@tonic-gate buf += n; 1668*7c478bd9Sstevel@tonic-gate } while ((count -= n) > 0); 1669*7c478bd9Sstevel@tonic-gate zlastseek = 0; 1670*7c478bd9Sstevel@tonic-gate } else { 1671*7c478bd9Sstevel@tonic-gate if (lseek(fd, (off_t)block, SEEK_CUR) < 0) 1672*7c478bd9Sstevel@tonic-gate return (-1); 1673*7c478bd9Sstevel@tonic-gate buf += block; 1674*7c478bd9Sstevel@tonic-gate zlastseek = 1; 1675*7c478bd9Sstevel@tonic-gate } 1676*7c478bd9Sstevel@tonic-gate } while (nbytes > 0); 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate return (0); 1679*7c478bd9Sstevel@tonic-gate } 1680*7c478bd9Sstevel@tonic-gate 1681*7c478bd9Sstevel@tonic-gate /* write last byte of file if necessary */ 1682*7c478bd9Sstevel@tonic-gate static int 1683*7c478bd9Sstevel@tonic-gate zclose(int fd) 1684*7c478bd9Sstevel@tonic-gate { 1685*7c478bd9Sstevel@tonic-gate zbsize = 0; 1686*7c478bd9Sstevel@tonic-gate 1687*7c478bd9Sstevel@tonic-gate if (zlastseek && (lseek(fd, (off_t)-1, SEEK_CUR) < 0 || 1688*7c478bd9Sstevel@tonic-gate zwrite(fd, "", 1) < 0)) 1689*7c478bd9Sstevel@tonic-gate return (-1); 1690*7c478bd9Sstevel@tonic-gate else 1691*7c478bd9Sstevel@tonic-gate return (0); 1692*7c478bd9Sstevel@tonic-gate } 1693*7c478bd9Sstevel@tonic-gate 1694*7c478bd9Sstevel@tonic-gate /* return true if buffer is not all zeros */ 1695*7c478bd9Sstevel@tonic-gate static int 1696*7c478bd9Sstevel@tonic-gate notzero(char *p, int n) 1697*7c478bd9Sstevel@tonic-gate { 1698*7c478bd9Sstevel@tonic-gate register int result = 0; 1699*7c478bd9Sstevel@tonic-gate 1700*7c478bd9Sstevel@tonic-gate while ((int)p & 3 && --n >= 0) 1701*7c478bd9Sstevel@tonic-gate result |= *p++; 1702*7c478bd9Sstevel@tonic-gate 1703*7c478bd9Sstevel@tonic-gate while ((n -= 4 * sizeof (int)) >= 0) { 1704*7c478bd9Sstevel@tonic-gate /* LINTED */ 1705*7c478bd9Sstevel@tonic-gate result |= ((int *)p)[0]; 1706*7c478bd9Sstevel@tonic-gate /* LINTED */ 1707*7c478bd9Sstevel@tonic-gate result |= ((int *)p)[1]; 1708*7c478bd9Sstevel@tonic-gate /* LINTED */ 1709*7c478bd9Sstevel@tonic-gate result |= ((int *)p)[2]; 1710*7c478bd9Sstevel@tonic-gate /* LINTED */ 1711*7c478bd9Sstevel@tonic-gate result |= ((int *)p)[3]; 1712*7c478bd9Sstevel@tonic-gate if (result) 1713*7c478bd9Sstevel@tonic-gate return (result); 1714*7c478bd9Sstevel@tonic-gate p += 4 * sizeof (int); 1715*7c478bd9Sstevel@tonic-gate } 1716*7c478bd9Sstevel@tonic-gate n += 4 * sizeof (int); 1717*7c478bd9Sstevel@tonic-gate 1718*7c478bd9Sstevel@tonic-gate while (--n >= 0) 1719*7c478bd9Sstevel@tonic-gate result |= *p++; 1720*7c478bd9Sstevel@tonic-gate 1721*7c478bd9Sstevel@tonic-gate return (result); 1722*7c478bd9Sstevel@tonic-gate } 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate /* 1725*7c478bd9Sstevel@tonic-gate * New functions to support ACLs 1726*7c478bd9Sstevel@tonic-gate */ 1727*7c478bd9Sstevel@tonic-gate 1728*7c478bd9Sstevel@tonic-gate /* 1729*7c478bd9Sstevel@tonic-gate * Get acl from f and send it over. 1730*7c478bd9Sstevel@tonic-gate * ACL record includes acl entry count, acl text length, and acl text. 1731*7c478bd9Sstevel@tonic-gate */ 1732*7c478bd9Sstevel@tonic-gate static int 1733*7c478bd9Sstevel@tonic-gate sendacl(int f) 1734*7c478bd9Sstevel@tonic-gate { 1735*7c478bd9Sstevel@tonic-gate int aclcnt; 1736*7c478bd9Sstevel@tonic-gate aclent_t *aclbufp; 1737*7c478bd9Sstevel@tonic-gate int aclsize; 1738*7c478bd9Sstevel@tonic-gate char *acltext; 1739*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 1740*7c478bd9Sstevel@tonic-gate 1741*7c478bd9Sstevel@tonic-gate if ((aclcnt = facl(f, GETACLCNT, 0, NULL)) < 0) { 1742*7c478bd9Sstevel@tonic-gate error("can't get acl count \n"); 1743*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1744*7c478bd9Sstevel@tonic-gate } 1745*7c478bd9Sstevel@tonic-gate 1746*7c478bd9Sstevel@tonic-gate /* send the acl count over */ 1747*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "A%d\n", aclcnt); 1748*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 1749*7c478bd9Sstevel@tonic-gate 1750*7c478bd9Sstevel@tonic-gate /* only send acl when it is non-trivial */ 1751*7c478bd9Sstevel@tonic-gate if (aclcnt > MIN_ACL_ENTRIES) { 1752*7c478bd9Sstevel@tonic-gate aclsize = aclcnt * sizeof (aclent_t); 1753*7c478bd9Sstevel@tonic-gate if ((aclbufp = (aclent_t *)malloc(aclsize)) == NULL) { 1754*7c478bd9Sstevel@tonic-gate error("rcp: cant allocate memory: aclcnt %d\n", 1755*7c478bd9Sstevel@tonic-gate aclcnt); 1756*7c478bd9Sstevel@tonic-gate exit(1); 1757*7c478bd9Sstevel@tonic-gate } 1758*7c478bd9Sstevel@tonic-gate if (facl(f, GETACL, aclcnt, aclbufp) < 0) { 1759*7c478bd9Sstevel@tonic-gate error("rcp: failed to get acl\n"); 1760*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1761*7c478bd9Sstevel@tonic-gate } 1762*7c478bd9Sstevel@tonic-gate acltext = acltotext(aclbufp, aclcnt); 1763*7c478bd9Sstevel@tonic-gate if (acltext == NULL) { 1764*7c478bd9Sstevel@tonic-gate error("rcp: failed to convert to text\n"); 1765*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1766*7c478bd9Sstevel@tonic-gate } 1767*7c478bd9Sstevel@tonic-gate 1768*7c478bd9Sstevel@tonic-gate /* send ACLs over: send the length first */ 1769*7c478bd9Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "A%d\n", strlen(acltext)); 1770*7c478bd9Sstevel@tonic-gate 1771*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 1772*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, acltext, strlen(acltext)); 1773*7c478bd9Sstevel@tonic-gate free(acltext); 1774*7c478bd9Sstevel@tonic-gate free(aclbufp); 1775*7c478bd9Sstevel@tonic-gate if (response() < 0) 1776*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1777*7c478bd9Sstevel@tonic-gate 1778*7c478bd9Sstevel@tonic-gate } 1779*7c478bd9Sstevel@tonic-gate return (ACL_OK); 1780*7c478bd9Sstevel@tonic-gate } 1781*7c478bd9Sstevel@tonic-gate 1782*7c478bd9Sstevel@tonic-gate /* 1783*7c478bd9Sstevel@tonic-gate * Use this routine to get acl entry count and acl text size (in bytes) 1784*7c478bd9Sstevel@tonic-gate */ 1785*7c478bd9Sstevel@tonic-gate static int 1786*7c478bd9Sstevel@tonic-gate getaclinfo(int *cnt) 1787*7c478bd9Sstevel@tonic-gate { 1788*7c478bd9Sstevel@tonic-gate char buf[BUFSIZ]; 1789*7c478bd9Sstevel@tonic-gate char *cp; 1790*7c478bd9Sstevel@tonic-gate char ch; 1791*7c478bd9Sstevel@tonic-gate 1792*7c478bd9Sstevel@tonic-gate /* get acl count */ 1793*7c478bd9Sstevel@tonic-gate cp = buf; 1794*7c478bd9Sstevel@tonic-gate if (desrcpread(rem, cp, 1) <= 0) 1795*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1796*7c478bd9Sstevel@tonic-gate if (*cp++ != 'A') { 1797*7c478bd9Sstevel@tonic-gate error("rcp: expect an ACL record, but got %c\n", *cp); 1798*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1799*7c478bd9Sstevel@tonic-gate } 1800*7c478bd9Sstevel@tonic-gate do { 1801*7c478bd9Sstevel@tonic-gate if (desrcpread(rem, &ch, sizeof (ch)) != sizeof (ch)) { 1802*7c478bd9Sstevel@tonic-gate error("rcp: lost connection ..\n"); 1803*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate *cp++ = ch; 1806*7c478bd9Sstevel@tonic-gate } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 1807*7c478bd9Sstevel@tonic-gate if (ch != '\n') { 1808*7c478bd9Sstevel@tonic-gate error("rcp: ACL record corrupted \n"); 1809*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1810*7c478bd9Sstevel@tonic-gate } 1811*7c478bd9Sstevel@tonic-gate cp = &buf[1]; 1812*7c478bd9Sstevel@tonic-gate *cnt = strtol(cp, &cp, 0); 1813*7c478bd9Sstevel@tonic-gate if (*cp != '\n') { 1814*7c478bd9Sstevel@tonic-gate error("rcp: ACL record corrupted \n"); 1815*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1816*7c478bd9Sstevel@tonic-gate } 1817*7c478bd9Sstevel@tonic-gate return (ACL_OK); 1818*7c478bd9Sstevel@tonic-gate } 1819*7c478bd9Sstevel@tonic-gate 1820*7c478bd9Sstevel@tonic-gate 1821*7c478bd9Sstevel@tonic-gate /* 1822*7c478bd9Sstevel@tonic-gate * Receive acl from the pipe and set it to f 1823*7c478bd9Sstevel@tonic-gate */ 1824*7c478bd9Sstevel@tonic-gate static int 1825*7c478bd9Sstevel@tonic-gate recvacl(int f, int exists, int preserve) 1826*7c478bd9Sstevel@tonic-gate { 1827*7c478bd9Sstevel@tonic-gate int aclcnt; /* acl entry count */ 1828*7c478bd9Sstevel@tonic-gate int aclsize; /* acl text length */ 1829*7c478bd9Sstevel@tonic-gate int j; 1830*7c478bd9Sstevel@tonic-gate char *tp; 1831*7c478bd9Sstevel@tonic-gate char *acltext; /* external format */ 1832*7c478bd9Sstevel@tonic-gate aclent_t *aclbufp; /* internal format */ 1833*7c478bd9Sstevel@tonic-gate 1834*7c478bd9Sstevel@tonic-gate /* get acl count */ 1835*7c478bd9Sstevel@tonic-gate if (getaclinfo(&aclcnt) != ACL_OK) 1836*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate if (aclcnt > MIN_ACL_ENTRIES) { 1839*7c478bd9Sstevel@tonic-gate /* get acl text size */ 1840*7c478bd9Sstevel@tonic-gate if (getaclinfo(&aclsize) != ACL_OK) 1841*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1842*7c478bd9Sstevel@tonic-gate if ((acltext = malloc(aclsize + 1)) == NULL) { 1843*7c478bd9Sstevel@tonic-gate error("rcp: cant allocate memory: %d\n", aclsize); 1844*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1845*7c478bd9Sstevel@tonic-gate } 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate tp = acltext; 1848*7c478bd9Sstevel@tonic-gate do { 1849*7c478bd9Sstevel@tonic-gate j = desrcpread(rem, tp, aclsize); 1850*7c478bd9Sstevel@tonic-gate if (j <= 0) { 1851*7c478bd9Sstevel@tonic-gate error("rcp: %s\n", j ? strerror(errno) : 1852*7c478bd9Sstevel@tonic-gate "dropped connection"); 1853*7c478bd9Sstevel@tonic-gate exit(1); 1854*7c478bd9Sstevel@tonic-gate } 1855*7c478bd9Sstevel@tonic-gate aclsize -= j; 1856*7c478bd9Sstevel@tonic-gate tp += j; 1857*7c478bd9Sstevel@tonic-gate } while (aclsize > 0); 1858*7c478bd9Sstevel@tonic-gate *tp = '\0'; 1859*7c478bd9Sstevel@tonic-gate 1860*7c478bd9Sstevel@tonic-gate if (preserve || !exists) { 1861*7c478bd9Sstevel@tonic-gate aclbufp = aclfromtext(acltext, &aclcnt); 1862*7c478bd9Sstevel@tonic-gate if (aclbufp == NULL) { 1863*7c478bd9Sstevel@tonic-gate error("rcp: failed to parse acl\n"); 1864*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1865*7c478bd9Sstevel@tonic-gate } 1866*7c478bd9Sstevel@tonic-gate if (f != -1) { 1867*7c478bd9Sstevel@tonic-gate if (facl(f, SETACL, aclcnt, aclbufp) < 0) { 1868*7c478bd9Sstevel@tonic-gate error("rcp: failed to set acl\n"); 1869*7c478bd9Sstevel@tonic-gate return (ACL_FAIL); 1870*7c478bd9Sstevel@tonic-gate } 1871*7c478bd9Sstevel@tonic-gate } 1872*7c478bd9Sstevel@tonic-gate /* -1 means that just consume the data in the pipe */ 1873*7c478bd9Sstevel@tonic-gate free(aclbufp); 1874*7c478bd9Sstevel@tonic-gate } 1875*7c478bd9Sstevel@tonic-gate free(acltext); 1876*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, "", 1); 1877*7c478bd9Sstevel@tonic-gate } 1878*7c478bd9Sstevel@tonic-gate return (ACL_OK); 1879*7c478bd9Sstevel@tonic-gate } 1880*7c478bd9Sstevel@tonic-gate 1881*7c478bd9Sstevel@tonic-gate 1882*7c478bd9Sstevel@tonic-gate static char * 1883*7c478bd9Sstevel@tonic-gate search_char(unsigned char *cp, unsigned char chr) 1884*7c478bd9Sstevel@tonic-gate { 1885*7c478bd9Sstevel@tonic-gate int len; 1886*7c478bd9Sstevel@tonic-gate 1887*7c478bd9Sstevel@tonic-gate while (*cp) { 1888*7c478bd9Sstevel@tonic-gate if (*cp == chr) 1889*7c478bd9Sstevel@tonic-gate return ((char *)cp); 1890*7c478bd9Sstevel@tonic-gate if ((len = mblen((char *)cp, MB_CUR_MAX)) <= 0) 1891*7c478bd9Sstevel@tonic-gate len = 1; 1892*7c478bd9Sstevel@tonic-gate cp += len; 1893*7c478bd9Sstevel@tonic-gate } 1894*7c478bd9Sstevel@tonic-gate return (0); 1895*7c478bd9Sstevel@tonic-gate } 1896*7c478bd9Sstevel@tonic-gate 1897*7c478bd9Sstevel@tonic-gate 1898*7c478bd9Sstevel@tonic-gate static int 1899*7c478bd9Sstevel@tonic-gate desrcpread(int fd, char *buf, int len) 1900*7c478bd9Sstevel@tonic-gate { 1901*7c478bd9Sstevel@tonic-gate return ((int)desread(fd, buf, len, 0)); 1902*7c478bd9Sstevel@tonic-gate } 1903*7c478bd9Sstevel@tonic-gate 1904*7c478bd9Sstevel@tonic-gate static int 1905*7c478bd9Sstevel@tonic-gate desrcpwrite(int fd, char *buf, int len) 1906*7c478bd9Sstevel@tonic-gate { 1907*7c478bd9Sstevel@tonic-gate /* 1908*7c478bd9Sstevel@tonic-gate * Note that rcp depends on the same file descriptor being both 1909*7c478bd9Sstevel@tonic-gate * input and output to the remote side. This is bogus, especially 1910*7c478bd9Sstevel@tonic-gate * when rcp is being run by a rsh that pipes. Fix it here because 1911*7c478bd9Sstevel@tonic-gate * it would require significantly more work in other places. 1912*7c478bd9Sstevel@tonic-gate * --hartmans 1/96 1913*7c478bd9Sstevel@tonic-gate */ 1914*7c478bd9Sstevel@tonic-gate 1915*7c478bd9Sstevel@tonic-gate if (fd == 0) 1916*7c478bd9Sstevel@tonic-gate fd = 1; 1917*7c478bd9Sstevel@tonic-gate return ((int)deswrite(fd, buf, len, 0)); 1918*7c478bd9Sstevel@tonic-gate } 1919*7c478bd9Sstevel@tonic-gate 1920*7c478bd9Sstevel@tonic-gate static char ** 1921*7c478bd9Sstevel@tonic-gate save_argv(int argc, char **argv) 1922*7c478bd9Sstevel@tonic-gate { 1923*7c478bd9Sstevel@tonic-gate int i; 1924*7c478bd9Sstevel@tonic-gate 1925*7c478bd9Sstevel@tonic-gate char **local_argv = (char **)calloc((unsigned)argc + 1, 1926*7c478bd9Sstevel@tonic-gate (unsigned)sizeof (char *)); 1927*7c478bd9Sstevel@tonic-gate 1928*7c478bd9Sstevel@tonic-gate /* 1929*7c478bd9Sstevel@tonic-gate * allocate an extra pointer, so that it is initialized to NULL and 1930*7c478bd9Sstevel@tonic-gate * execv() will work 1931*7c478bd9Sstevel@tonic-gate */ 1932*7c478bd9Sstevel@tonic-gate for (i = 0; i < argc; i++) { 1933*7c478bd9Sstevel@tonic-gate local_argv[i] = strsave(argv[i]); 1934*7c478bd9Sstevel@tonic-gate } 1935*7c478bd9Sstevel@tonic-gate 1936*7c478bd9Sstevel@tonic-gate return (local_argv); 1937*7c478bd9Sstevel@tonic-gate } 1938*7c478bd9Sstevel@tonic-gate 1939*7c478bd9Sstevel@tonic-gate #define SIZEOF_INADDR sizeof (struct in_addr) 1940*7c478bd9Sstevel@tonic-gate 1941*7c478bd9Sstevel@tonic-gate static void 1942*7c478bd9Sstevel@tonic-gate answer_auth(char *config_file, char *ccache_file) 1943*7c478bd9Sstevel@tonic-gate { 1944*7c478bd9Sstevel@tonic-gate krb5_data pname_data, msg; 1945*7c478bd9Sstevel@tonic-gate krb5_creds creds, *new_creds; 1946*7c478bd9Sstevel@tonic-gate krb5_ccache cc; 1947*7c478bd9Sstevel@tonic-gate krb5_auth_context auth_context = NULL; 1948*7c478bd9Sstevel@tonic-gate 1949*7c478bd9Sstevel@tonic-gate if (config_file) { 1950*7c478bd9Sstevel@tonic-gate const char *filenames[2]; 1951*7c478bd9Sstevel@tonic-gate 1952*7c478bd9Sstevel@tonic-gate filenames[1] = NULL; 1953*7c478bd9Sstevel@tonic-gate filenames[0] = config_file; 1954*7c478bd9Sstevel@tonic-gate if (krb5_set_config_files(bsd_context, filenames)) 1955*7c478bd9Sstevel@tonic-gate exit(1); 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate (void) memset((char *)&creds, 0, sizeof (creds)); 1958*7c478bd9Sstevel@tonic-gate 1959*7c478bd9Sstevel@tonic-gate if (krb5_read_message(bsd_context, (krb5_pointer) &rem, &pname_data)) 1960*7c478bd9Sstevel@tonic-gate exit(1); 1961*7c478bd9Sstevel@tonic-gate 1962*7c478bd9Sstevel@tonic-gate if (krb5_read_message(bsd_context, (krb5_pointer) &rem, 1963*7c478bd9Sstevel@tonic-gate &creds.second_ticket)) 1964*7c478bd9Sstevel@tonic-gate exit(1); 1965*7c478bd9Sstevel@tonic-gate 1966*7c478bd9Sstevel@tonic-gate if (ccache_file == NULL) { 1967*7c478bd9Sstevel@tonic-gate if (krb5_cc_default(bsd_context, &cc)) 1968*7c478bd9Sstevel@tonic-gate exit(1); 1969*7c478bd9Sstevel@tonic-gate } else { 1970*7c478bd9Sstevel@tonic-gate if (krb5_cc_resolve(bsd_context, ccache_file, &cc)) 1971*7c478bd9Sstevel@tonic-gate exit(1); 1972*7c478bd9Sstevel@tonic-gate } 1973*7c478bd9Sstevel@tonic-gate 1974*7c478bd9Sstevel@tonic-gate if (krb5_cc_get_principal(bsd_context, cc, &creds.client)) 1975*7c478bd9Sstevel@tonic-gate exit(1); 1976*7c478bd9Sstevel@tonic-gate 1977*7c478bd9Sstevel@tonic-gate if (krb5_parse_name(bsd_context, pname_data.data, &creds.server)) 1978*7c478bd9Sstevel@tonic-gate exit(1); 1979*7c478bd9Sstevel@tonic-gate 1980*7c478bd9Sstevel@tonic-gate krb5_xfree(pname_data.data); 1981*7c478bd9Sstevel@tonic-gate if (krb5_get_credentials(bsd_context, KRB5_GC_USER_USER, cc, &creds, 1982*7c478bd9Sstevel@tonic-gate &new_creds)) 1983*7c478bd9Sstevel@tonic-gate exit(1); 1984*7c478bd9Sstevel@tonic-gate 1985*7c478bd9Sstevel@tonic-gate if (krb5_mk_req_extended(bsd_context, &auth_context, 1986*7c478bd9Sstevel@tonic-gate AP_OPTS_USE_SESSION_KEY, NULL, new_creds, &msg)) 1987*7c478bd9Sstevel@tonic-gate exit(1); 1988*7c478bd9Sstevel@tonic-gate 1989*7c478bd9Sstevel@tonic-gate if (krb5_write_message(bsd_context, (krb5_pointer) & rem, &msg)) { 1990*7c478bd9Sstevel@tonic-gate krb5_xfree(msg.data); 1991*7c478bd9Sstevel@tonic-gate exit(1); 1992*7c478bd9Sstevel@tonic-gate } 1993*7c478bd9Sstevel@tonic-gate /* setup eblock for des_read and write */ 1994*7c478bd9Sstevel@tonic-gate krb5_copy_keyblock(bsd_context, &new_creds->keyblock, &session_key); 1995*7c478bd9Sstevel@tonic-gate 1996*7c478bd9Sstevel@tonic-gate /* OK process key */ 1997*7c478bd9Sstevel@tonic-gate eblock.crypto_entry = session_key->enctype; 1998*7c478bd9Sstevel@tonic-gate eblock.key = (krb5_keyblock *)session_key; 1999*7c478bd9Sstevel@tonic-gate 2000*7c478bd9Sstevel@tonic-gate init_encrypt(encrypt_flag, bsd_context, KCMD_OLD_PROTOCOL, 2001*7c478bd9Sstevel@tonic-gate &desinbuf, &desoutbuf, CLIENT, &eblock); 2002*7c478bd9Sstevel@tonic-gate /* cleanup */ 2003*7c478bd9Sstevel@tonic-gate krb5_free_cred_contents(bsd_context, &creds); 2004*7c478bd9Sstevel@tonic-gate krb5_free_creds(bsd_context, new_creds); 2005*7c478bd9Sstevel@tonic-gate krb5_xfree(msg.data); 2006*7c478bd9Sstevel@tonic-gate } 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate 2009*7c478bd9Sstevel@tonic-gate static void 2010*7c478bd9Sstevel@tonic-gate try_normal_rcp(int cur_argc, char **cur_argv) 2011*7c478bd9Sstevel@tonic-gate { 2012*7c478bd9Sstevel@tonic-gate char *target; 2013*7c478bd9Sstevel@tonic-gate 2014*7c478bd9Sstevel@tonic-gate /* 2015*7c478bd9Sstevel@tonic-gate * Reset all KRB5 relevant flags and set the 2016*7c478bd9Sstevel@tonic-gate * cmd-buffer so that normal rcp works 2017*7c478bd9Sstevel@tonic-gate */ 2018*7c478bd9Sstevel@tonic-gate krb5auth_flag = encrypt_flag = encrypt_done = 0; 2019*7c478bd9Sstevel@tonic-gate cmd = cmd_orig; 2020*7c478bd9Sstevel@tonic-gate cmd_sunw = cmd_sunw_orig; 2021*7c478bd9Sstevel@tonic-gate 2022*7c478bd9Sstevel@tonic-gate if (cur_argc < 2) 2023*7c478bd9Sstevel@tonic-gate usage(); 2024*7c478bd9Sstevel@tonic-gate 2025*7c478bd9Sstevel@tonic-gate if (cur_argc > 2) 2026*7c478bd9Sstevel@tonic-gate targetshouldbedirectory = 1; 2027*7c478bd9Sstevel@tonic-gate 2028*7c478bd9Sstevel@tonic-gate rem = -1; 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate prev_argc = cur_argc; 2031*7c478bd9Sstevel@tonic-gate prev_argv = save_argv(cur_argc, cur_argv); 2032*7c478bd9Sstevel@tonic-gate 2033*7c478bd9Sstevel@tonic-gate (void) init_service(krb5auth_flag); 2034*7c478bd9Sstevel@tonic-gate 2035*7c478bd9Sstevel@tonic-gate if (target = colon(cur_argv[cur_argc - 1])) { 2036*7c478bd9Sstevel@tonic-gate toremote(target, cur_argc, cur_argv); 2037*7c478bd9Sstevel@tonic-gate } else { 2038*7c478bd9Sstevel@tonic-gate tolocal(cur_argc, cur_argv); 2039*7c478bd9Sstevel@tonic-gate if (targetshouldbedirectory) 2040*7c478bd9Sstevel@tonic-gate verifydir(cur_argv[cur_argc - 1]); 2041*7c478bd9Sstevel@tonic-gate } 2042*7c478bd9Sstevel@tonic-gate exit(errs); 2043*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2044*7c478bd9Sstevel@tonic-gate } 2045*7c478bd9Sstevel@tonic-gate 2046*7c478bd9Sstevel@tonic-gate 2047*7c478bd9Sstevel@tonic-gate static int 2048*7c478bd9Sstevel@tonic-gate init_service(int krb5flag) 2049*7c478bd9Sstevel@tonic-gate { 2050*7c478bd9Sstevel@tonic-gate struct servent *sp; 2051*7c478bd9Sstevel@tonic-gate boolean_t success = B_FALSE; 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate if (krb5flag > 0) { 2054*7c478bd9Sstevel@tonic-gate sp = getservbyname("kshell", "tcp"); 2055*7c478bd9Sstevel@tonic-gate if (sp == NULL) { 2056*7c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 2057*7c478bd9Sstevel@tonic-gate gettext("rcp: kshell/tcp: unknown service.\n" 2058*7c478bd9Sstevel@tonic-gate "trying normal shell/tcp service\n")); 2059*7c478bd9Sstevel@tonic-gate } else { 2060*7c478bd9Sstevel@tonic-gate portnumber = sp->s_port; 2061*7c478bd9Sstevel@tonic-gate success = B_TRUE; 2062*7c478bd9Sstevel@tonic-gate } 2063*7c478bd9Sstevel@tonic-gate } else { 2064*7c478bd9Sstevel@tonic-gate portnumber = htons(IPPORT_CMDSERVER); 2065*7c478bd9Sstevel@tonic-gate success = B_TRUE; 2066*7c478bd9Sstevel@tonic-gate } 2067*7c478bd9Sstevel@tonic-gate return (success); 2068*7c478bd9Sstevel@tonic-gate } 2069*7c478bd9Sstevel@tonic-gate 2070*7c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/ 2071*7c478bd9Sstevel@tonic-gate static void 2072*7c478bd9Sstevel@tonic-gate error(char *fmt, ...) 2073*7c478bd9Sstevel@tonic-gate { 2074*7c478bd9Sstevel@tonic-gate va_list ap; 2075*7c478bd9Sstevel@tonic-gate char buf[RCP_BUFSIZE]; 2076*7c478bd9Sstevel@tonic-gate char *cp = buf; 2077*7c478bd9Sstevel@tonic-gate 2078*7c478bd9Sstevel@tonic-gate va_start(ap, fmt); 2079*7c478bd9Sstevel@tonic-gate errs++; 2080*7c478bd9Sstevel@tonic-gate *cp++ = 1; 2081*7c478bd9Sstevel@tonic-gate (void) vsnprintf(cp, sizeof (buf) - 1, fmt, ap); 2082*7c478bd9Sstevel@tonic-gate va_end(ap); 2083*7c478bd9Sstevel@tonic-gate 2084*7c478bd9Sstevel@tonic-gate (void) desrcpwrite(rem, buf, strlen(buf)); 2085*7c478bd9Sstevel@tonic-gate if (iamremote == 0) 2086*7c478bd9Sstevel@tonic-gate (void) write(2, buf + 1, strlen(buf + 1)); 2087*7c478bd9Sstevel@tonic-gate } 2088