Commit | Line | Data |
---|---|---|
22e155fc | 1 | /* |
f8b77578 | 2 | * Copyright (c) 1983, 1990 The Regents of the University of California. |
ebb479fc KB |
3 | * All rights reserved. |
4 | * | |
27c71911 | 5 | * %sccs.include.redist.c% |
22e155fc DF |
6 | */ |
7 | ||
8 | #ifndef lint | |
9 | char copyright[] = | |
f8b77578 | 10 | "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ |
22e155fc | 11 | All rights reserved.\n"; |
ebb479fc | 12 | #endif /* not lint */ |
22e155fc | 13 | |
b7ff3bb3 | 14 | #ifndef lint |
a045d3a2 | 15 | static char sccsid[] = "@(#)rcp.c 5.32 (Berkeley) %G%"; |
ebb479fc | 16 | #endif /* not lint */ |
b7ff3bb3 | 17 | |
4ca10280 SL |
18 | /* |
19 | * rcp | |
20 | */ | |
ed0072ae | 21 | #include <sys/param.h> |
b7ff3bb3 | 22 | #include <sys/stat.h> |
af86e024 | 23 | #include <sys/time.h> |
b7ff3bb3 | 24 | #include <sys/ioctl.h> |
a045d3a2 KB |
25 | #include <sys/socket.h> |
26 | #include <sys/wait.h> | |
94a2d2a7 | 27 | #include <netinet/in.h> |
f8b77578 MK |
28 | #include <netinet/in_systm.h> |
29 | #include <netinet/ip.h> | |
a045d3a2 KB |
30 | #include <dirent.h> |
31 | #include <fcntl.h> | |
32 | #include <signal.h> | |
b7ff3bb3 | 33 | #include <pwd.h> |
92e58d95 | 34 | #include <netdb.h> |
b7ff3bb3 | 35 | #include <errno.h> |
a045d3a2 | 36 | #include <unistd.h> |
35673a6d | 37 | #include <stdio.h> |
42029053 | 38 | #include <stdlib.h> |
a045d3a2 | 39 | #include <string.h> |
35673a6d | 40 | #include <ctype.h> |
e4ba000a | 41 | #include "pathnames.h" |
4ca10280 | 42 | |
35673a6d | 43 | #ifdef KERBEROS |
1b8d273e | 44 | #include <kerberosIV/des.h> |
579f51c2 | 45 | #include <kerberosIV/krb.h> |
5d178979 KF |
46 | char dst_realm_buf[REALM_SZ]; |
47 | char *dest_realm = NULL; | |
898015bc | 48 | int use_kerberos = 1; |
5d178979 KF |
49 | CREDENTIALS cred; |
50 | Key_schedule schedule; | |
51 | extern char *krb_realmofhost(); | |
a045d3a2 | 52 | #define OPTIONS "dfk:prt" |
898015bc | 53 | #else |
5d178979 | 54 | #define OPTIONS "dfprt" |
2b6b7619 KF |
55 | #endif |
56 | ||
35673a6d | 57 | struct passwd *pwd; |
5d178979 KF |
58 | u_short port; |
59 | uid_t userid; | |
60 | int errs, rem; | |
61 | int pflag, iamremote, iamrecursive, targetshouldbedirectory; | |
371655cc | 62 | |
5d178979 | 63 | #define CMDNEEDS 64 |
d4c44137 | 64 | char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ |
b7ff3bb3 | 65 | |
35673a6d KB |
66 | typedef struct _buf { |
67 | int cnt; | |
68 | char *buf; | |
69 | } BUF; | |
b7ff3bb3 | 70 | |
a045d3a2 KB |
71 | void lostconn(); |
72 | ||
b7ff3bb3 BJ |
73 | main(argc, argv) |
74 | int argc; | |
75 | char **argv; | |
76 | { | |
35673a6d | 77 | extern int optind; |
a045d3a2 | 78 | extern char *optarg; |
11bfe9c9 | 79 | struct servent *sp; |
f95b553a | 80 | int ch, fflag, tflag; |
898015bc | 81 | char *targ, *shell, *colon(); |
92e58d95 | 82 | |
f95b553a | 83 | fflag = tflag = 0; |
5d178979 | 84 | while ((ch = getopt(argc, argv, OPTIONS)) != EOF) |
35673a6d | 85 | switch(ch) { |
5d178979 | 86 | /* user-visible flags */ |
35673a6d KB |
87 | case 'p': /* preserve access/mod times */ |
88 | ++pflag; | |
af86e024 | 89 | break; |
35673a6d KB |
90 | case 'r': |
91 | ++iamrecursive; | |
af86e024 | 92 | break; |
5d178979 KF |
93 | #ifdef KERBEROS |
94 | case 'k': | |
a045d3a2 | 95 | strncpy(dst_realm_buf, optarg, REALM_SZ); |
5d178979 | 96 | dest_realm = dst_realm_buf; |
f95b553a | 97 | break; |
35673a6d | 98 | #endif |
5d178979 KF |
99 | /* rshd-invoked options (server) */ |
100 | case 'd': | |
101 | targetshouldbedirectory = 1; | |
102 | break; | |
103 | case 'f': /* "from" */ | |
104 | iamremote = 1; | |
105 | fflag = 1; | |
106 | break; | |
107 | case 't': /* "to" */ | |
108 | iamremote = 1; | |
109 | tflag = 1; | |
110 | break; | |
111 | ||
35673a6d KB |
112 | case '?': |
113 | default: | |
5f286db0 | 114 | usage(); |
af86e024 | 115 | } |
35673a6d KB |
116 | argc -= optind; |
117 | argv += optind; | |
118 | ||
5d178979 | 119 | #ifdef KERBEROS |
898015bc | 120 | shell = "kshell"; |
898015bc | 121 | sp = getservbyname(shell, "tcp"); |
5d178979 KF |
122 | if (sp == NULL) { |
123 | char msgbuf[64]; | |
124 | use_kerberos = 0; | |
a045d3a2 KB |
125 | (void)snprintf(msgbuf, sizeof(msgbuf), |
126 | "can't get entry for %s/tcp service", shell); | |
5d178979 | 127 | old_warning(msgbuf); |
42029053 | 128 | sp = getservbyname(shell = "shell", "tcp"); |
5d178979 KF |
129 | } |
130 | #else | |
42029053 | 131 | sp = getservbyname(shell = "shell", "tcp"); |
5d178979 KF |
132 | #endif |
133 | if (sp == NULL) { | |
42029053 | 134 | (void)fprintf(stderr, "rcp: %s/tcp: unknown service\n", shell); |
5d178979 KF |
135 | exit(1); |
136 | } | |
137 | port = sp->s_port; | |
138 | ||
139 | if (!(pwd = getpwuid(userid = getuid()))) { | |
42029053 | 140 | (void)fprintf(stderr, "rcp: unknown user %d.\n", (int)userid); |
5d178979 KF |
141 | exit(1); |
142 | } | |
143 | ||
f95b553a | 144 | if (fflag) { |
5d178979 | 145 | /* follow "protocol", send data */ |
f95b553a KB |
146 | (void)response(); |
147 | (void)setuid(userid); | |
148 | source(argc, argv); | |
149 | exit(errs); | |
150 | } | |
151 | ||
152 | if (tflag) { | |
5d178979 | 153 | /* receive data */ |
f95b553a KB |
154 | (void)setuid(userid); |
155 | sink(argc, argv); | |
156 | exit(errs); | |
157 | } | |
158 | ||
5f286db0 KB |
159 | if (argc < 2) |
160 | usage(); | |
b7ff3bb3 BJ |
161 | if (argc > 2) |
162 | targetshouldbedirectory = 1; | |
35673a6d | 163 | |
5f286db0 | 164 | rem = -1; |
5d178979 KF |
165 | /* command to be executed on remote system using "rsh" */ |
166 | #ifdef KERBEROS | |
a045d3a2 KB |
167 | (void)snprintf(cmd, sizeof(cmd), |
168 | "rcp%s%s%s%s", iamrecursive ? " -r" : "", | |
898015bc | 169 | "", |
5d178979 KF |
170 | pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); |
171 | #else | |
a045d3a2 KB |
172 | (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s", |
173 | iamrecursive ? " -r" : "", pflag ? " -p" : "", | |
174 | targetshouldbedirectory ? " -d" : ""); | |
5d178979 | 175 | #endif |
35673a6d KB |
176 | |
177 | (void)signal(SIGPIPE, lostconn); | |
178 | ||
179 | if (targ = colon(argv[argc - 1])) | |
5d178979 | 180 | toremote(targ, argc, argv); /* destination is remote host */ |
35673a6d | 181 | else { |
5d178979 | 182 | tolocal(argc, argv); /* destination is local host */ |
35673a6d KB |
183 | if (targetshouldbedirectory) |
184 | verifydir(argv[argc - 1]); | |
185 | } | |
186 | exit(errs); | |
187 | } | |
188 | ||
189 | toremote(targ, argc, argv) | |
190 | char *targ; | |
191 | int argc; | |
192 | char **argv; | |
193 | { | |
a045d3a2 | 194 | int i, len, tos; |
d4c44137 | 195 | char *bp, *host, *src, *suser, *thost, *tuser; |
42029053 | 196 | char *colon(); |
35673a6d KB |
197 | |
198 | *targ++ = 0; | |
199 | if (*targ == 0) | |
200 | targ = "."; | |
201 | ||
d4c44137 | 202 | if (thost = index(argv[argc - 1], '@')) { |
5d178979 | 203 | /* user@host */ |
35673a6d KB |
204 | *thost++ = 0; |
205 | tuser = argv[argc - 1]; | |
206 | if (*tuser == '\0') | |
9e9252a8 | 207 | tuser = NULL; |
35673a6d KB |
208 | else if (!okname(tuser)) |
209 | exit(1); | |
210 | } else { | |
211 | thost = argv[argc - 1]; | |
212 | tuser = NULL; | |
213 | } | |
2b6b7619 | 214 | |
35673a6d KB |
215 | for (i = 0; i < argc - 1; i++) { |
216 | src = colon(argv[i]); | |
217 | if (src) { /* remote to remote */ | |
218 | *src++ = 0; | |
219 | if (*src == 0) | |
220 | src = "."; | |
221 | host = index(argv[i], '@'); | |
a045d3a2 KB |
222 | len = strlen(_PATH_RSH) + strlen(argv[i]) + |
223 | strlen(src) + (tuser ? strlen(tuser) : 0) + | |
224 | strlen(thost) + strlen(targ) + CMDNEEDS + 20; | |
225 | if (!(bp = malloc(len))) | |
226 | nospace(); | |
35673a6d KB |
227 | if (host) { |
228 | *host++ = 0; | |
229 | suser = argv[i]; | |
230 | if (*suser == '\0') | |
231 | suser = pwd->pw_name; | |
232 | else if (!okname(suser)) | |
233 | continue; | |
a045d3a2 | 234 | (void)snprintf(bp, len, |
35673a6d KB |
235 | "%s %s -l %s -n %s %s '%s%s%s:%s'", |
236 | _PATH_RSH, host, suser, cmd, src, | |
237 | tuser ? tuser : "", tuser ? "@" : "", | |
238 | thost, targ); | |
239 | } else | |
a045d3a2 KB |
240 | (void)snprintf(bp, len, |
241 | "%s %s -n %s %s '%s%s%s:%s'", | |
35673a6d KB |
242 | _PATH_RSH, argv[i], cmd, src, |
243 | tuser ? tuser : "", tuser ? "@" : "", | |
244 | thost, targ); | |
d4c44137 KB |
245 | (void)susystem(bp); |
246 | (void)free(bp); | |
35673a6d KB |
247 | } else { /* local to remote */ |
248 | if (rem == -1) { | |
a045d3a2 KB |
249 | len = strlen(targ) + CMDNEEDS + 20; |
250 | if (!(bp = malloc(len))) | |
d4c44137 | 251 | nospace(); |
a045d3a2 | 252 | (void)snprintf(bp, len, "%s -t %s", cmd, targ); |
35673a6d KB |
253 | host = thost; |
254 | #ifdef KERBEROS | |
255 | if (use_kerberos) | |
5d178979 KF |
256 | rem = kerberos(&host, bp, |
257 | pwd->pw_name, | |
d4c44137 | 258 | tuser ? tuser : pwd->pw_name); |
35673a6d KB |
259 | else |
260 | #endif | |
9e9252a8 JB |
261 | rem = rcmd(&host, port, pwd->pw_name, |
262 | tuser ? tuser : pwd->pw_name, | |
d4c44137 | 263 | bp, 0); |
35673a6d KB |
264 | if (rem < 0) |
265 | exit(1); | |
f8b77578 MK |
266 | tos = IPTOS_THROUGHPUT; |
267 | if (setsockopt(rem, IPPROTO_IP, IP_TOS, | |
268 | (char *)&tos, sizeof(int)) < 0) | |
d9847eab | 269 | perror("rcp: setsockopt TOS (ignored)"); |
35673a6d KB |
270 | if (response() < 0) |
271 | exit(1); | |
d4c44137 | 272 | (void)free(bp); |
35673a6d | 273 | (void)setuid(userid); |
b7ff3bb3 | 274 | } |
35673a6d | 275 | source(1, argv+i); |
b7ff3bb3 | 276 | } |
35673a6d KB |
277 | } |
278 | } | |
279 | ||
280 | tolocal(argc, argv) | |
281 | int argc; | |
282 | char **argv; | |
283 | { | |
a045d3a2 | 284 | int i, len, tos; |
d4c44137 | 285 | char *bp, *host, *src, *suser; |
42029053 | 286 | char *colon(); |
35673a6d KB |
287 | |
288 | for (i = 0; i < argc - 1; i++) { | |
d4c44137 | 289 | if (!(src = colon(argv[i]))) { /* local to local */ |
a045d3a2 KB |
290 | len = strlen(_PATH_CP) + strlen(argv[i]) + |
291 | strlen(argv[argc - 1]) + 20; | |
292 | if (!(bp = malloc(len))) | |
d4c44137 | 293 | nospace(); |
a045d3a2 | 294 | (void)snprintf(bp, len, "%s%s%s %s %s", _PATH_CP, |
d4c44137 KB |
295 | iamrecursive ? " -r" : "", pflag ? " -p" : "", |
296 | argv[i], argv[argc - 1]); | |
297 | (void)susystem(bp); | |
298 | (void)free(bp); | |
299 | continue; | |
300 | } | |
301 | *src++ = 0; | |
302 | if (*src == 0) | |
303 | src = "."; | |
304 | host = index(argv[i], '@'); | |
305 | if (host) { | |
306 | *host++ = 0; | |
307 | suser = argv[i]; | |
308 | if (*suser == '\0') | |
35673a6d | 309 | suser = pwd->pw_name; |
d4c44137 | 310 | else if (!okname(suser)) |
35673a6d | 311 | continue; |
d4c44137 KB |
312 | } else { |
313 | host = argv[i]; | |
314 | suser = pwd->pw_name; | |
b7ff3bb3 | 315 | } |
a045d3a2 KB |
316 | len = strlen(src) + CMDNEEDS + 20; |
317 | if (!(bp = malloc(len))) | |
d4c44137 | 318 | nospace(); |
a045d3a2 | 319 | (void)snprintf(bp, len, "%s -f %s", cmd, src); |
d4c44137 KB |
320 | #ifdef KERBEROS |
321 | if (use_kerberos) | |
5d178979 | 322 | rem = kerberos(&host, bp, pwd->pw_name, suser); |
d4c44137 KB |
323 | else |
324 | #endif | |
325 | rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); | |
326 | (void)free(bp); | |
327 | if (rem < 0) | |
328 | continue; | |
f8b77578 MK |
329 | (void)seteuid(userid); |
330 | tos = IPTOS_THROUGHPUT; | |
331 | if (setsockopt(rem, IPPROTO_IP, IP_TOS, | |
332 | (char *)&tos, sizeof(int)) < 0) | |
d9847eab | 333 | perror("rcp: setsockopt TOS (ignored)"); |
d4c44137 | 334 | sink(1, argv + argc - 1); |
f8b77578 | 335 | (void)seteuid(0); |
d4c44137 KB |
336 | (void)close(rem); |
337 | rem = -1; | |
b7ff3bb3 | 338 | } |
b7ff3bb3 BJ |
339 | } |
340 | ||
341 | verifydir(cp) | |
342 | char *cp; | |
343 | { | |
344 | struct stat stb; | |
345 | ||
11bfe9c9 RC |
346 | if (stat(cp, &stb) >= 0) { |
347 | if ((stb.st_mode & S_IFMT) == S_IFDIR) | |
348 | return; | |
349 | errno = ENOTDIR; | |
350 | } | |
ef49bf4f | 351 | error("rcp: %s: %s.\n", cp, strerror(errno)); |
b7ff3bb3 BJ |
352 | exit(1); |
353 | } | |
354 | ||
355 | char * | |
356 | colon(cp) | |
35673a6d | 357 | register char *cp; |
b7ff3bb3 | 358 | { |
35673a6d | 359 | for (; *cp; ++cp) { |
b7ff3bb3 | 360 | if (*cp == ':') |
35673a6d | 361 | return(cp); |
b7ff3bb3 | 362 | if (*cp == '/') |
35673a6d | 363 | return(0); |
b7ff3bb3 | 364 | } |
35673a6d | 365 | return(0); |
b7ff3bb3 BJ |
366 | } |
367 | ||
368 | okname(cp0) | |
369 | char *cp0; | |
370 | { | |
371 | register char *cp = cp0; | |
372 | register int c; | |
373 | ||
374 | do { | |
375 | c = *cp; | |
376 | if (c & 0200) | |
377 | goto bad; | |
378 | if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') | |
379 | goto bad; | |
d4c44137 | 380 | } while (*++cp); |
35673a6d | 381 | return(1); |
b7ff3bb3 | 382 | bad: |
d4c44137 | 383 | (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); |
35673a6d | 384 | return(0); |
b7ff3bb3 BJ |
385 | } |
386 | ||
48755084 S |
387 | susystem(s) |
388 | char *s; | |
b7ff3bb3 | 389 | { |
48755084 | 390 | int status, pid, w; |
5d178979 | 391 | register sig_t istat, qstat; |
b7ff3bb3 | 392 | |
48755084 | 393 | if ((pid = vfork()) == 0) { |
35673a6d | 394 | (void)setuid(userid); |
e4ba000a | 395 | execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); |
48755084 S |
396 | _exit(127); |
397 | } | |
398 | istat = signal(SIGINT, SIG_IGN); | |
399 | qstat = signal(SIGQUIT, SIG_IGN); | |
400 | while ((w = wait(&status)) != pid && w != -1) | |
401 | ; | |
402 | if (w == -1) | |
403 | status = -1; | |
35673a6d KB |
404 | (void)signal(SIGINT, istat); |
405 | (void)signal(SIGQUIT, qstat); | |
406 | return(status); | |
b7ff3bb3 BJ |
407 | } |
408 | ||
409 | source(argc, argv) | |
410 | int argc; | |
411 | char **argv; | |
412 | { | |
b7ff3bb3 | 413 | struct stat stb; |
35673a6d KB |
414 | static BUF buffer; |
415 | BUF *bp; | |
5f10dd79 | 416 | off_t i; |
35673a6d KB |
417 | int x, readerr, f, amt; |
418 | char *last, *name, buf[BUFSIZ]; | |
419 | BUF *allocbuf(); | |
b7ff3bb3 BJ |
420 | |
421 | for (x = 0; x < argc; x++) { | |
422 | name = argv[x]; | |
35673a6d | 423 | if ((f = open(name, O_RDONLY, 0)) < 0) { |
ef49bf4f | 424 | error("rcp: %s: %s\n", name, strerror(errno)); |
b7ff3bb3 BJ |
425 | continue; |
426 | } | |
427 | if (fstat(f, &stb) < 0) | |
428 | goto notreg; | |
429 | switch (stb.st_mode&S_IFMT) { | |
430 | ||
431 | case S_IFREG: | |
432 | break; | |
433 | ||
434 | case S_IFDIR: | |
435 | if (iamrecursive) { | |
35673a6d | 436 | (void)close(f); |
af86e024 | 437 | rsource(name, &stb); |
b7ff3bb3 BJ |
438 | continue; |
439 | } | |
35673a6d | 440 | /* FALLTHROUGH */ |
b7ff3bb3 | 441 | default: |
35673a6d | 442 | notreg: (void)close(f); |
b7ff3bb3 BJ |
443 | error("rcp: %s: not a plain file\n", name); |
444 | continue; | |
445 | } | |
446 | last = rindex(name, '/'); | |
447 | if (last == 0) | |
448 | last = name; | |
449 | else | |
450 | last++; | |
af86e024 JL |
451 | if (pflag) { |
452 | /* | |
453 | * Make it compatible with possible future | |
454 | * versions expecting microseconds. | |
455 | */ | |
a045d3a2 KB |
456 | (void)snprintf(buf, sizeof(buf), |
457 | "T%ld 0 %ld 0\n", stb.st_mtime, stb.st_atime); | |
42029053 | 458 | (void)write(rem, buf, (int)strlen(buf)); |
af86e024 | 459 | if (response() < 0) { |
35673a6d | 460 | (void)close(f); |
af86e024 JL |
461 | continue; |
462 | } | |
463 | } | |
a045d3a2 KB |
464 | (void)snprintf(buf, sizeof(buf), |
465 | "C%04o %ld %s\n", stb.st_mode&07777, stb.st_size, last); | |
42029053 | 466 | (void)write(rem, buf, (int)strlen(buf)); |
b7ff3bb3 | 467 | if (response() < 0) { |
35673a6d | 468 | (void)close(f); |
b7ff3bb3 BJ |
469 | continue; |
470 | } | |
809ba2d2 | 471 | if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { |
35673a6d | 472 | (void)close(f); |
371655cc KM |
473 | continue; |
474 | } | |
f68c1c98 | 475 | readerr = 0; |
371655cc KM |
476 | for (i = 0; i < stb.st_size; i += bp->cnt) { |
477 | amt = bp->cnt; | |
b7ff3bb3 BJ |
478 | if (i + amt > stb.st_size) |
479 | amt = stb.st_size - i; | |
f68c1c98 KB |
480 | if (readerr == 0 && read(f, bp->buf, amt) != amt) |
481 | readerr = errno; | |
35673a6d | 482 | (void)write(rem, bp->buf, amt); |
b7ff3bb3 | 483 | } |
35673a6d | 484 | (void)close(f); |
f68c1c98 | 485 | if (readerr == 0) |
35673a6d | 486 | (void)write(rem, "", 1); |
b7ff3bb3 | 487 | else |
ef49bf4f | 488 | error("rcp: %s: %s\n", name, strerror(readerr)); |
35673a6d | 489 | (void)response(); |
b7ff3bb3 BJ |
490 | } |
491 | } | |
492 | ||
af86e024 | 493 | rsource(name, statp) |
b7ff3bb3 | 494 | char *name; |
af86e024 | 495 | struct stat *statp; |
b7ff3bb3 | 496 | { |
a045d3a2 KB |
497 | DIR *dirp; |
498 | struct dirent *dp; | |
d4c44137 | 499 | char *last, *vect[1], path[MAXPATHLEN]; |
b7ff3bb3 | 500 | |
a045d3a2 | 501 | if (!(dirp = opendir(name))) { |
ef49bf4f | 502 | error("rcp: %s: %s\n", name, strerror(errno)); |
b7ff3bb3 BJ |
503 | return; |
504 | } | |
505 | last = rindex(name, '/'); | |
506 | if (last == 0) | |
507 | last = name; | |
508 | else | |
509 | last++; | |
af86e024 | 510 | if (pflag) { |
a045d3a2 KB |
511 | (void)snprintf(path, sizeof(path), |
512 | "T%ld 0 %ld 0\n", statp->st_mtime, statp->st_atime); | |
42029053 | 513 | (void)write(rem, path, (int)strlen(path)); |
af86e024 | 514 | if (response() < 0) { |
a045d3a2 | 515 | closedir(dirp); |
af86e024 JL |
516 | return; |
517 | } | |
518 | } | |
a045d3a2 KB |
519 | (void)snprintf(path, sizeof(path), |
520 | "D%04o %d %s\n", statp->st_mode&07777, 0, last); | |
42029053 | 521 | (void)write(rem, path, (int)strlen(path)); |
b7ff3bb3 | 522 | if (response() < 0) { |
a045d3a2 | 523 | closedir(dirp); |
b7ff3bb3 BJ |
524 | return; |
525 | } | |
a045d3a2 | 526 | while (dp = readdir(dirp)) { |
b7ff3bb3 BJ |
527 | if (dp->d_ino == 0) |
528 | continue; | |
529 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) | |
530 | continue; | |
d4c44137 KB |
531 | if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { |
532 | error("%s/%s: name too long.\n", name, dp->d_name); | |
b7ff3bb3 BJ |
533 | continue; |
534 | } | |
a045d3a2 | 535 | (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); |
d4c44137 KB |
536 | vect[0] = path; |
537 | source(1, vect); | |
b7ff3bb3 | 538 | } |
a045d3a2 | 539 | closedir(dirp); |
35673a6d KB |
540 | (void)write(rem, "E\n", 2); |
541 | (void)response(); | |
b7ff3bb3 BJ |
542 | } |
543 | ||
544 | response() | |
545 | { | |
35673a6d KB |
546 | register char *cp; |
547 | char ch, resp, rbuf[BUFSIZ]; | |
b7ff3bb3 | 548 | |
35673a6d | 549 | if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) |
b7ff3bb3 | 550 | lostconn(); |
b7ff3bb3 | 551 | |
35673a6d KB |
552 | cp = rbuf; |
553 | switch(resp) { | |
af86e024 | 554 | case 0: /* ok */ |
35673a6d | 555 | return(0); |
b7ff3bb3 BJ |
556 | default: |
557 | *cp++ = resp; | |
35673a6d | 558 | /* FALLTHROUGH */ |
af86e024 JL |
559 | case 1: /* error, followed by err msg */ |
560 | case 2: /* fatal error, "" */ | |
b7ff3bb3 | 561 | do { |
35673a6d | 562 | if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) |
b7ff3bb3 | 563 | lostconn(); |
35673a6d KB |
564 | *cp++ = ch; |
565 | } while (cp < &rbuf[BUFSIZ] && ch != '\n'); | |
566 | ||
567 | if (!iamremote) | |
568 | (void)write(2, rbuf, cp - rbuf); | |
569 | ++errs; | |
b7ff3bb3 | 570 | if (resp == 1) |
35673a6d | 571 | return(-1); |
b7ff3bb3 BJ |
572 | exit(1); |
573 | } | |
574 | /*NOTREACHED*/ | |
575 | } | |
576 | ||
a045d3a2 | 577 | void |
b7ff3bb3 BJ |
578 | lostconn() |
579 | { | |
35673a6d KB |
580 | if (!iamremote) |
581 | (void)fprintf(stderr, "rcp: lost connection\n"); | |
b7ff3bb3 BJ |
582 | exit(1); |
583 | } | |
584 | ||
585 | sink(argc, argv) | |
586 | int argc; | |
587 | char **argv; | |
588 | { | |
d4c44137 | 589 | register char *cp; |
35673a6d | 590 | static BUF buffer; |
371655cc | 591 | struct stat stb; |
af86e024 | 592 | struct timeval tv[2]; |
ef49bf4f | 593 | enum { YES, NO, DISPLAYED } wrerr; |
d4c44137 KB |
594 | BUF *bp, *allocbuf(); |
595 | off_t i, j; | |
596 | char ch, *targ, *why; | |
597 | int amt, count, exists, first, mask, mode; | |
ef49bf4f | 598 | int ofd, setimes, size, targisdir; |
42029053 | 599 | char *np, *vect[1], buf[BUFSIZ]; |
b7ff3bb3 | 600 | |
d4c44137 KB |
601 | #define atime tv[0] |
602 | #define mtime tv[1] | |
603 | #define SCREWUP(str) { why = str; goto screwup; } | |
604 | ||
605 | setimes = targisdir = 0; | |
606 | mask = umask(0); | |
a4372a41 | 607 | if (!pflag) |
35673a6d | 608 | (void)umask(mask); |
11bfe9c9 | 609 | if (argc != 1) { |
b7ff3bb3 BJ |
610 | error("rcp: ambiguous target\n"); |
611 | exit(1); | |
612 | } | |
613 | targ = *argv; | |
614 | if (targetshouldbedirectory) | |
615 | verifydir(targ); | |
35673a6d | 616 | (void)write(rem, "", 1); |
b7ff3bb3 BJ |
617 | if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) |
618 | targisdir = 1; | |
d4c44137 KB |
619 | for (first = 1;; first = 0) { |
620 | cp = buf; | |
b7ff3bb3 BJ |
621 | if (read(rem, cp, 1) <= 0) |
622 | return; | |
623 | if (*cp++ == '\n') | |
d4c44137 | 624 | SCREWUP("unexpected <newline>"); |
b7ff3bb3 | 625 | do { |
d4c44137 | 626 | if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) |
b7ff3bb3 | 627 | SCREWUP("lost connection"); |
d4c44137 KB |
628 | *cp++ = ch; |
629 | } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); | |
b7ff3bb3 | 630 | *cp = 0; |
d4c44137 KB |
631 | |
632 | if (buf[0] == '\01' || buf[0] == '\02') { | |
b7ff3bb3 | 633 | if (iamremote == 0) |
42029053 | 634 | (void)write(2, buf + 1, (int)strlen(buf + 1)); |
d4c44137 | 635 | if (buf[0] == '\02') |
b7ff3bb3 BJ |
636 | exit(1); |
637 | errs++; | |
638 | continue; | |
639 | } | |
d4c44137 | 640 | if (buf[0] == 'E') { |
35673a6d | 641 | (void)write(rem, "", 1); |
b7ff3bb3 BJ |
642 | return; |
643 | } | |
af86e024 | 644 | |
3eafec57 | 645 | if (ch == '\n') |
6f6da275 | 646 | *--cp = 0; |
3eafec57 | 647 | |
af86e024 | 648 | #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); |
d4c44137 | 649 | cp = buf; |
af86e024 JL |
650 | if (*cp == 'T') { |
651 | setimes++; | |
652 | cp++; | |
653 | getnum(mtime.tv_sec); | |
654 | if (*cp++ != ' ') | |
655 | SCREWUP("mtime.sec not delimited"); | |
656 | getnum(mtime.tv_usec); | |
657 | if (*cp++ != ' ') | |
658 | SCREWUP("mtime.usec not delimited"); | |
659 | getnum(atime.tv_sec); | |
660 | if (*cp++ != ' ') | |
661 | SCREWUP("atime.sec not delimited"); | |
662 | getnum(atime.tv_usec); | |
663 | if (*cp++ != '\0') | |
664 | SCREWUP("atime.usec not delimited"); | |
35673a6d | 665 | (void)write(rem, "", 1); |
af86e024 JL |
666 | continue; |
667 | } | |
4550ab9e RC |
668 | if (*cp != 'C' && *cp != 'D') { |
669 | /* | |
670 | * Check for the case "rcp remote:foo\* local:bar". | |
671 | * In this case, the line "No match." can be returned | |
672 | * by the shell before the rcp command on the remote is | |
673 | * executed so the ^Aerror_message convention isn't | |
674 | * followed. | |
675 | */ | |
676 | if (first) { | |
677 | error("%s\n", cp); | |
678 | exit(1); | |
679 | } | |
b7ff3bb3 | 680 | SCREWUP("expected control record"); |
4550ab9e | 681 | } |
b7ff3bb3 | 682 | mode = 0; |
d4c44137 | 683 | for (++cp; cp < buf + 5; cp++) { |
b7ff3bb3 BJ |
684 | if (*cp < '0' || *cp > '7') |
685 | SCREWUP("bad mode"); | |
686 | mode = (mode << 3) | (*cp - '0'); | |
687 | } | |
688 | if (*cp++ != ' ') | |
689 | SCREWUP("mode not delimited"); | |
690 | size = 0; | |
a4372a41 | 691 | while (isdigit(*cp)) |
b7ff3bb3 BJ |
692 | size = size * 10 + (*cp++ - '0'); |
693 | if (*cp++ != ' ') | |
694 | SCREWUP("size not delimited"); | |
d4c44137 KB |
695 | if (targisdir) { |
696 | static char *namebuf; | |
697 | static int cursize; | |
42029053 | 698 | size_t need; |
d4c44137 KB |
699 | |
700 | need = strlen(targ) + strlen(cp) + 250; | |
701 | if (need > cursize) { | |
42029053 | 702 | if (!(namebuf = malloc(need))) |
3eafec57 | 703 | error("out of memory\n"); |
d4c44137 | 704 | } |
a045d3a2 | 705 | (void)snprintf(namebuf, need, "%s%s%s", targ, |
b7ff3bb3 | 706 | *targ ? "/" : "", cp); |
d4c44137 KB |
707 | np = namebuf; |
708 | } | |
b7ff3bb3 | 709 | else |
d4c44137 KB |
710 | np = targ; |
711 | exists = stat(np, &stb) == 0; | |
712 | if (buf[0] == 'D') { | |
11bfe9c9 | 713 | if (exists) { |
b7ff3bb3 BJ |
714 | if ((stb.st_mode&S_IFMT) != S_IFDIR) { |
715 | errno = ENOTDIR; | |
716 | goto bad; | |
717 | } | |
a4372a41 | 718 | if (pflag) |
d4c44137 KB |
719 | (void)chmod(np, mode); |
720 | } else if (mkdir(np, mode) < 0) | |
b7ff3bb3 | 721 | goto bad; |
d4c44137 KB |
722 | vect[0] = np; |
723 | sink(1, vect); | |
af86e024 JL |
724 | if (setimes) { |
725 | setimes = 0; | |
d4c44137 KB |
726 | if (utimes(np, tv) < 0) |
727 | error("rcp: can't set times on %s: %s\n", | |
ef49bf4f | 728 | np, strerror(errno)); |
af86e024 | 729 | } |
b7ff3bb3 | 730 | continue; |
11bfe9c9 | 731 | } |
d4c44137 | 732 | if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { |
ef49bf4f | 733 | bad: error("rcp: %s: %s\n", np, strerror(errno)); |
b7ff3bb3 | 734 | continue; |
b7ff3bb3 | 735 | } |
a4372a41 | 736 | if (exists && pflag) |
d4c44137 | 737 | (void)fchmod(ofd, mode); |
35673a6d | 738 | (void)write(rem, "", 1); |
d4c44137 KB |
739 | if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { |
740 | (void)close(ofd); | |
371655cc KM |
741 | continue; |
742 | } | |
743 | cp = bp->buf; | |
744 | count = 0; | |
ef49bf4f | 745 | wrerr = NO; |
b7ff3bb3 | 746 | for (i = 0; i < size; i += BUFSIZ) { |
371655cc | 747 | amt = BUFSIZ; |
b7ff3bb3 BJ |
748 | if (i + amt > size) |
749 | amt = size - i; | |
371655cc | 750 | count += amt; |
b7ff3bb3 | 751 | do { |
371655cc | 752 | j = read(rem, cp, amt); |
9e9252a8 | 753 | if (j <= 0) { |
3eafec57 | 754 | error("rcp: %s\n", |
ef49bf4f | 755 | j ? strerror(errno) : |
d4c44137 | 756 | "dropped connection"); |
b7ff3bb3 | 757 | exit(1); |
9e9252a8 | 758 | } |
b7ff3bb3 BJ |
759 | amt -= j; |
760 | cp += j; | |
761 | } while (amt > 0); | |
371655cc | 762 | if (count == bp->cnt) { |
ef49bf4f | 763 | if (wrerr == NO && |
d4c44137 | 764 | write(ofd, bp->buf, count) != count) |
ef49bf4f | 765 | wrerr = YES; |
371655cc KM |
766 | count = 0; |
767 | cp = bp->buf; | |
768 | } | |
b7ff3bb3 | 769 | } |
ef49bf4f | 770 | if (count != 0 && wrerr == NO && |
d4c44137 | 771 | write(ofd, bp->buf, count) != count) |
ef49bf4f KB |
772 | wrerr = YES; |
773 | if (ftruncate(ofd, size)) { | |
d4c44137 | 774 | error("rcp: can't truncate %s: %s\n", np, |
ef49bf4f KB |
775 | strerror(errno)); |
776 | wrerr = DISPLAYED; | |
777 | } | |
d4c44137 | 778 | (void)close(ofd); |
35673a6d | 779 | (void)response(); |
ef49bf4f | 780 | if (setimes && wrerr == NO) { |
af86e024 | 781 | setimes = 0; |
ef49bf4f | 782 | if (utimes(np, tv) < 0) { |
af86e024 | 783 | error("rcp: can't set times on %s: %s\n", |
ef49bf4f KB |
784 | np, strerror(errno)); |
785 | wrerr = DISPLAYED; | |
786 | } | |
787 | } | |
788 | switch(wrerr) { | |
789 | case YES: | |
790 | error("rcp: %s: %s\n", np, strerror(errno)); | |
791 | break; | |
792 | case NO: | |
35673a6d | 793 | (void)write(rem, "", 1); |
ef49bf4f KB |
794 | break; |
795 | case DISPLAYED: | |
796 | break; | |
797 | } | |
b7ff3bb3 BJ |
798 | } |
799 | screwup: | |
d4c44137 | 800 | error("rcp: protocol screwup: %s\n", why); |
b7ff3bb3 BJ |
801 | exit(1); |
802 | } | |
803 | ||
35673a6d | 804 | BUF * |
371655cc | 805 | allocbuf(bp, fd, blksize) |
35673a6d | 806 | BUF *bp; |
371655cc KM |
807 | int fd, blksize; |
808 | { | |
809 | struct stat stb; | |
42029053 | 810 | size_t size; |
371655cc KM |
811 | |
812 | if (fstat(fd, &stb) < 0) { | |
ef49bf4f | 813 | error("rcp: fstat: %s\n", strerror(errno)); |
35673a6d | 814 | return(0); |
371655cc KM |
815 | } |
816 | size = roundup(stb.st_blksize, blksize); | |
817 | if (size == 0) | |
818 | size = blksize; | |
819 | if (bp->cnt < size) { | |
820 | if (bp->buf != 0) | |
821 | free(bp->buf); | |
42029053 | 822 | bp->buf = malloc(size); |
d4c44137 | 823 | if (!bp->buf) { |
371655cc | 824 | error("rcp: malloc: out of memory\n"); |
35673a6d | 825 | return(0); |
371655cc KM |
826 | } |
827 | } | |
828 | bp->cnt = size; | |
35673a6d | 829 | return(bp); |
371655cc KM |
830 | } |
831 | ||
35673a6d | 832 | /* VARARGS1 */ |
d4c44137 | 833 | error(fmt, a1, a2, a3) |
b7ff3bb3 | 834 | char *fmt; |
d4c44137 | 835 | int a1, a2, a3; |
b7ff3bb3 | 836 | { |
3eafec57 | 837 | static FILE *fp; |
35673a6d KB |
838 | |
839 | ++errs; | |
3eafec57 KB |
840 | if (!fp && !(fp = fdopen(rem, "w"))) |
841 | return; | |
842 | (void)fprintf(fp, "%c", 0x01); | |
843 | (void)fprintf(fp, fmt, a1, a2, a3); | |
844 | (void)fflush(fp); | |
35673a6d | 845 | if (!iamremote) |
3eafec57 | 846 | (void)fprintf(stderr, fmt, a1, a2, a3); |
b7ff3bb3 | 847 | } |
5f286db0 | 848 | |
d4c44137 KB |
849 | nospace() |
850 | { | |
851 | (void)fprintf(stderr, "rcp: out of memory.\n"); | |
852 | exit(1); | |
853 | } | |
854 | ||
d4c44137 | 855 | |
5f286db0 KB |
856 | usage() |
857 | { | |
35673a6d | 858 | #ifdef KERBEROS |
898015bc KM |
859 | (void)fprintf(stderr, "%s\n\t%s\n", |
860 | "usage: rcp [-k realm] [-p] f1 f2", | |
861 | "or: rcp [-k realm] [-rp] f1 ... fn directory"); | |
a678b549 | 862 | #else |
35673a6d KB |
863 | (void)fprintf(stderr, |
864 | "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); | |
a678b549 | 865 | #endif |
5f286db0 KB |
866 | exit(1); |
867 | } | |
5d178979 KF |
868 | |
869 | #ifdef KERBEROS | |
870 | old_warning(str) | |
871 | char *str; | |
872 | { | |
873 | (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); | |
874 | } | |
875 | ||
876 | int | |
877 | kerberos(host, bp, locuser, user) | |
878 | ||
879 | char **host, *bp, *locuser, *user; | |
880 | { | |
881 | struct servent *sp; | |
882 | ||
883 | again: | |
884 | if (use_kerberos) { | |
885 | rem = KSUCCESS; | |
886 | errno = 0; | |
887 | if (dest_realm == NULL) | |
888 | dest_realm = krb_realmofhost(*host); | |
889 | ||
5d178979 KF |
890 | rem = krcmd( |
891 | host, port, | |
892 | user, bp, 0, dest_realm); | |
893 | ||
894 | if (rem < 0) { | |
895 | use_kerberos = 0; | |
896 | sp = getservbyname("shell", "tcp"); | |
897 | if (sp == NULL) { | |
898 | (void)fprintf(stderr, | |
899 | "rcp: unknown service shell/tcp\n"); | |
900 | exit(1); | |
901 | } | |
902 | if (errno == ECONNREFUSED) | |
903 | old_warning( | |
904 | "remote host doesn't support Kerberos"); | |
905 | ||
906 | if (errno == ENOENT) | |
907 | old_warning( | |
908 | "Can't provide Kerberos auth data"); | |
909 | port = sp->s_port; | |
910 | goto again; | |
911 | } | |
912 | } else { | |
5d178979 KF |
913 | rem = rcmd(host, sp->s_port, locuser, user, bp, 0); |
914 | } | |
915 | return(rem); | |
916 | } | |
917 | #endif /* KERBEROS */ |