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
  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
 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
 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
 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
 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
 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
 864 timeout()
 865 {
 866         longjmp(Sjbuf, 1);
 867 }
 868 
 869 /* skip to next field */
 870 static char *
 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
 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
 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
 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 */