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 2014 Garrett D'Amore
23 */
24 /*
25 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
30 /* All Rights Reserved */
31
32
33 /*
34
35 * uucp file transfer program:
36 * to place a call to a remote machine, login, and
37 * copy files between the two machines.
38
39 */
40 /*
41 * Added check to limit the total number of uucicos as defined
42 * in the Limits file.
43 *
44 * Added -f flag to "force execution", ignoring the limit on the
45 * number of uucicos. This will be used when invoking uucico from
46 * Uutry.
47 */
48
49 #include "uucp.h"
50 #include "log.h"
51
52 #ifndef V7
53 #include <sys/mkdev.h>
54 #endif /* V7 */
55
56 #ifdef TLI
57 #include <sys/tiuser.h>
58 #endif /* TLI */
59
60 jmp_buf Sjbuf;
61 extern unsigned msgtime;
62 char uuxqtarg[MAXBASENAME] = {'\0'};
63 int uuxqtflag = 0;
64
65 extern int (*Setup)(), (*Teardown)(); /* defined in interface.c */
66
67 #define USAGE "Usage: %s [-x NUM] [-r [0|1]] -s SYSTEM -u USERID -d SPOOL -i INTERFACE [-f]\n"
68 extern void closedem();
69 void cleanup(), cleanTM();
70
71 extern int sysaccess(), guinfo(), eaccess(), countProcs(), interface(),
72 savline(), omsg(), restline(), imsg(), callok(), gnxseq(),
73 cmtseq(), conn(), startup(), cntrl();
74 extern void setuucp(), fixline(), gename(), ulkseq(), pfEndfile();
75
76 #ifdef NOSTRANGERS
77 static void checkrmt(); /* See if we want to talk to remote. */
78 #endif /* NOSTRANGERS */
79
80 extern char *Mytype;
81
82 static char *pskip();
83
84 int
main(argc,argv,envp)85 main(argc, argv, envp)
86 int argc;
87 char *argv[];
88 char **envp;
89 {
90
91 extern void intrEXIT(), onintr(), timeout();
92 extern void setservice();
93 #ifndef ATTSVR3
94 void setTZ();
95 #endif /* ATTSVR3 */
96 int ret, seq, exitcode;
97 char file[NAMESIZE];
98 char msg[BUFSIZ], *p, *q;
99 char xflag[6]; /* -xN N is single digit */
100 char *ttyn;
101 char *iface; /* interface name */
102 char cb[128];
103 time_t ts, tconv;
104 char lockname[MAXFULLNAME];
105 struct limits limitval;
106 int maxnumb;
107 int force = 0; /* set to force execution, ignoring uucico limit */
108 char gradedir[2*NAMESIZE];
109
110 /* Set locale environment variables local definitions */
111 (void) setlocale(LC_ALL, "");
112 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
113 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it wasn't */
114 #endif
115 (void) textdomain(TEXT_DOMAIN);
116
117 Ulimit = ulimit(1,0L);
118 Uid = getuid();
119 Euid = geteuid(); /* this should be UUCPUID */
120 if (Uid == 0)
121 setuid(UUCPUID);
122 Env = envp;
123 Role = SLAVE;
124 strcpy(Logfile, LOGCICO);
125 *Rmtname = NULLCHAR;
126 Ifn = Ofn = -1; /* must be set before signal handlers */
127
128 closedem();
129 time(&Nstat.t_qtime);
130 tconv = Nstat.t_start = Nstat.t_qtime;
131 strcpy(Progname, "uucico");
132 setservice(Progname);
133 ret = sysaccess(EACCESS_SYSTEMS);
134 ASSERT(ret == 0, Ct_OPEN, "Systems", ret);
135 ret = sysaccess(EACCESS_DEVICES);
136 ASSERT(ret == 0, Ct_OPEN, "Devices", ret);
137 ret = sysaccess(EACCESS_DIALERS);
138 ASSERT(ret == 0, Ct_OPEN, "Dialers", ret);
139 Pchar = 'C';
140 (void) signal(SIGILL, intrEXIT);
141 (void) signal(SIGTRAP, intrEXIT);
142 (void) signal(SIGIOT, intrEXIT);
143 (void) signal(SIGEMT, intrEXIT);
144 (void) signal(SIGFPE, intrEXIT);
145 (void) signal(SIGBUS, intrEXIT);
146 (void) signal(SIGSEGV, intrEXIT);
147 (void) signal(SIGSYS, intrEXIT);
148 if (signal(SIGPIPE, SIG_IGN) != SIG_IGN) /* This for sockets */
149 (void) signal(SIGPIPE, intrEXIT);
150 (void) signal(SIGINT, onintr);
151 (void) signal(SIGHUP, onintr);
152 (void) signal(SIGQUIT, onintr);
153 (void) signal(SIGTERM, onintr);
154 #ifdef SIGUSR1
155 (void) signal(SIGUSR1, SIG_IGN);
156 #endif
157 #ifdef SIGUSR2
158 (void) signal(SIGUSR2, SIG_IGN);
159 #endif
160 #ifdef BSD4_2
161 (void) sigsetmask(sigblock(0) & ~(1 << (SIGALRM - 1)));
162 #endif /*BSD4_2*/
163
164 pfInit();
165 scInit("xfer");
166 ret = guinfo(Euid, User);
167 ASSERT(ret == 0, "BAD UID ", "", ret);
168 strncpy(Uucp, User, NAMESIZE);
169
170 setuucp(User);
171
172 *xflag = NULLCHAR;
173 iface = "UNIX";
174
175 while ((ret = getopt(argc, argv, "fd:c:r:s:x:u:i:")) != EOF) {
176 switch (ret) {
177 case 'd':
178 if ( eaccess(optarg, 01) != 0 ) {
179 (void) fprintf(stderr, gettext("%s: cannot"
180 " access spool directory %s\n"),
181 Progname, optarg);
182 exit(1);
183 }
184 Spool = optarg;
185 break;
186 case 'c':
187 Mytype = optarg;
188 break;
189 case 'f':
190 ++force;
191 break;
192 case 'r':
193 if ( (Role = atoi(optarg)) != MASTER && Role != SLAVE ) {
194 (void) fprintf(stderr, gettext("%s: bad value"
195 " '%s' for -r argument\n" USAGE),
196 Progname, optarg, Progname);
197 exit(1);
198 }
199 break;
200 case 's':
201 strncpy(Rmtname, optarg, MAXFULLNAME-1);
202 if (versys(Rmtname)) {
203 (void) fprintf(stderr,
204 gettext("%s: %s not in Systems file\n"),
205 Progname, optarg);
206 cleanup(101);
207 }
208 /* set args for possible xuuxqt call */
209 strcpy(uuxqtarg, Rmtname);
210 /* if versys put a longer name in, truncate it again */
211 Rmtname[MAXBASENAME] = '\0';
212 break;
213 case 'x':
214 Debug = atoi(optarg);
215 if (Debug <= 0)
216 Debug = 1;
217 if (Debug > 9)
218 Debug = 9;
219 (void) sprintf(xflag, "-x%d", Debug);
220 break;
221 case 'u':
222 DEBUG(4, "Loginuser %s specified\n", optarg);
223 strncpy(Loginuser, optarg, NAMESIZE);
224 Loginuser[NAMESIZE - 1] = NULLCHAR;
225 break;
226 case 'i':
227 /* interface type */
228 iface = optarg;
229 break;
230 default:
231 (void) fprintf(stderr, gettext(USAGE), Progname);
232 exit(1);
233 }
234 }
235
236 if (Role == MASTER || *Loginuser == NULLCHAR) {
237 ret = guinfo(Uid, Loginuser);
238 ASSERT(ret == 0, "BAD LOGIN_UID ", "", ret);
239 }
240
241 /* limit the total number of uucicos */
242 if (force) {
243 DEBUG(4, "force flag set (ignoring uucico limit)\n%s", "");
244 } else if (scanlimit("uucico", &limitval) == FAIL) {
245 DEBUG(1, "No limits for uucico in %s\n", LIMITS);
246 } else {
247 maxnumb = limitval.totalmax;
248 if (maxnumb < 0) {
249 DEBUG(4, "Non-positive limit for uucico in %s\n", LIMITS);
250 DEBUG(1, "No limits for uucico\n%s", "");
251 } else {
252 DEBUG(4, "Uucico limit %d -- ", maxnumb);
253 (void) sprintf(lockname, "%s.", LOCKPRE);
254 if (countProcs(lockname, (maxnumb-1)) == FALSE) {
255 DEBUG(4, "exiting\n%s", "");
256 cleanup(101);
257 }
258 DEBUG(4, "continuing\n%s", "");
259 }
260 }
261
262 pfStrtConn((Role == MASTER) ? 'M' : 'S');
263 if (Role == MASTER) {
264 if (*Rmtname == NULLCHAR) {
265 DEBUG(5, "No -s specified\n%s" , "");
266 cleanup(101);
267 }
268 /* get Myname - it depends on who I'm calling--Rmtname */
269 (void) mchFind(Rmtname);
270 myName(Myname);
271 if (EQUALSN(Rmtname, Myname, MAXBASENAME)) {
272 DEBUG(5, "This system specified: -sMyname: %s, ", Myname);
273 cleanup(101);
274 }
275 acInit("xfer");
276 }
277
278 ASSERT(chdir(Spool) == 0, Ct_CHDIR, Spool, errno);
279 strcpy(Wrkdir, Spool);
280
281 scReqsys((Role == MASTER) ? Myname : Rmtname); /* log requestor system */
282
283 if (Role == SLAVE) {
284
285 #ifndef ATTSVR3
286 setTZ();
287 #endif /* ATTSVR3 */
288
289 if (freopen(RMTDEBUG, "a", stderr) == 0) {
290 errent(Ct_OPEN, RMTDEBUG, errno, __FILE__, __LINE__);
291 freopen("/dev/null", "w", stderr);
292 }
293 if ( interface(iface) ) {
294 (void)fprintf(stderr,
295 "%s: invalid interface %s\n", Progname, iface);
296 cleanup(101);
297 }
298 /*master setup will be called from processdev()*/
299 if ( (*Setup)( Role, &Ifn, &Ofn ) ) {
300 DEBUG(5, "SLAVE Setup failed%s", "");
301 cleanup(101);
302 }
303
304 /*
305 * initial handshake
306 */
307 (void) savline();
308 fixline(Ifn, 0, D_ACU);
309 /* get MyName - use logFind to check PERMISSIONS file */
310 (void) logFind(Loginuser, "");
311 myName(Myname);
312
313 DEBUG(4,"cico.c: Myname - %s\n",Myname);
314 DEBUG(4,"cico.c: Loginuser - %s\n",Loginuser);
315 fflush(stderr);
316 Nstat.t_scall = times(&Nstat.t_tga);
317 (void) sprintf(msg, "here=%s", Myname);
318 omsg('S', msg, Ofn);
319 (void) signal(SIGALRM, timeout);
320 (void) alarm(msgtime); /* give slow machines a second chance */
321 if (setjmp(Sjbuf)) {
322
323 /*
324 * timed out
325 */
326 (void) restline();
327 rmlock(CNULL);
328 exit(0);
329 }
330 for (;;) {
331 ret = imsg(msg, Ifn);
332 if (ret != 0) {
333 (void) alarm(0);
334 (void) restline();
335 rmlock(CNULL);
336 exit(0);
337 }
338 if (msg[0] == 'S')
339 break;
340 }
341 Nstat.t_ecall = times(&Nstat.t_tga);
342 (void) alarm(0);
343 q = &msg[1];
344 p = pskip(q);
345 strncpy(Rmtname, q, MAXBASENAME);
346 Rmtname[MAXBASENAME] = '\0';
347
348 seq = 0;
349 while (p && *p == '-') {
350 q = pskip(p);
351 switch(*(++p)) {
352 case 'x':
353 Debug = atoi(++p);
354 if (Debug <= 0)
355 Debug = 1;
356 (void) sprintf(xflag, "-x%d", Debug);
357 break;
358 case 'Q':
359 seq = atoi(++p);
360 if (seq < 0)
361 seq = 0;
362 break;
363 #ifdef MAXGRADE
364 case 'v': /* version -- -vname=val or -vname */
365 if (strncmp(++p, "grade=", 6) == 0 &&
366 isalnum(p[6]))
367 MaxGrade = p[6];
368 break;
369 #endif /* MAXGRADE */
370 case 'R':
371 Restart++;
372 p++;
373 break;
374 case 'U':
375 SizeCheck++;
376 RemUlimit = strtol(++p, (char **) NULL,0);
377 break;
378 default:
379 break;
380 }
381 p = q;
382 }
383 DEBUG(4, "sys-%s\n", Rmtname);
384 if (strpbrk(Rmtname, Shchar) != NULL) {
385 DEBUG(4, "Bad remote system name '%s'\n", Rmtname);
386 logent(Rmtname, "BAD REMOTE SYSTEM NAME");
387 omsg('R', "Bad remote system name", Ofn);
388 cleanup(101);
389 }
390 if (Restart)
391 CDEBUG(1,"Checkpoint Restart enabled\n%s", "");
392
393 #ifdef NOSTRANGERS
394 checkrmt(); /* Do we know the remote system. */
395 #else
396 (void) versys(Rmtname); /* in case the real name is longer */
397 #endif /* NOSTRANGERS */
398
399 (void) sprintf(lockname, "%ld", (long) getpid());
400 if (umlock(LOCKPRE, lockname)) {
401 omsg('R', "LCK", Ofn);
402 cleanup(101);
403 }
404
405 /* validate login using PERMISSIONS file */
406 if (logFind(Loginuser, Rmtname) == FAIL) {
407 scWrite(); /* log security violation */
408 Uerror = SS_BAD_LOG_MCH;
409 logent(UERRORTEXT, "FAILED");
410 systat(Rmtname, SS_BAD_LOG_MCH, UERRORTEXT,
411 Retrytime);
412 omsg('R', "LOGIN", Ofn);
413 cleanup(101);
414 }
415
416 ret = callBack();
417 DEBUG(4,"return from callcheck: %s",ret ? "TRUE" : "FALSE");
418 if (ret==TRUE) {
419 (void) signal(SIGINT, SIG_IGN);
420 (void) signal(SIGHUP, SIG_IGN);
421 omsg('R', "CB", Ofn);
422 logent("CALLBACK", "REQUIRED");
423 /*
424 * set up for call back
425 */
426 chremdir(Rmtname);
427 (void) sprintf(file, "%s/%c", Rmtname, D_QUEUE);
428 chremdir(file);
429 gename(CMDPRE, Rmtname, 'C', file);
430 (void) close(creat(file, CFILEMODE));
431 if (callok(Rmtname) == SS_CALLBACK_LOOP) {
432 systat(Rmtname, SS_CALLBACK_LOOP, "CALL BACK - LOOP", Retrytime);
433 } else {
434 systat(Rmtname, SS_CALLBACK, "CALL BACK", Retrytime);
435 xuucico(Rmtname);
436 }
437 cleanup(101);
438 }
439
440 if (callok(Rmtname) == SS_SEQBAD) {
441 Uerror = SS_SEQBAD;
442 logent(UERRORTEXT, "PREVIOUS");
443 omsg('R', "BADSEQ", Ofn);
444 cleanup(101);
445 }
446
447 if (gnxseq(Rmtname) == seq) {
448 if (Restart) {
449 if (SizeCheck)
450 (void) sprintf (msg, "OK -R -U0x%lx %s",
451 Ulimit, xflag);
452 else
453 (void) sprintf (msg, "OK -R %s", xflag);
454 omsg('R', msg, Ofn);
455 } else
456 omsg('R', "OK", Ofn);
457 (void) cmtseq();
458 } else {
459 Uerror = SS_SEQBAD;
460 systat(Rmtname, SS_SEQBAD, UERRORTEXT, Retrytime);
461 logent(UERRORTEXT, "HANDSHAKE FAILED");
462 ulkseq();
463 omsg('R', "BADSEQ", Ofn);
464 cleanup(101);
465 }
466 ttyn = ttyname(Ifn);
467 if (ttyn != CNULL && *ttyn != NULLCHAR) {
468 struct stat ttysbuf;
469 if ( fstat(Ifn,&ttysbuf) == 0 )
470 Dev_mode = ttysbuf.st_mode;
471 else
472 Dev_mode = R_DEVICEMODE;
473 if ( EQUALSN(ttyn,"/dev/",5) )
474 strcpy(Dc, ttyn+5);
475 else
476 strcpy(Dc, ttyn);
477 chmod(ttyn, S_DEVICEMODE);
478 } else
479 strcpy(Dc, "notty");
480 /* set args for possible xuuxqt call */
481 strcpy(uuxqtarg, Rmtname);
482 }
483
484 strcpy(User, Uucp);
485 /*
486 * Ensure reasonable ulimit (MINULIMIT)
487 */
488
489 #ifndef V7
490 {
491 long minulimit;
492 minulimit = ulimit(1, (long) 0);
493 ASSERT(minulimit >= MINULIMIT, "ULIMIT TOO SMALL",
494 Loginuser, (int) minulimit);
495 }
496 #endif
497 if (Role == MASTER && callok(Rmtname) != 0) {
498 logent("SYSTEM STATUS", "CAN NOT CALL");
499 cleanup(101);
500 }
501
502 chremdir(Rmtname);
503
504 (void) strcpy(Wrkdir, RemSpool);
505 if (Role == MASTER) {
506
507 /*
508 * master part
509 */
510 (void) signal(SIGINT, SIG_IGN);
511 (void) signal(SIGHUP, SIG_IGN);
512 (void) signal(SIGQUIT, SIG_IGN);
513 if (Ifn != -1 && Role == MASTER) {
514 (void) (*Write)(Ofn, EOTMSG, strlen(EOTMSG));
515 (void) close(Ofn);
516 (void) close(Ifn);
517 Ifn = Ofn = -1;
518 rmlock(CNULL);
519 sleep(3);
520 }
521
522 /*
523 * Find the highest priority job grade that has
524 * jobs to do. This is needed to form the lock name.
525 */
526
527 findgrade(RemSpool, JobGrade);
528 DEBUG(4, "Job grade to process - %s\n", JobGrade);
529
530 /*
531 * Lock the job grade if there is one to process.
532 */
533
534 if (*JobGrade != NULLCHAR) {
535 (void) sprintf(gradedir, "%s/%s", Rmtname, JobGrade);
536 chremdir(gradedir);
537
538 (void) sprintf(lockname, "%.*s.%s", SYSNSIZE, Rmtname, JobGrade);
539 (void) sprintf(msg, "call to %s - process job grade %s ",
540 Rmtname, JobGrade);
541 if (umlock(LOCKPRE, lockname) != 0) {
542 logent(msg, "LOCKED");
543 CDEBUG(1, "Currently Talking With %s\n",
544 Rmtname);
545 cleanup(100);
546 }
547 } else {
548 (void) sprintf(msg, "call to %s - no work", Rmtname);
549 }
550
551 Nstat.t_scall = times(&Nstat.t_tga);
552 Ofn = Ifn = conn(Rmtname);
553 Nstat.t_ecall = times(&Nstat.t_tga);
554 if (Ofn < 0) {
555 delock(LOCKPRE, lockname);
556 logent(UERRORTEXT, "CONN FAILED");
557 systat(Rmtname, Uerror, UERRORTEXT, Retrytime);
558 cleanup(101);
559 } else {
560 logent(msg, "SUCCEEDED");
561 ttyn = ttyname(Ifn);
562 if (ttyn != CNULL && *ttyn != NULLCHAR) {
563 struct stat ttysbuf;
564 if ( fstat(Ifn,&ttysbuf) == 0 )
565 Dev_mode = ttysbuf.st_mode;
566 else
567 Dev_mode = R_DEVICEMODE;
568 chmod(ttyn, M_DEVICEMODE);
569 }
570 }
571
572 if (setjmp(Sjbuf)) {
573 delock(LOCKPRE, lockname);
574 Uerror = SS_LOGIN_FAILED;
575 logent(Rmtname, UERRORTEXT);
576 systat(Rmtname, SS_LOGIN_FAILED,
577 UERRORTEXT, Retrytime);
578 DEBUG(4, "%s - failed\n", UERRORTEXT);
579 cleanup(101);
580 }
581 (void) signal(SIGALRM, timeout);
582 /* give slow guys lots of time to thrash */
583 (void) alarm(2 * msgtime);
584 for (;;) {
585 ret = imsg(msg, Ifn);
586 if (ret != 0) {
587 continue; /* try again */
588 }
589 if (msg[0] == 'S')
590 break;
591 }
592 (void) alarm(0);
593 if(EQUALSN("here=", &msg[1], 5)){
594 /* This may be a problem, we check up to MAXBASENAME
595 * characters now. The old comment was:
596 * this is a problem. We'd like to compare with an
597 * untruncated Rmtname but we fear incompatability.
598 * So we'll look at most 6 chars (at most).
599 */
600 (void) pskip(&msg[6]);
601 if (!EQUALSN(&msg[6], Rmtname, MAXBASENAME)) {
602 delock(LOCKPRE, lockname);
603 Uerror = SS_WRONG_MCH;
604 logent(&msg[6], UERRORTEXT);
605 systat(Rmtname, SS_WRONG_MCH, UERRORTEXT,
606 Retrytime);
607 DEBUG(4, "%s - failed\n", UERRORTEXT);
608 cleanup(101);
609 }
610 }
611 CDEBUG(1,"Login Successful: System=%s\n",&msg[6]);
612 seq = gnxseq(Rmtname);
613 (void) sprintf(msg, "%s -Q%d -R -U0x%lx %s",
614 Myname, seq, Ulimit, xflag);
615 #ifdef MAXGRADE
616 if (MaxGrade != NULLCHAR) {
617 p = strchr(msg, NULLCHAR);
618 sprintf(p, " -vgrade=%c", MaxGrade);
619 }
620 #endif /* MAXGRADE */
621 omsg('S', msg, Ofn);
622 (void) alarm(msgtime); /* give slow guys some thrash time */
623 for (;;) {
624 ret = imsg(msg, Ifn);
625 DEBUG(4, "msg-%s\n", msg);
626 if (ret != 0) {
627 (void) alarm(0);
628 delock(LOCKPRE, lockname);
629 ulkseq();
630 cleanup(101);
631 }
632 if (msg[0] == 'R')
633 break;
634 }
635 (void) alarm(0);
636
637 /* check for rejects from remote */
638 Uerror = 0;
639 if (EQUALS(&msg[1], "LCK"))
640 Uerror = SS_RLOCKED;
641 else if (EQUALS(&msg[1], "LOGIN"))
642 Uerror = SS_RLOGIN;
643 else if (EQUALS(&msg[1], "CB"))
644 Uerror = (callBack() ? SS_CALLBACK_LOOP : SS_CALLBACK);
645 else if (EQUALS(&msg[1], "You are unknown to me"))
646 Uerror = SS_RUNKNOWN;
647 else if (EQUALS(&msg[1], "BADSEQ"))
648 Uerror = SS_SEQBAD;
649 else if (!EQUALSN(&msg[1], "OK", 2))
650 Uerror = SS_UNKNOWN_RESPONSE;
651 if (Uerror) {
652 delock(LOCKPRE, lockname);
653 systat(Rmtname, Uerror, UERRORTEXT, Retrytime);
654 logent(UERRORTEXT, "HANDSHAKE FAILED");
655 CDEBUG(1, "HANDSHAKE FAILED: %s\n", UERRORTEXT);
656 ulkseq();
657 cleanup(101);
658 }
659 (void) cmtseq();
660
661 /*
662 * See if we have any additional parameters on the OK
663 */
664
665 if (strlen(&msg[3])) {
666 p = pskip(&msg[3]);
667 while (p && *p == '-') {
668 q = pskip(p);
669 switch(*(++p)) {
670 case 'R':
671 Restart++;
672 p++;
673 break;
674 case 'U':
675 SizeCheck++;
676 RemUlimit = strtol(++p, (char **) NULL, 0);
677 break;
678 case 'x':
679 if (!Debug) {
680 Debug = atoi(++p);
681 if (Debug <= 0)
682 Debug = 1;
683 }
684 break;
685 default:
686 break;
687 }
688 p = q;
689 }
690 }
691
692 }
693 DEBUG(4, " Rmtname %s, ", Rmtname);
694 DEBUG(4, " Restart %s, ", (Restart ? "YES" : "NO"));
695 DEBUG(4, "Role %s, ", Role ? "MASTER" : "SLAVE");
696 DEBUG(4, "Ifn - %d, ", Ifn);
697 DEBUG(4, "Loginuser - %s\n", Loginuser);
698
699 /* alarm/setjmp added here due to experience with uucico
700 * hanging for hours in imsg().
701 */
702 if (setjmp(Sjbuf)) {
703 delock(LOCKPRE, lockname);
704 logent("startup", "TIMEOUT");
705 DEBUG(4, "%s - timeout\n", "startup");
706 cleanup(101);
707 }
708 (void) alarm(MAXSTART);
709 ret = startup();
710 (void) alarm(0);
711
712 if (ret != SUCCESS) {
713 delock(LOCKPRE, lockname);
714 logent("startup", "FAILED");
715 Uerror = SS_STARTUP;
716 CDEBUG(1, "%s\n", UERRORTEXT);
717 systat(Rmtname, Uerror, UERRORTEXT, Retrytime);
718 exitcode = 101;
719 } else {
720 pfConnected(Rmtname, Dc);
721 acConnected(Rmtname, Dc);
722 logent("startup", "OK");
723 systat(Rmtname, SS_INPROGRESS, UTEXT(SS_INPROGRESS),Retrytime);
724 Nstat.t_sftp = times(&Nstat.t_tga);
725
726 exitcode = cntrl();
727 Nstat.t_eftp = times(&Nstat.t_tga);
728 DEBUG(4, "cntrl - %d\n", exitcode);
729 (void) signal(SIGINT, SIG_IGN);
730 (void) signal(SIGHUP, SIG_IGN);
731 (void) signal(SIGALRM, timeout);
732
733 if (exitcode == 0) {
734 (void) time(&ts);
735 (void) sprintf(cb, "conversation complete %s %ld",
736 Dc, ts - tconv);
737 logent(cb, "OK");
738 systat(Rmtname, SS_OK, UTEXT(SS_OK), Retrytime);
739
740 } else {
741 logent("conversation complete", "FAILED");
742 systat(Rmtname, SS_CONVERSATION,
743 UTEXT(SS_CONVERSATION), Retrytime);
744 }
745 (void) alarm(msgtime); /* give slow guys some thrash time */
746 omsg('O', "OOOOO", Ofn);
747 CDEBUG(4, "send OO %d,", ret);
748 if (!setjmp(Sjbuf)) {
749 for (;;) {
750 omsg('O', "OOOOO", Ofn);
751 ret = imsg(msg, Ifn);
752 if (ret != 0)
753 break;
754 if (msg[0] == 'O')
755 break;
756 }
757 }
758 (void) alarm(0);
759 }
760 cleanup(exitcode);
761 /*NOTREACHED*/
762 return (0);
763 }
764
765 /*
766 * clean and exit with "code" status
767 */
768 void
cleanup(code)769 cleanup(code)
770 int code;
771 {
772 (void) signal(SIGINT, SIG_IGN);
773 (void) signal(SIGHUP, SIG_IGN);
774 rmlock(CNULL);
775 closedem();
776 alarm(msgtime); /* Start timer in case closes hang. */
777 if (setjmp(Sjbuf) == 0)
778 (*Teardown)( Role, Ifn, Ofn );
779 alarm(0); /* Turn off timer. */
780 DEBUG(4, "exit code %d\n", code);
781 CDEBUG(1, "Conversation Complete: Status %s\n\n",
782 code ? "FAILED" : "SUCCEEDED");
783
784 cleanTM();
785 if ((code == 0) && (uuxqtflag == 1))
786 xuuxqt(uuxqtarg);
787 exit(code);
788 }
789
790 short TM_cnt = 0;
791 char TM_name[MAXNAMESIZE];
792
793 void
cleanTM()794 cleanTM()
795 {
796 int i;
797 char tm_name[MAXNAMESIZE];
798
799 DEBUG(7,"TM_cnt: %d\n",TM_cnt);
800 for(i=0; i < TM_cnt; i++) {
801 (void) sprintf(tm_name, "%s.%3.3d", TM_name, i);
802 DEBUG(7, "tm_name: %s\n", tm_name);
803 unlink(tm_name);
804 }
805 return;
806 }
807
808 void
TMname(file,pnum)809 TMname(file, pnum)
810 char *file;
811 pid_t pnum;
812 {
813
814 (void) sprintf(file, "%s/TM.%.5ld.%.3d", RemSpool, (long) pnum, TM_cnt);
815 if (TM_cnt == 0)
816 (void) sprintf(TM_name, "%s/TM.%.5ld", RemSpool, (long) pnum);
817 DEBUG(7, "TMname(%s)\n", file);
818 TM_cnt++;
819 return;
820 }
821
822 /*
823 * intrrupt - remove locks and exit
824 */
825 void
onintr(inter)826 onintr(inter)
827 int inter;
828 {
829 char str[30];
830 /* I'm putting a test for zero here because I saw it happen
831 * and don't know how or why, but it seemed to then loop
832 * here for ever?
833 */
834 if (inter == 0)
835 exit(99);
836 (void) signal(inter, SIG_IGN);
837 (void) sprintf(str, "SIGNAL %d", inter);
838 logent(str, "CAUGHT");
839 pfEndfile("PARTIAL FILE");
840 acEnd(PARTIAL); /*stop collecting accounting log */
841 cleanup(inter);
842 }
843
844 void
intrEXIT(inter)845 intrEXIT(inter)
846 int inter;
847 {
848 char cb[20];
849
850 (void) sprintf(cb, "SIGNAL %d", inter);
851 logent("INTREXIT", cb);
852 (void) signal(SIGIOT, SIG_DFL);
853 (void) signal(SIGILL, SIG_DFL);
854 rmlock(CNULL);
855 closedem();
856 (void) setuid(Uid);
857 abort();
858 }
859
860 /*
861 * catch SIGALRM routine
862 */
863 void
timeout()864 timeout()
865 {
866 longjmp(Sjbuf, 1);
867 }
868
869 /* skip to next field */
870 static char *
pskip(p)871 pskip(p)
872 char *p;
873 {
874 if ((p = strchr(p, ' ')) != CNULL)
875 do
876 *p++ = NULLCHAR;
877 while (*p == ' ');
878 return(p);
879 }
880
881 void
closedem()882 closedem()
883 {
884 int i, maxfiles;
885
886 #ifdef ATTSVR3
887 maxfiles = ulimit(4,0);
888 #else /* !ATTSVR3 */
889 #ifdef BSD4_2
890 maxfiles = getdtablesize();
891 #else /* BSD4_2 */
892 maxfiles = _NFILE;
893 #endif /* BSD4_2 */
894 #endif /* ATTSVR3 */
895
896 for ( i = 3; i < maxfiles; i++ )
897 if ( i != Ifn && i != Ofn && i != fileno(stderr) )
898 (void) close(i);
899 return;
900 }
901
902 #ifndef ATTSVR3
903
904 /*
905 * setTZ()
906 *
907 * if login "shell" is uucico (i.e., Role == SLAVE), must set
908 * timezone env variable TZ. otherwise will default to EST.
909 */
910
911 #define LINELEN 81
912
913 void
setTZ()914 setTZ()
915 {
916 static char buf[LINELEN], *bp;
917 extern char *fgets();
918 FILE *tzfp;
919 extern FILE *fopen();
920 int i;
921 extern int fclose(), strncmp();
922
923 if ( (tzfp = fopen("/etc/default/init","r")) == (FILE *)NULL )
924 return;
925 while ( (bp = fgets(buf,LINELEN,tzfp)) != (char *)NULL ) {
926 while ( isspace(*bp) )
927 ++bp;
928 if ( strncmp(bp, "TZ=", 3) == 0 ) {
929 for ( i = strlen(bp) - 1; i > 0 && isspace(*(bp+i)); --i )
930 *(bp+i) = '\0';
931 putenv(bp);
932 (void)fclose(tzfp);
933 return;
934 }
935 }
936 (void)fclose(tzfp);
937 return;
938 }
939 #endif /* ATTSVR3 */
940
941 #ifdef NOSTRANGERS
942 /*
943 * Function: checkrmt
944 *
945 * If NOSTRANGERS is defined, see if the remote system is in our systems
946 * file. If it is not, execute NOSTRANGERS and then reject the call.
947 */
948
949 static void
checkrmt()950 checkrmt ()
951
952 {
953 char ** eVarPtr; /* Pointer to environment variable. */
954 char msgbuf[BUFSIZ]; /* Place to build messages. */
955 pid_t procid; /* ID of Nostranger process. */
956 static char * safePath = PATH;
957 int status; /* Exit status of child. */
958 pid_t waitrv; /* Return value from wait system call. */
959
960 /* here's the place to look the remote system up in the Systems file.
961 * If the command NOSTRANGERS is executable and
962 * If they're not in my file then hang up */
963
964 if (versys(Rmtname) && (access(NOSTRANGERS, 1) == 0)) {
965 sprintf(msgbuf, "Invoking %s for %%s\n", NOSTRANGERS);
966 DEBUG(4, msgbuf, Rmtname);
967
968 /*
969 * Ignore hangup in case remote goes away before we can
970 * finish logging.
971 */
972
973 (void) signal(SIGHUP, SIG_IGN);
974 omsg('R', "You are unknown to me", Ofn);
975 scWrite(); /* log unknown remote system */
976 procid = fork();
977 if ( procid == 0 ) {
978 /*
979 * Before execing the no strangers program, there is
980 * a security aspect to consider. If NOSTRANGERS is
981 * not a full path name, then the PATH environment
982 * variable will provide places to look for the file.
983 * To be safe, we will set the PATH environment
984 * variable before we do the exec.
985 */
986
987 /* Find PATH in current environment and change it. */
988
989 for (eVarPtr = Env; *eVarPtr != CNULL; eVarPtr++) {
990 if (PREFIX("PATH=", *eVarPtr))
991 *eVarPtr = safePath;
992 }
993 execlp( NOSTRANGERS, "stranger", Rmtname, (char *) 0);
994 sprintf(msgbuf, "Execlp of %s failed with errno=%%d\n",
995 NOSTRANGERS);
996 DEBUG(4, msgbuf, errno);
997 perror(gettext("cico.c: execlp NOSTRANGERS failed"));
998 cleanup(errno);
999 } else if (procid < 0) {
1000 perror(gettext("cico.c: execlp NOSTRANGERS failed"));
1001 cleanup(errno);
1002 } else {
1003 while ((waitrv = wait(&status)) != procid)
1004 if (waitrv == -1 && errno != EINTR)
1005 cleanup(errno);
1006 sprintf(msgbuf, "%s exit status was %%#x\n",
1007 NOSTRANGERS);
1008 DEBUG(4, msgbuf, status);
1009 }
1010 cleanup(101);
1011 }
1012 }
1013 #endif /* NOSTRANGERS */
1014