1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 #include "uucp.h"
30
31 /*
32 * uucp
33 * user id
34 * make a copy in spool directory
35 */
36 int Copy = 0;
37 static int _Transfer = 0;
38 char Nuser[32];
39 char *Ropt = " ";
40 char Optns[10];
41 char Uopts[BUFSIZ];
42 char Xopts[BUFSIZ];
43 char Sgrade[NAMESIZE];
44 int Mail = 0;
45 int Notify = 0;
46
47 void cleanup(), ruux(), usage();
48 int eaccess(), guinfo(), vergrd(), gwd(), ckexpf(), uidstat(), uidxcp(),
49 copy(), gtcfile();
50 void commitall(), wfabort(), mailst(), gename(), svcfile();
51
52 char Sfile[MAXFULLNAME];
53
54 int
main(argc,argv,envp)55 main(argc, argv, envp)
56 int argc;
57 char *argv[];
58 char **envp;
59 {
60 char *jid();
61 int ret;
62 int errors = 0;
63 char *fopt, *sys2p;
64 char sys1[MAXFULLNAME], sys2[MAXFULLNAME];
65 char fwd1[MAXFULLNAME], fwd2[MAXFULLNAME];
66 char file1[MAXFULLNAME], file2[MAXFULLNAME];
67 short jflag = 0; /* -j flag Jobid printout */
68 extern int split();
69
70
71 /* Set locale environment variables local definitions */
72 (void) setlocale(LC_ALL, "");
73 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
74 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
75 #endif
76 (void) textdomain(TEXT_DOMAIN);
77
78 /* this fails in some versions, but it doesn't hurt */
79 Uid = getuid();
80 Euid = geteuid();
81 if (Uid == 0)
82 (void) setuid(UUCPUID);
83
84 /* choose LOGFILE */
85 (void) strcpy(Logfile, LOGUUCP);
86
87 Env = envp;
88 fopt = NULL;
89 (void) strcpy(Progname, "uucp");
90 Pchar = 'U';
91 *Uopts = NULLCHAR;
92 *Xopts = NULLCHAR;
93 *Sgrade = NULLCHAR;
94
95 if (eaccess(GRADES, 0) != -1) {
96 Grade = 'A';
97 Sgrades = TRUE;
98 sprintf(Sgrade, "%s", "default");
99 }
100
101 /*
102 * find name of local system
103 */
104 uucpname(Myname);
105 Optns[0] = '-';
106 Optns[1] = 'd';
107 Optns[2] = 'c';
108 Optns[3] = Nuser[0] = Sfile[0] = NULLCHAR;
109
110 /*
111 * find id of user who spawned command to
112 * determine
113 */
114 (void) guinfo(Uid, User);
115
116 /*
117 * create/append command log
118 */
119 commandlog(argc,argv);
120
121 while ((ret = getopt(argc, argv, "Ccdfg:jmn:rs:x:")) != EOF) {
122 switch (ret) {
123
124 /*
125 * make a copy of the file in the spool
126 * directory.
127 */
128 case 'C':
129 Copy = 1;
130 Optns[2] = 'C';
131 break;
132
133 /*
134 * not used (default)
135 */
136 case 'c':
137 break;
138
139 /*
140 * not used (default)
141 */
142 case 'd':
143 break;
144 case 'f':
145 Optns[1] = 'f';
146 break;
147
148 /*
149 * set service grade
150 */
151 case 'g':
152 snprintf(Xopts, sizeof (Xopts), "-g%s", optarg);
153 if (!Sgrades) {
154 if (strlen(optarg) < (size_t)2 && isalnum(*optarg))
155 Grade = *optarg;
156 else {
157 (void) fprintf(stderr, gettext("No"
158 " administrator defined service"
159 " grades available on this"
160 " machine.\n"));
161 (void) fprintf(stderr, gettext("UUCP"
162 " service grades range from"
163 " [A-Z][a-z] only.\n"));
164 cleanup(-1);
165 }
166 }
167 else {
168 (void) strncpy(Sgrade, optarg, NAMESIZE-1);
169 Sgrade[NAMESIZE-1] = NULLCHAR;
170 if (vergrd(Sgrade) != SUCCESS)
171 cleanup(FAIL);
172 }
173 break;
174
175 case 'j': /* job id */
176 jflag = 1;
177 break;
178
179 /*
180 * send notification to local user
181 */
182 case 'm':
183 Mail = 1;
184 (void) strcat(Optns, "m");
185 break;
186
187 /*
188 * send notification to user on remote
189 * if no user specified do not send notification
190 */
191 case 'n':
192 /*
193 * We should add "n" option to Optns only once,
194 * even if multiple -n option are passed to uucp
195 */
196 if (!Notify) {
197 (void) strlcat(Optns, "n", sizeof (Optns));
198 Notify = 1;
199 }
200 (void) sprintf(Nuser, "%.8s", optarg);
201
202 /*
203 * We do the copy multiple times when multiple
204 * -n options are specified, but
205 * only the last -n value is used.
206 */
207 (void) snprintf(Uopts, sizeof (Uopts), "-n%s ", Nuser);
208
209 break;
210
211 /*
212 * create JCL files but do not start uucico
213 */
214 case 'r':
215 Ropt = "-r";
216 break;
217
218 /*
219 * return status file
220 */
221 case 's':
222 fopt = optarg;
223 /* "m" needed for compatability */
224 (void) strcat(Optns, "mo");
225 break;
226
227 /*
228 * turn on debugging
229 */
230 case 'x':
231 Debug = atoi(optarg);
232 if (Debug <= 0)
233 Debug = 1;
234 #ifdef SMALL
235 fprintf(stderr, gettext("WARNING: uucp built with SMALL"
236 " flag defined -- no debug info available\n"));
237 #endif /* SMALL */
238 break;
239
240 default:
241 usage();
242 break;
243 }
244 }
245 DEBUG(4, "\n\n** %s **\n", "START");
246 gwd(Wrkdir);
247 if (fopt) {
248 if (*fopt != '/')
249 (void) snprintf(Sfile, MAXFULLNAME, "%s/%s",
250 Wrkdir, fopt);
251 else
252 (void) snprintf(Sfile, MAXFULLNAME, "%s", fopt);
253
254 }
255 else
256 if (strlcpy(Sfile, "dummy", sizeof (Sfile)) >= sizeof (Sfile))
257 return (2);
258
259 /*
260 * work in WORKSPACE directory
261 */
262 ret = chdir(WORKSPACE);
263 if (ret != 0) {
264 (void) fprintf(stderr, gettext("No work directory - %s -"
265 " get help\n"), WORKSPACE);
266 cleanup(-12);
267 }
268
269 if (Nuser[0] == NULLCHAR)
270 (void) strcpy(Nuser, User);
271 (void) strcpy(Loginuser, User);
272 DEBUG(4, "UID %ld, ", (long) Uid);
273 DEBUG(4, "User %s\n", User);
274 if (argc - optind < 2) {
275 usage();
276 }
277
278 /*
279 * set up "to" system and file names
280 */
281
282 (void) split(argv[argc - 1], sys2, fwd2, file2);
283 if (*sys2 != NULLCHAR) {
284 (void) strncpy(Rmtname, sys2, MAXBASENAME);
285 Rmtname[MAXBASENAME] = NULLCHAR;
286
287 /* get real Myname - it depends on who I'm calling--Rmtname */
288 (void) mchFind(Rmtname);
289 myName(Myname);
290
291 if (versys(sys2) != 0) {
292 (void) fprintf(stderr,
293 gettext("bad system: %s\n"), sys2);
294 cleanup(-EX_NOHOST);
295 }
296 }
297
298 DEBUG(9, "sys2: %s, ", sys2);
299 DEBUG(9, "fwd2: %s, ", fwd2);
300 DEBUG(9, "file2: %s\n", file2);
301
302 /*
303 * if there are more than 2 argsc, file2 is a directory
304 */
305 if (argc - optind > 2)
306 (void) strcat(file2, "/");
307
308 /*
309 * do each from argument
310 */
311
312 for ( ; optind < argc - 1; optind++) {
313 (void) split(argv[optind], sys1, fwd1, file1);
314 if (*sys1 != NULLCHAR) {
315 if (versys(sys1) != 0) {
316 (void) fprintf(stderr,
317 gettext("bad system: %s\n"), sys1);
318 cleanup(-EX_NOHOST);
319 }
320 }
321
322 /* source files can have at most one ! */
323 if (*fwd1 != NULLCHAR) {
324 /* syntax error */
325 (void) fprintf(stderr,
326 gettext("illegal syntax %s\n"), argv[optind]);
327 exit(2);
328 }
329
330 /*
331 * check for required remote expansion of file names -- generate
332 * and execute a uux command
333 * e.g.
334 * uucp owl!~/dan/.. ~/dan/
335 *
336 * NOTE: The source file part must be full path name.
337 * If ~ it will be expanded locally - it assumes the remote
338 * names are the same.
339 */
340
341 if (*sys1 != NULLCHAR)
342 if ((strchr(file1, '*') != NULL
343 || strchr(file1, '?') != NULL
344 || strchr(file1, '[') != NULL)) {
345 /* do a uux command */
346 if (ckexpf(file1) == FAIL)
347 exit(6);
348 (void) strncpy(Rmtname, sys1, MAXBASENAME);
349 Rmtname[MAXBASENAME] = NULLCHAR;
350 /* get real Myname - it depends on who I'm calling--Rmtname */
351 (void) mchFind(Rmtname);
352 myName(Myname);
353 if (*sys2 == NULLCHAR)
354 sys2p = Myname;
355 ruux(sys1, sys1, file1, sys2p, fwd2, file2);
356 continue;
357 }
358
359 /*
360 * check for forwarding -- generate and execute a uux command
361 * e.g.
362 * uucp uucp.c raven!owl!~/dan/
363 */
364
365 if (*fwd2 != NULLCHAR) {
366 ruux(sys2, sys1, file1, "", fwd2, file2);
367 continue;
368 }
369
370 /*
371 * check for both source and destination on other systems --
372 * generate and execute a uux command
373 */
374
375 if (*sys1 != NULLCHAR )
376 if ( (!EQUALS(Myname, sys1))
377 && *sys2 != NULLCHAR
378 && (!EQUALS(sys2, Myname)) ) {
379 ruux(sys2, sys1, file1, "", fwd2, file2);
380 continue;
381 }
382
383
384 sys2p = sys2;
385 if (*sys1 == NULLCHAR) {
386 if (*sys2 == NULLCHAR)
387 sys2p = Myname;
388 (void) strcpy(sys1, Myname);
389 } else {
390 (void) strncpy(Rmtname, sys1, MAXBASENAME);
391 Rmtname[MAXBASENAME] = NULLCHAR;
392 /* get real Myname - it depends on who I'm calling--Rmtname */
393 (void) mchFind(Rmtname);
394 myName(Myname);
395 if (*sys2 == NULLCHAR)
396 sys2p = Myname;
397 }
398
399 DEBUG(4, "sys1 - %s, ", sys1);
400 DEBUG(4, "file1 - %s, ", file1);
401 DEBUG(4, "Rmtname - %s\n", Rmtname);
402 if (copy(sys1, file1, sys2p, file2))
403 errors++;
404 }
405
406 /* move the work files to their proper places */
407 commitall();
408
409 /*
410 * Wait for all background uux processes to finish so
411 * that our caller will know that we're done with all
412 * input files and it's safe to remove them.
413 */
414 while (wait(NULL) != -1)
415 ;
416
417 /*
418 * do not spawn daemon if -r option specified
419 */
420 if (*Ropt != '-') {
421 #ifndef V7
422 long limit;
423 char msg[100];
424 limit = ulimit(1, (long) 0);
425 if (limit < MINULIMIT) {
426 (void) sprintf(msg,
427 "ULIMIT (%ld) < MINULIMIT (%ld)", limit, MINULIMIT);
428 logent(msg, "Low-ULIMIT");
429 }
430 else
431 #endif
432 xuucico(Rmtname);
433 }
434 if (jflag) {
435 (void) strncpy(Jobid, jid(), NAMESIZE);
436 printf("%s\n", Jobid);
437 }
438 cleanup(errors);
439 /*NOTREACHED*/
440 return (0);
441 }
442
443 /*
444 * cleanup lock files before exiting
445 */
446 void
cleanup(code)447 cleanup(code)
448 int code;
449 {
450 static int first = 1;
451
452 if (first) {
453 first = 0;
454 rmlock(CNULL);
455 if (code != 0)
456 wfabort(); /* this may be extreme -- abort all work */
457 }
458 if (code < 0) {
459 (void) fprintf(stderr,
460 gettext("uucp failed completely (%d)\n"), (-code));
461 exit(-code);
462 }
463 else if (code > 0) {
464 (void) fprintf(stderr, gettext(
465 "uucp failed partially: %d file(s) sent; %d error(s)\n"),
466 _Transfer, code);
467 exit(code);
468 }
469 exit(code);
470 }
471
472 static FILE *syscfile();
473 /*
474 * generate copy files for s1!f1 -> s2!f2
475 * Note: only one remote machine, other situations
476 * have been taken care of in main.
477 * return:
478 * 0 -> success
479 * Non-zero -> failure
480 */
481 int
copy(s1,f1,s2,f2)482 copy(s1, f1, s2, f2)
483 char *s1, *f1, *s2, *f2;
484 {
485 FILE *cfp;
486 struct stat stbuf, stbuf1;
487 int type, statret;
488 char dfile[NAMESIZE];
489 char cfile[NAMESIZE];
490 char command[10+(2*MAXFULLNAME)];
491 char file1[MAXFULLNAME], file2[MAXFULLNAME];
492 char msg[BUFSIZ];
493
494 type = 0;
495 (void) strcpy(file1, f1);
496 (void) strcpy(file2, f2);
497 if (!EQUALS(s1, Myname))
498 type = 1;
499 if (!EQUALS(s2, Myname))
500 type = 2;
501
502 DEBUG(4, "copy: file1=<%s> ", file1);
503 DEBUG(4, "file2=<%s>\n", file2);
504 switch (type) {
505 case 0:
506
507 /*
508 * all work here
509 */
510 DEBUG(4, "all work here %d\n", type);
511
512 /*
513 * check access control permissions
514 */
515 if (ckexpf(file1))
516 return(-6);
517 if (ckexpf(file2))
518 return(-7);
519
520 setuid(Uid);
521 if (chkperm(file1, file2, strchr(Optns, 'd')) &&
522 (access(file2, W_OK) == -1)) {
523 (void) fprintf(stderr, gettext("permission denied\n"));
524 cleanup(1);
525 }
526
527 /*
528 * copy file locally
529 *
530 * Changed from uidxcp() to fic file made and owner
531 * being modified for existing files, and local file
532 * name expansion.
533 */
534 DEBUG(2, "local copy: %s -> ", file1);
535 DEBUG(2, "%s\n", file2);
536
537 sprintf(command, "cp %s %s", file1, file2);
538 if ((cfp = popen(command, "r")) == NULL) {
539 perror("popen");
540 DEBUG(5, "popen failed - errno %d\n", errno);
541 setuid(Euid);
542 return (FAIL);
543 }
544 if (pclose(cfp) != 0) {
545 DEBUG(5, "Copy failed - errno %d\n", errno);
546 return (FAIL);
547 }
548 setuid(Euid);
549
550 /*
551 * if user specified -m, notify "local" user
552 */
553 if ( Mail ) {
554 sprintf(msg,
555 "REQUEST: %s!%s --> %s!%s (%s)\n(SYSTEM %s) copy succeeded\n",
556 s1, file1, s2, file2, User, s2 );
557 mailst(User, "copy succeeded", msg, "", "");
558 }
559 /*
560 * if user specified -n, notify "remote" user
561 */
562 if ( Notify ) {
563 sprintf(msg, "%s from %s!%s arrived\n",
564 file2, s1, User );
565 mailst(Nuser, msg, msg, "", "");
566 }
567 return(0);
568 case 1:
569
570 /*
571 * receive file
572 */
573 DEBUG(4, "receive file - %d\n", type);
574
575 /*
576 * expand source and destination file names
577 * and check access permissions
578 */
579 if (file1[0] != '~')
580 if (ckexpf(file1))
581 return(6);
582 if (ckexpf(file2))
583 return(7);
584
585
586 gename(DATAPRE, s2, Grade, dfile);
587
588 /*
589 * insert JCL card in file
590 */
591 cfp = syscfile(cfile, s1);
592 (void) fprintf(cfp,
593 "R %s %s %s %s %s %o %s %s\n", file1, file2,
594 User, Optns,
595 *Sfile ? Sfile : "dummy",
596 0777, Nuser, dfile);
597 (void) fclose(cfp);
598 (void) sprintf(msg, "%s!%s --> %s!%s", Rmtname, file1,
599 Myname, file2);
600 logent(msg, "QUEUED");
601 break;
602 case 2:
603
604 /*
605 * send file
606 */
607 if (ckexpf(file1))
608 return(6);
609 /* XQTDIR hook enables 3rd party uux requests (cough) */
610 DEBUG(4, "Workdir = <%s>\n", Wrkdir);
611 if (file2[0] != '~' && !EQUALS(Wrkdir, XQTDIR))
612 if (ckexpf(file2))
613 return(7);
614 DEBUG(4, "send file - %d\n", type);
615
616 if (uidstat(file1, &stbuf) != 0) {
617 (void) fprintf(stderr,
618 gettext("can't get status for file %s\n"), file1);
619 return(8);
620 }
621 if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
622 (void) fprintf(stderr,
623 gettext("directory name illegal - %s\n"), file1);
624 return(9);
625 }
626 /* see if I can read this file as read uid, gid */
627 if (access(file1, R_OK) != 0) {
628 (void) fprintf(stderr,
629 gettext("uucp can't read (%s) mode (%o)\n"),
630 file1, stbuf.st_mode&0777);
631 return(3);
632 }
633
634 /*
635 * make a copy of file in spool directory
636 */
637
638 gename(DATAPRE, s2, Grade, dfile);
639
640 if (Copy || !READANY(file1) ) {
641
642 if (uidxcp(file1, dfile))
643 return(5);
644
645 (void) chmod(dfile, DFILEMODE);
646 }
647
648 cfp = syscfile(cfile, s2);
649 (void) fprintf(cfp, "S %s %s %s %s %s %lo %s %s\n",
650 file1, file2, User, Optns, dfile,
651 (long) stbuf.st_mode & LEGALMODE, Nuser, Sfile);
652 (void) fclose(cfp);
653 (void) sprintf(msg, "%s!%s --> %s!%s", Myname, file1,
654 Rmtname, file2);
655 logent(msg, "QUEUED");
656 break;
657 }
658 _Transfer++;
659 return(0);
660 }
661
662
663 /*
664 * syscfile(file, sys)
665 * char *file, *sys;
666 *
667 * get the cfile for system sys (creat if need be)
668 * return stream pointer
669 *
670 * returns
671 * stream pointer to open cfile
672 *
673 */
674
675 static FILE *
syscfile(file,sys)676 syscfile(file, sys)
677 char *file, *sys;
678 {
679 FILE *cfp;
680
681 if (gtcfile(file, sys) == FAIL) {
682 gename(CMDPRE, sys, Grade, file);
683 ASSERT(access(file, 0) != 0, Fl_EXISTS, file, errno);
684 cfp = fdopen(creat(file, CFILEMODE), "w");
685 svcfile(file, sys, Sgrade);
686 } else
687 cfp = fopen(file, "a");
688 ASSERT(cfp != NULL, Ct_OPEN, file, errno);
689 return(cfp);
690 }
691
692
693 /*
694 * generate and execute a uux command
695 */
696
697 void
ruux(rmt,sys1,file1,sys2,fwd2,file2)698 ruux(rmt, sys1, file1, sys2, fwd2, file2)
699 char *rmt, *sys1, *file1, *sys2, *fwd2, *file2;
700 {
701 char cmd[BUFSIZ];
702 char xcmd[BUFSIZ];
703 char * xarg[6];
704 int narg = 0;
705 int i;
706
707 /* get real Myname - it depends on who I'm calling--rmt */
708 (void) mchFind(rmt);
709 myName(Myname);
710
711 xarg[narg++] = UUX;
712 xarg[narg++] = "-C";
713 if (*Xopts != NULLCHAR)
714 xarg[narg++] = Xopts;
715 if (*Ropt != ' ')
716 xarg[narg++] = Ropt;
717
718 (void) sprintf(cmd, "%s!uucp -C", rmt);
719
720 if (*Uopts != NULLCHAR)
721 (void) sprintf(cmd+strlen(cmd), " (%s) ", Uopts);
722
723 if (*sys1 == NULLCHAR || EQUALS(sys1, Myname)) {
724 if (ckexpf(file1))
725 exit(6);
726 (void) sprintf(cmd+strlen(cmd), " %s!%s ", sys1, file1);
727 }
728 else
729 if (!EQUALS(rmt, sys1))
730 (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", sys1, file1);
731 else
732 (void) sprintf(cmd+strlen(cmd), " (%s) ", file1);
733
734 if (*fwd2 != NULLCHAR) {
735 if (*sys2 != NULLCHAR)
736 (void) sprintf(cmd+strlen(cmd),
737 " (%s!%s!%s) ", sys2, fwd2, file2);
738 else
739 (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", fwd2, file2);
740 }
741 else {
742 if (*sys2 == NULLCHAR || EQUALS(sys2, Myname))
743 if (ckexpf(file2))
744 exit(7);
745 (void) sprintf(cmd+strlen(cmd), " (%s!%s) ", sys2, file2);
746 }
747
748 xarg[narg++] = cmd;
749 xarg[narg] = (char *) 0;
750
751 xcmd[0] = NULLCHAR;
752 for (i=0; i < narg; i++) {
753 strcat(xcmd, xarg[i]);
754 strcat(xcmd, " ");
755 }
756 DEBUG(2, "cmd: %s\n", xcmd);
757 logent(xcmd, "QUEUED");
758
759 if (fork() == 0) {
760 ASSERT(setuid(getuid()) == 0, "setuid", "failed", 99);
761 execv(UUX, xarg);
762 exit(0);
763 }
764 return;
765 }
766
767 void
usage()768 usage()
769 {
770
771 (void) fprintf(stderr, gettext(
772 "Usage: %s [-c|-C] [-d|-f] [-g GRADE] [-jm] [-n USER]\\\n"
773 "[-r] [-s FILE] [-x DEBUG_LEVEL] source-files destination-file\n"),
774 Progname);
775 cleanup(-2);
776 }
777