xref: /original-bsd/usr.bin/uucp/uucp/uucp.c (revision a8414ee1)
1 /*-
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1988 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[] = "@(#)uucp.c	5.10 (Berkeley) 04/24/91";
16 #endif /* not lint */
17 
18 #include "uucp.h"
19 #include <sys/stat.h>
20 #include "uust.h"
21 
22 /*
23  *	uucp command
24  */
25 
26 int Uid;
27 char *Ropt = " ";
28 char Path[100], Optns[10], Ename[MAXBASENAME+1];
29 char Grade = 'n';
30 #ifdef DONTCOPY
31 int Copy = 0;
32 #else !DONTCOPY
33 int Copy = 1;
34 #endif !DONTCOPY
35 char Nuser[32];
36 struct timeb Now;
37 
38 /* variables used to check if talking to more than one system. */
39 int	xsflag = -1;
40 char	xsys[MAXBASENAME+1];
41 
42 long Nbytes = 0;
43 #define MAXBYTES 50000	/* maximun number of bytes of data per C. file */
44 #define MAXCOUNT 15	/* maximun number of files per C. file */
45 
46 main(argc, argv)
47 int argc;
48 char **argv;
49 {
50 	char *sysfile1, *sysfl2;
51 	register char *cp;
52 	char file1[MAXFULLNAME], file2[MAXFULLNAME];
53 	int avoidgwd = 0, c;
54 	extern char *optarg;
55 	extern int optind;
56 
57 	strcpy(Progname, "uucp");
58 	uucpname(Myname);
59 	umask(WFMASK);
60 	Optns[0] = '-';
61 	Optns[1] = 'd';
62 #ifdef DONTCOPY
63 	Optns[2] = 'c';
64 #else !DONTCOPY
65 	Optns[2] = 'C';
66 #endif !DONTCOPY
67 	Ename[0] = Nuser[0] = Optns[3] = '\0';
68 	while((c = getopt(argc, argv, "aCcdfe:g:mn:rs:x:")) != EOF)
69 		switch(c) {
70 		case 'a':
71 			/* efficiency hack; avoid gwd call */
72 			avoidgwd = 1;
73 			break;
74 		case 'C':
75 			Copy = 1;
76 			Optns[2] = 'C';
77 			break;
78 		case 'c':
79 			Copy = 0;
80 			Optns[2] = 'c';
81 			break;
82 		case 'd':
83 			break;
84 		case 'f':
85 			Optns[1] = 'f';
86 			break;
87 		case 'e':
88 			strncpy(Ename, optarg, MAXBASENAME);
89 			break;
90 		case 'g':
91 			Grade = *optarg;
92 			break;
93 		case 'm':
94 			strcat(Optns, "m");
95 			break;
96 		case 'n':
97 			sprintf(Nuser, "%.31s", optarg);
98 			break;
99 		case 'r':
100 			Ropt = argv[optind-1];
101 			break;
102 		case 's':
103 			Spool = optarg;
104 			break;
105 		case 'x':
106 			chkdebug();
107 			Debug = atoi(optarg);
108 			if (Debug <= 0)
109 				Debug = 1;
110 			fprintf(stderr, "DEBUG %d\n", Debug);
111 			break;
112 		case '?':
113 		default:
114 			fprintf(stderr, "unknown flag %s\n", argv[optind-1]);
115 			break;
116 		}
117 
118 	DEBUG(4, "\n\n** %s **\n", "START");
119 	if (!avoidgwd) {
120 		cp = getwd(Wrkdir);
121 		if (cp == NULL) {
122 			syslog(LOG_WARNING, "getwd failed");
123 			cleanup(1);
124 		}
125 	}
126 	if (subchdir(Spool) < 0) {
127 		syslog(LOG_WARNING, "chdir(%s) failed: %m", Spool);
128 		cleanup(1);
129 	}
130 
131 	Uid = getuid();
132 	if (guinfo(Uid, User, Path) != SUCCESS) {
133 		syslog(LOG_WARNING, "Can't find username for uid %d", Uid);
134 		DEBUG(1, "Using username", "uucp");
135 		strcpy(User, "uucp");
136 	}
137 	DEBUG(4, "UID %d, ", Uid);
138 	DEBUG(4, "User %s,", User);
139 	DEBUG(4, "Ename (%s) ", Ename);
140 	DEBUG(4, "PATH %s\n", Path);
141 	if (optind > (argc-2)) {
142 		fprintf(stderr, "usage: uucp [flags] from... to\n");
143 		cleanup(1);
144 	}
145 
146 
147 	/*  set up "to" system and file names  */
148 	if ((cp = index(argv[--argc], '!')) != NULL) {
149 		sysfl2 = argv[argc];
150 		*cp = '\0';
151 		if (*sysfl2 == '\0')
152 			sysfl2 = Myname;
153 		else
154 			strncpy(Rmtname, sysfl2, MAXBASENAME);
155 		if (versys(&sysfl2) != 0) {
156 			fprintf(stderr, "bad system name: %s\n", sysfl2);
157 			cleanup(1);
158 		}
159 		if (Rmtname[0] != '\0')
160 			strncpy(Rmtname, sysfl2, MAXBASENAME);
161 		/* block multi-hop requests immediately */
162 		if (index(cp+1, '!') != NULL) {
163 			fprintf(stderr, "uucp handles only adjacent sites.\n");
164 			fprintf(stderr, "Try uusend for multi-hop delivery.\n");
165 			cleanup(1);
166 		}
167 		strcpy(file2, cp + 1);
168 	} else {
169 		sysfl2 = Myname;
170 		strcpy(file2, argv[argc]);
171 	}
172 	if (strlen(sysfl2) > MAXBASENAME)
173 		sysfl2[MAXBASENAME] = '\0';
174 
175 
176 	/*  do each from argument  */
177 	while (optind < argc) {
178 		if ((cp = index(argv[optind], '!')) != NULL) {
179 			sysfile1 = argv[optind];
180 			*cp = '\0';
181 			if (strlen(sysfile1) > MAXBASENAME)
182 				sysfile1[MAXBASENAME] = '\0';
183 			if (*sysfile1 == '\0')
184 				sysfile1 = Myname;
185 			else
186 				strncpy(Rmtname, sysfile1, MAXBASENAME);
187 			if (versys(&sysfile1) != 0) {
188 				fprintf(stderr, "bad system name: %s\n", sysfile1);
189 				cleanup(1);
190 			}
191 			if (Rmtname[0] != '\0')
192 				strncpy(Rmtname, sysfl2, MAXBASENAME);
193 			strcpy(file1, cp + 1);
194 		} else {
195 			sysfile1 = Myname;
196 			strcpy(file1, argv[optind]);
197 		}
198 		DEBUG(4, "file1 - %s\n", file1);
199 		copy(sysfile1, file1, sysfl2, file2);
200 		optind++;
201 	}
202 
203 	clscfile();
204 	if (*Ropt != '-' && xsflag >= 0)
205 		xuucico(xsys);
206 	cleanup(0);
207 }
208 
209 cleanup(code)
210 int code;
211 {
212 	logcls();
213 	rmlock(CNULL);
214 	if (code)
215 		fprintf(stderr, "uucp failed. code %d\n", code);
216 	exit(code);
217 }
218 
219 
220 /*
221  *	generate copy files
222  *
223  *	return codes 0  |  FAIL
224  */
225 
226 copy(s1, f1, s2, f2)
227 register char *s1, *f1, *s2, *f2;
228 {
229 	int type, statret;
230 	struct stat stbuf, stbuf1;
231 	char dfile[NAMESIZE];
232 	char file1[MAXFULLNAME], file2[MAXFULLNAME];
233 	FILE *cfp, *gtcfile();
234 	char opts[100];
235 
236 	type = 0;
237 	opts[0] = '\0';
238 	strcpy(file1, f1);
239 	strcpy(file2, f2);
240 	if (strcmp(s1, Myname) != SAME)
241 		type = 1;
242 	if (strcmp(s2, Myname) != SAME)
243 		type += 2;
244 	if (type & 01)
245 		if ((index(f1, '*') != NULL
246 		  || index(f1, '?') != NULL
247 		  || index(f1, '[') != NULL))
248 			type = 4;
249 
250 	switch (type) {
251 	case 0:
252 		/* all work here */
253 		DEBUG(4, "all work here %d\n", type);
254 		if (ckexpf(file1))
255 			 return FAIL;
256 		if (ckexpf(file2))
257 			 return FAIL;
258 		if (stat(subfile(file1), &stbuf) != 0) {
259 			fprintf(stderr, "can't get file status %s \n copy failed\n",
260 			  file1);
261 			return SUCCESS;
262 		}
263 		statret = stat(subfile(file2), &stbuf1);
264 		if (statret == 0
265 		  && stbuf.st_ino == stbuf1.st_ino
266 		  && stbuf.st_dev == stbuf1.st_dev) {
267 			fprintf(stderr, "%s %s - same file; can't copy\n", file1, file2);
268 			return SUCCESS;
269 		}
270 		if (chkpth(User, "", file1) != 0
271 		  || chkperm(file2, index(Optns, 'd'))
272 		  || chkpth(User, "", file2) != 0) {
273 			fprintf(stderr, "permission denied\n");
274 			cleanup(1);
275 		}
276 		if ((stbuf.st_mode & ANYREAD) == 0) {
277 			fprintf(stderr, "can't read file (%s) mode (%o)\n",
278 			  file1, (int)stbuf.st_mode);
279 			return FAIL;
280 		}
281 		if (statret == 0 && (stbuf1.st_mode & ANYWRITE) == 0) {
282 			fprintf(stderr, "can't write file (%s) mode (%o)\n",
283 			  file2, (int)stbuf.st_mode);
284 			return FAIL;
285 		}
286 		xcp(file1, file2);
287 		/* With odd umask() might not be able to read it himself */
288 		(void) chmod(file2, 0666);
289 		logent("WORK HERE", "DONE");
290 		return SUCCESS;
291 	case 1:
292 		/* receive file */
293 		DEBUG(4, "receive file - %d\n", type);
294 		chsys(s1);
295 		if (file1[0] != '~')
296 			if (ckexpf(file1))
297 				 return FAIL;
298 		if (ckexpf(file2))
299 			 return FAIL;
300 		if (chkpth(User, "", file2) != 0) {
301 			fprintf(stderr, "permission denied\n");
302 			return FAIL;
303 		}
304 		if (Ename[0] != '\0') {
305 			/* execute uux - remote uucp */
306 			xuux(Ename, s1, file1, s2, file2, opts);
307 			return SUCCESS;
308 		}
309 
310 		cfp = gtcfile(s1);
311 		fprintf(cfp, "R %s %s %s %s\n", file1, file2, User, Optns);
312 		break;
313 	case 2:
314 		/* send file */
315 		if (ckexpf(file1))
316 			 return FAIL;
317 		if (file2[0] != '~')
318 			if (ckexpf(file2))
319 				 return FAIL;
320 		DEBUG(4, "send file - %d\n", type);
321 		chsys(s2);
322 
323 		if (chkpth(User, "", file1) != 0) {
324 			fprintf(stderr, "permission denied %s\n", file1);
325 			return FAIL;
326 		}
327 		if (stat(subfile(file1), &stbuf) != 0) {
328 			fprintf(stderr, "can't get status for file %s\n", file1);
329 			return FAIL;
330 		}
331 		if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
332 			fprintf(stderr, "directory name illegal - %s\n",
333 			  file1);
334 			return FAIL;
335 		}
336 		if ((stbuf.st_mode & ANYREAD) == 0) {
337 			fprintf(stderr, "can't read file (%s) mode (%o)\n",
338 			  file1, (int)stbuf.st_mode);
339 			return FAIL;
340 		}
341 		if ((Nuser[0] != '\0') && (index(Optns, 'n') == NULL))
342 			strcat(Optns, "n");
343 		if (Ename[0] != '\0') {
344 			/* execute uux - remote uucp */
345 			if (Nuser[0] != '\0')
346 				sprintf(opts, "-n%s", Nuser);
347 			xuux(Ename, s1, file1, s2, file2, opts);
348 			return SUCCESS;
349 		}
350 		Nbytes +=  stbuf.st_size;
351 		if (Copy) {
352 			gename(DATAPRE, Myname, Grade, dfile);
353 			if (xcp(file1, dfile) != 0) {
354 				fprintf(stderr, "can't copy %s\n", file1);
355 				return FAIL;
356 			}
357 		}
358 		else {
359 			/* make a dummy D. name */
360 			/* cntrl.c knows names < 6 chars are dummy D. files */
361 			strcpy(dfile, "D.0");
362 		}
363 		cfp = gtcfile(s2);
364 		fprintf(cfp, "S %s %s %s %s %s %o %s\n", file1, file2,
365 			User, Optns, dfile, (int)stbuf.st_mode & 0777, Nuser);
366 		break;
367 	case 3:
368 	case 4:
369 		/*  send uucp command for execution on s1  */
370 		DEBUG(4, "send uucp command - %d\n", type);
371 		chsys(s1);
372 		if (strcmp(s2,  Myname) == SAME) {
373 			if (ckexpf(file2))
374 				 return FAIL;
375 			if (chkpth(User, "", file2) != 0) {
376 				fprintf(stderr, "permission denied\n");
377 				return FAIL;
378 			}
379 		}
380 		if (Ename[0] != '\0') {
381 			/* execute uux - remote uucp */
382 			xuux(Ename, s1, file1, s2, file2, opts);
383 			return SUCCESS;
384 		}
385 		cfp = gtcfile(s1);
386 		fprintf(cfp, "X %s %s!%s %s %s\n", file1, s2, file2, User, Optns);
387 		break;
388 	}
389 	return SUCCESS;
390 }
391 
392 /*
393  *	execute uux for remote uucp
394  *
395  *	return code - none
396  */
397 
398 xuux(ename, s1, f1, s2, f2, opts)
399 char *ename, *s1, *s2, *f1, *f2, *opts;
400 {
401 	char cmd[200];
402 
403 	DEBUG(4, "Ropt(%s) ", Ropt);
404 	DEBUG(4, "ename(%s) ", ename);
405 	DEBUG(4, "s1(%s) ", s1);
406 	DEBUG(4, "f1(%s) ", f1);
407 	DEBUG(4, "s2(%s) ", s2);
408 	DEBUG(4, "f2(%s)\n", f2);
409 	sprintf(cmd, "uux %s %s!uucp %s %s!%s \\(%s!%s\\)",
410 	 Ropt, ename, opts,  s1, f1, s2, f2);
411 	DEBUG(4, "cmd (%s)\n", cmd);
412 	system(cmd);
413 	return;
414 }
415 
416 FILE *Cfp = NULL;
417 char Cfile[NAMESIZE];
418 
419 /*
420  *	get a Cfile descriptor
421  *
422  *	return an open file descriptor
423  */
424 
425 FILE *
426 gtcfile(sys)
427 register char *sys;
428 {
429 	static char presys[8] = "";
430 	static int cmdcount = 0;
431 	register int savemask;
432 
433 	if (strcmp(presys, sys) != SAME  /* this is !SAME on first call */
434 	  || Nbytes > MAXBYTES
435 	  || ++cmdcount > MAXCOUNT) {
436 		cmdcount = 1;
437 		Nbytes = 0;
438 		if (presys[0] != '\0') {
439 			clscfile();
440 		}
441 		gename(CMDPRE, sys, Grade, Cfile);
442 #ifdef VMS
443 		savemask = umask(~0600); /* vms must have read permission */
444 #else !VMS
445 		savemask = umask(~0200);
446 #endif !VMS
447 		Cfp = fopen(subfile(Cfile), "w");
448 		umask(savemask);
449 		if (Cfp == NULL) {
450 			syslog(LOG_WARNING, "fopen(%s) failed: %m",
451 				subfile(Cfile));
452 			cleanup(1);
453 		}
454 		strcpy(presys, sys);
455 	}
456 	return Cfp;
457 }
458 
459 /*
460  *	close cfile
461  *
462  *	return code - none
463  */
464 
465 clscfile()
466 {
467 	if (Cfp == NULL)
468 		return;
469 	fclose(Cfp);
470 	chmod(subfile(Cfile), ~WFMASK & 0777);
471 	logent(Cfile, "QUE'D");
472 	US_CRS(Cfile);
473 	Cfp = NULL;
474 }
475 
476 /*
477  * compile a list of all systems we are referencing
478  */
479 chsys(s1)
480 register char *s1;
481 {
482 	if (xsflag < 0)
483 		xsflag = 0;
484 	else if (xsflag > 0)
485 		return;
486 
487 	if (xsys[0] == '\0') {
488 		strncpy(xsys, s1, MAXBASENAME);
489 		return;
490 	}
491 
492 	if (strncmp(xsys, s1, MAXBASENAME) == SAME)
493 		return;
494 
495 	xsflag++;
496 	xsys[0] = '\0';
497 }
498