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