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