Commit | Line | Data |
---|---|---|
877b2bc4 | 1 | #ifndef lint |
46b15d8a | 2 | static char sccsid[] = "@(#)uusend.c 5.2 (Berkeley) %G%"; |
877b2bc4 SL |
3 | #endif |
4 | ||
5 | /* | |
6 | * uusend: primitive operation to allow uucp like copy of binary files | |
7 | * but handle indirection over systems. | |
8 | * | |
9 | * usage: uusend [-r] [-m ooo] localfile sysname1!sysname2!...!destfile | |
10 | * uusend [-r] [-m ooo] - sysname1!sysname2!...!destfile | |
11 | * | |
12 | * Author: Mark Horton, May 1980. | |
13 | * | |
14 | * "-r" switch added. Has same effect as "-r" in uux. 11/82 CCW | |
15 | * | |
16 | * Error recovery (a la uucp) added & ifdefs for ruusend (as in rmail). | |
17 | * Checks for illegal access to /usr/lib/uucp. | |
18 | * February 1983 Christopher Woodbury | |
19 | * Fixed mode set[ug]id loophole. 4/8/83 CCW | |
20 | * | |
21 | * Add '-f' to make uusend syntax more similar to UUCP. "destname" | |
22 | * can now be a directory. June 1983 CCW | |
23 | */ | |
24 | ||
25 | #include <stdio.h> | |
26 | #include <pwd.h> | |
27 | #include <sys/types.h> | |
28 | #include <sys/stat.h> | |
29 | ||
46b15d8a RC |
30 | /* |
31 | * define RECOVER to permit requests like 'uusend file sys1!sys2!~uucp' | |
32 | * (abbreviation for 'uusend file sys1!sys2!~uucp/file'). | |
33 | * define DEBUG to keep log of uusend uusage. | |
34 | * define RUUSEND if neighboring sites permit 'ruusend', | |
35 | * which they certainly should to avoid security holes | |
36 | */ | |
877b2bc4 | 37 | #define RECOVER |
46b15d8a | 38 | /*#define DEBUG "/usr/spool/uucp/uusend.log"/**/ |
877b2bc4 SL |
39 | |
40 | FILE *in, *out; | |
41 | FILE *dout; | |
42 | ||
46b15d8a RC |
43 | extern FILE *popen(); |
44 | extern char *index(), *strcpy(), *strcat(), *ctime(); | |
877b2bc4 SL |
45 | |
46 | #ifdef RUUSEND | |
47 | int rsend; | |
46b15d8a | 48 | #endif RUUSEND |
877b2bc4 SL |
49 | int mode = -1; /* mode to chmod new file to */ |
50 | char *nextsys; /* next system in the chain */ | |
51 | char dnbuf[200]; /* buffer for result of ~user/file */ | |
52 | char cmdbuf[256]; /* buffer to build uux command in */ | |
53 | char *rflg = ""; /* default value of rflg ccw -- 1 Nov '82 */ | |
54 | ||
55 | struct passwd *user; /* entry in /etc/passwd for ~user */ | |
56 | struct passwd *getpwnam(); | |
57 | struct stat stbuf; | |
58 | ||
59 | char *excl; /* location of first ! in destname */ | |
60 | char *sl; /* location of first / in destname */ | |
61 | char *sourcename; /* argv[1] */ | |
62 | char *destname; /* argv[2] */ | |
63 | char *UULIB = "/usr/lib/uucp"; /* UUCP lib directory */ | |
64 | ||
65 | #ifdef RECOVER | |
66 | char *UUPUB = "/usr/spool/uucppublic/"; /* public UUCP directory */ | |
67 | char *filename; /* file name from end of destname */ | |
68 | char *getfname(); /* routine to get filename from destname */ | |
69 | int fflg; | |
70 | char f[100]; /* name of default output file */ | |
46b15d8a | 71 | #else !RECOVER |
877b2bc4 | 72 | char *f = ""; /* so we waste a little space */ |
46b15d8a | 73 | #endif !RECOVER |
877b2bc4 SL |
74 | |
75 | main(argc, argv) | |
76 | int argc; | |
77 | char **argv; | |
78 | { | |
79 | register int c; | |
46b15d8a RC |
80 | long count; |
81 | extern char **environ; | |
877b2bc4 SL |
82 | |
83 | #ifdef DEBUG | |
84 | long t; | |
46b15d8a | 85 | umask(022); |
877b2bc4 SL |
86 | dout = fopen(DEBUG, "a"); |
87 | if (dout == NULL) { | |
88 | printf("Cannot append to %s\n", DEBUG); | |
89 | exit(1); | |
90 | } | |
91 | freopen(DEBUG, "a", stdout); | |
877b2bc4 SL |
92 | fprintf(dout, "\nuusend run: "); |
93 | for (c=0; c<argc; c++) | |
94 | fprintf(dout, "%s ", argv[c]); | |
95 | time(&t); | |
96 | fprintf(dout, "%s", ctime(&t)); | |
46b15d8a | 97 | #endif DEBUG |
877b2bc4 SL |
98 | |
99 | #ifdef RUUSEND | |
100 | if(argv[0][0] == 'r') | |
101 | rsend++; | |
46b15d8a | 102 | #endif RUUSEND |
877b2bc4 SL |
103 | while (argc > 1 && argv[1][0] == '-' && argv[1][1]) { |
104 | switch(argv[1][1]) { | |
105 | case 'm': | |
106 | sscanf(argv[2], "%o", &mode); | |
107 | mode &= 0777; /* fix set[ug]id loophole */ | |
108 | argc--; argv++; | |
109 | break; | |
110 | case 'r': /* -r flag for uux */ | |
111 | rflg = "-r "; | |
112 | break; | |
113 | #ifdef RECOVER | |
114 | case 'f': | |
115 | fflg++; | |
116 | strcpy(f, argv[1]); | |
117 | break; | |
46b15d8a | 118 | #endif RECOVER |
877b2bc4 SL |
119 | default: |
120 | fprintf(stderr, "Bad flag: %s\n", argv[1]); | |
121 | break; | |
122 | } | |
123 | argc--; argv++; | |
124 | } | |
125 | ||
126 | if (argc != 3) { | |
127 | fprintf(stderr, "Usage: uusend [-m ooo] [-r] -/file sys!sys!..!rfile\n"); | |
128 | exit(1); | |
129 | } | |
130 | ||
131 | sourcename = argv[1]; | |
132 | destname = argv[2]; | |
133 | ||
134 | if (sourcename[0] == '-') | |
135 | in = stdin; | |
136 | else { | |
137 | #ifdef RUUSEND | |
138 | if (rsend) { | |
139 | fprintf(stderr, "illegal input\n"); | |
140 | exit(2); | |
141 | } | |
46b15d8a | 142 | #endif RUUSEND |
877b2bc4 SL |
143 | in = fopen(sourcename, "r"); |
144 | if (in == NULL) { | |
145 | perror(argv[1]); | |
146 | exit(2); | |
147 | } | |
148 | if (!fflg || f[2] == '\0') { | |
149 | strcpy(f, "-f"); | |
150 | strcat(f, getfname(sourcename)); | |
151 | fflg++; | |
152 | } | |
153 | } | |
154 | ||
155 | excl = index(destname, '!'); | |
156 | if (excl) { | |
157 | /* | |
158 | * destname is on a remote system. | |
159 | */ | |
160 | nextsys = destname; | |
161 | *excl++ = 0; | |
162 | destname = excl; | |
163 | if (mode < 0) { | |
164 | fstat(fileno(in), &stbuf); | |
165 | mode = stbuf.st_mode & 0777; | |
166 | } | |
167 | #ifdef RUUSEND | |
46b15d8a RC |
168 | sprintf(cmdbuf,"uux -gn -z %s- \"%s!ruusend %s -m %o - (%s)\"", |
169 | #else !RUUSEND | |
170 | sprintf(cmdbuf, "uux -gn -z %s- \"%s!uusend %s -m %o - (%s)\"", | |
171 | #endif !RUUSEND | |
877b2bc4 SL |
172 | rflg, nextsys, f, mode, destname); |
173 | #ifdef DEBUG | |
174 | fprintf(dout, "remote: nextsys='%s', destname='%s', cmd='%s'\n", nextsys, destname, cmdbuf); | |
46b15d8a | 175 | #endif DEBUG |
877b2bc4 SL |
176 | out = popen(cmdbuf, "w"); |
177 | } else { | |
178 | /* | |
179 | * destname is local. | |
180 | */ | |
181 | if (destname[0] == '~') { | |
182 | #ifdef DEBUG | |
183 | fprintf(dout, "before ~: '%s'\n", destname); | |
184 | fflush(dout); | |
46b15d8a | 185 | #endif DEBUG |
877b2bc4 SL |
186 | sl = index(destname, '/'); |
187 | #ifdef RECOVER | |
188 | if (sl == NULL && !fflg) { | |
189 | fprintf(stderr, "Illegal ~user\n"); | |
190 | exit(3); | |
191 | } | |
192 | for (sl = destname; *sl != '\0'; sl++) | |
193 | ; /* boy, is this a hack! */ | |
46b15d8a | 194 | #else !RECOVER |
877b2bc4 SL |
195 | if (sl == NULL) { |
196 | fprintf(stderr, "Illegal ~user\n"); | |
197 | exit(3); | |
198 | } | |
199 | *sl++ = 0; | |
46b15d8a | 200 | #endif !RECOVER |
877b2bc4 SL |
201 | user = getpwnam(destname+1); |
202 | if (user == NULL) { | |
203 | fprintf(stderr, "No such user as %s\n", | |
204 | destname); | |
205 | #ifdef RECOVER | |
206 | if ((filename =getfname(sl)) == NULL && | |
207 | !fflg) | |
208 | exit(4); | |
209 | strcpy(dnbuf, UUPUB); | |
210 | if (fflg) | |
211 | strcat(dnbuf, &f[2]); | |
212 | else | |
213 | strcat(dnbuf, filename); | |
214 | } | |
215 | else { | |
216 | strcpy(dnbuf, user->pw_dir); | |
217 | strcat(dnbuf, "/"); | |
218 | strcat(dnbuf, sl); | |
219 | } | |
46b15d8a | 220 | #else !RECOVER |
877b2bc4 SL |
221 | exit(4); |
222 | } | |
223 | strcpy(dnbuf, user->pw_dir); | |
224 | strcat(dnbuf, "/"); | |
225 | strcat(dnbuf, sl); | |
46b15d8a | 226 | #endif !RECOVER |
877b2bc4 SL |
227 | destname = dnbuf; |
228 | } | |
229 | #ifdef RECOVER | |
230 | else | |
231 | destname = strcpy(dnbuf, destname); | |
46b15d8a | 232 | #endif !RECOVER |
877b2bc4 SL |
233 | if(strncmp(UULIB, destname, strlen(UULIB)) == 0) { |
234 | fprintf(stderr, "illegal file: %s", destname); | |
235 | exit(4); | |
236 | } | |
237 | #ifdef RECOVER | |
238 | if (stat(destname, &stbuf) == 0 && | |
239 | (stbuf.st_mode & S_IFMT) == S_IFDIR && | |
240 | fflg) { | |
46b15d8a RC |
241 | strcat(destname, "/"); |
242 | strcat(destname, &f[2]); | |
877b2bc4 | 243 | } |
46b15d8a | 244 | #endif RECOVER |
877b2bc4 SL |
245 | out = fopen(destname, "w"); |
246 | #ifdef DEBUG | |
247 | fprintf(dout, "local, file='%s'\n", destname); | |
46b15d8a | 248 | #endif DEBUG |
877b2bc4 SL |
249 | if (out == NULL) { |
250 | perror(destname); | |
251 | #ifdef RECOVER | |
252 | if (strncmp(destname,UUPUB,strlen(UUPUB)) == 0) | |
253 | exit(5); /* forget it! */ | |
254 | filename = getfname(destname); | |
255 | if (destname == dnbuf) /* cmdbuf is scratch */ | |
256 | filename = strcpy(cmdbuf, filename); | |
257 | destname = strcpy(dnbuf, UUPUB); | |
258 | if (user != NULL) { | |
259 | strcat(destname, user->pw_name); | |
260 | if (stat(destname, &stbuf) == -1) { | |
46b15d8a | 261 | mkdir(destname, 0777); |
877b2bc4 SL |
262 | } |
263 | strcat(destname, "/"); | |
264 | } | |
877b2bc4 SL |
265 | if (fflg) |
266 | strcat(destname, &f[2]); | |
267 | else | |
268 | strcat(destname, filename); | |
877b2bc4 SL |
269 | if ((out = fopen(destname, "w")) == NULL) |
270 | exit(5); /* all for naught! */ | |
46b15d8a | 271 | #else !RECOVER |
877b2bc4 | 272 | exit(5); |
46b15d8a | 273 | #endif !RECOVER |
877b2bc4 SL |
274 | } |
275 | if (mode > 0) | |
276 | chmod(destname, mode); /* don't bother to check it */ | |
277 | } | |
278 | ||
279 | /* | |
280 | * Now, in any case, copy from in to out. | |
281 | */ | |
282 | ||
46b15d8a | 283 | count = 0; |
877b2bc4 SL |
284 | while ((c=getc(in)) != EOF) { |
285 | putc(c, out); | |
286 | count++; | |
287 | } | |
288 | #ifdef DEBUG | |
289 | fprintf(dout, "count %ld bytes\n", count); | |
290 | fclose(dout); | |
46b15d8a RC |
291 | #endif DEBUG |
292 | ||
877b2bc4 SL |
293 | fclose(in); |
294 | fclose(out); /* really should pclose in that case */ | |
295 | exit(0); | |
296 | } | |
297 | ||
298 | /* | |
299 | * Return the ptr in sp at which the character c appears; | |
300 | * NULL if not found. Included so I don't have to fight the | |
301 | * index/strchr battle. | |
302 | */ | |
303 | ||
304 | #define NULL 0 | |
305 | ||
306 | char * | |
307 | index(sp, c) | |
308 | register char *sp, c; | |
309 | { | |
310 | do { | |
311 | if (*sp == c) | |
312 | return(sp); | |
313 | } while (*sp++); | |
314 | return(NULL); | |
315 | } | |
316 | ||
317 | #ifdef RECOVER | |
318 | char * | |
319 | getfname(p) | |
320 | register char *p; | |
321 | { | |
322 | register char *s; | |
323 | s = p; | |
324 | while (*p != '\0') | |
325 | p++; | |
326 | if (p == s) | |
327 | return (NULL); | |
328 | for (;p != s; p--) | |
329 | if (*p == '/') { | |
330 | p++; | |
331 | break; | |
332 | } | |
333 | return (p); | |
334 | } | |
335 | ||
46b15d8a RC |
336 | #ifndef BSD4_2 |
337 | makedir(dirname, mode) | |
877b2bc4 | 338 | char *dirname; |
46b15d8a | 339 | int mode; |
877b2bc4 SL |
340 | { |
341 | register int pid; | |
342 | int retcode, status; | |
343 | switch ((pid = fork())) { | |
344 | case -1: /* error */ | |
345 | return (-1); | |
877b2bc4 SL |
346 | case 0: /* child */ |
347 | umask(0); | |
46b15d8a | 348 | execl("/bin/mkdir", "mkdir", dirname, (char *)0); |
877b2bc4 | 349 | exit(1); |
46b15d8a | 350 | /* NOTREACHED */ |
877b2bc4 SL |
351 | default: /* parent */ |
352 | while ((retcode=wait(&status)) != pid && retcode != -1) | |
353 | ; | |
354 | if (retcode == -1) | |
46b15d8a RC |
355 | return -1; |
356 | else { | |
357 | chmod(dirname, mode); | |
358 | return status; | |
359 | } | |
877b2bc4 | 360 | } |
46b15d8a | 361 | /* NOTREACHED */ |
877b2bc4 | 362 | } |
46b15d8a RC |
363 | #endif !BSD4_2 |
364 | #endif RECOVER |