xref: /original-bsd/usr.bin/uucp/uusend/uusend.c (revision 93ab02a6)
1 /*-
2  * Copyright (c) 1980, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980, 1991 The Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)uusend.c	5.4 (Berkeley) 04/24/91";
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 
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 *
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 *
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
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