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