new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / uucp / uucico / cico.c
CommitLineData
d34dfbc0
KB
1/*-
2 * Copyright (c) 1985 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * %sccs.include.proprietary.c%
6 */
7
ce5db1eb 8#ifndef lint
d34dfbc0
KB
9static char sccsid[] = "@(#)cico.c 5.21 (Berkeley) %G%";
10#endif /* not lint */
ce5db1eb 11
ce5db1eb 12#include <signal.h>
4b31fbb4 13#include "uucp.h"
ce5db1eb 14#include <setjmp.h>
88db71e9 15#ifdef USG
ce5db1eb 16#include <termio.h>
9c672c90 17#include <fcntl.h>
ce5db1eb 18#endif
88db71e9 19#ifndef USG
ce5db1eb
SL
20#include <sgtty.h>
21#endif
88db71e9
RC
22#ifdef BSDTCP
23#include <netdb.h>
24#include <netinet/in.h>
25#include <sys/socket.h>
26#endif BSDTCP
27#include <sys/stat.h>
9c672c90
RA
28#ifdef BSD4_2
29#include <sys/time.h>
30#include <fcntl.h>
31#else
32#include <time.h>
33#endif
88db71e9
RC
34#include "uust.h"
35#include "uusub.h"
c861cac9 36#include "pathnames.h"
ce5db1eb 37
4b31fbb4
JB
38#if defined(VMS) && defined(BSDTCP)
39#define NOGETPEER
40#endif
41
ce5db1eb 42jmp_buf Sjbuf;
88db71e9
RC
43jmp_buf Pipebuf;
44
45/* call fail text */
ce5db1eb
SL
46char *Stattext[] = {
47 "",
48 "BAD SYSTEM",
88db71e9 49 "WRONG TIME TO CALL",
ce5db1eb
SL
50 "SYSTEM LOCKED",
51 "NO DEVICE",
2af814a5 52 "CALL FAILED",
ce5db1eb
SL
53 "LOGIN FAILED",
54 "BAD SEQUENCE"
88db71e9 55};
ce5db1eb 56
88db71e9
RC
57/* call fail codes */
58int Stattype[] = {
59 0,
60 0,
61 SS_WRONGTIME,
62 0,
63 SS_NODEVICE,
64 SS_FAIL,
65 SS_FAIL,
66 SS_BADSEQ
67};
ce5db1eb 68
2af814a5
JB
69 /* Arguments to setdebug(): */
70#define DBG_TEMP 0 /* Create a temporary audit file */
71#define DBG_PERM 1 /* Create a permanent audit file */
72#define DBG_CLEAN 2 /* Cleanup, discard temp file */
ce5db1eb 73
88db71e9 74int ReverseRole = 0;
88db71e9 75int Role = SLAVE;
9c672c90
RA
76int InitialRole = SLAVE;
77long StartTime;
88db71e9 78int onesys = 0;
1a85e9d2 79int turntime = 30 * 60; /* 30 minutes expressed in seconds */
2af814a5 80char *ttyn = NULL;
88db71e9 81extern int LocalOnly;
2af814a5 82extern int errno;
1a85e9d2
RC
83extern char MaxGrade, DefMaxGrade;
84extern char Myfullname[];
88db71e9 85
9c672c90
RA
86long Bytes_Sent, Bytes_Received;
87
88db71e9 88#ifdef USG
ce5db1eb
SL
89struct termio Savettyb;
90#endif
88db71e9 91#ifndef USG
ce5db1eb
SL
92struct sgttyb Savettyb;
93#endif
94
274cf361
RA
95#define SETPROCTITLE
96#ifdef SETPROCTITLE
97char **Argv = NULL; /* pointer to argument vector */
98char *LastArgv = NULL; /* end of argv */
99#endif SETPROCTITLE
100
2af814a5
JB
101/*
102 * this program is used to place a call to a
ce5db1eb
SL
103 * remote machine, login, and copy files between the two machines.
104 */
274cf361 105main(argc, argv, envp)
2af814a5 106int argc;
a5c64120 107char **argv;
274cf361 108char **envp;
ce5db1eb
SL
109{
110 register int ret;
111 int seq;
ce5db1eb 112 char wkpre[NAMESIZE], file[NAMESIZE];
2af814a5 113 char msg[MAXFULLNAME], *q;
ce5db1eb 114 register char *p;
41654125
KB
115 static void onintr(), timeout(), dbg_signal();
116 static char *pskip();
a5c64120
RA
117 extern char *optarg;
118 extern int optind;
a534f0fb 119 char rflags[MAXFULLNAME];
4b31fbb4 120#ifdef NOGETPEER
88db71e9 121 u_long Hostnumber = 0;
4b31fbb4 122#endif NOGETPEER
ce5db1eb
SL
123
124 strcpy(Progname, "uucico");
ce5db1eb 125
2ae50b97 126#ifdef BSD4_2
a5c64120 127 sigsetmask(0L); /* in case we inherit blocked signals */
2ae50b97 128#endif BSD4_2
ce5db1eb
SL
129 signal(SIGINT, onintr);
130 signal(SIGHUP, onintr);
131 signal(SIGQUIT, onintr);
132 signal(SIGTERM, onintr);
133 signal(SIGPIPE, onintr); /* 4.1a tcp-ip stupidity */
3d98b35e 134 signal(SIGUSR1, dbg_signal);
ce5db1eb
SL
135 ret = guinfo(getuid(), User, msg);
136 strcpy(Loginuser, User);
4b31fbb4 137 uucpname(Myname);
a5c64120
RA
138 if (ret == FAIL) {
139 syslog(LOG_ERR, "can't get uid");
140 cleanup(FAIL);
141 }
ce5db1eb 142
2af814a5
JB
143 setbuf (stderr, CNULL);
144
145 rflags[0] = '\0';
ce5db1eb
SL
146 umask(WFMASK);
147 strcpy(Rmtname, Myname);
148 Ifn = Ofn = -1;
a5c64120
RA
149 while ((ret = getopt(argc, argv, "RLd:g:p:r:s:x:t:")) != EOF)
150 switch(ret){
ce5db1eb 151 case 'd':
a5c64120 152 Spool = optarg;
ce5db1eb 153 break;
ce5db1eb 154 case 'g':
1a85e9d2 155 case 'p':
a5c64120 156 MaxGrade = DefMaxGrade = *optarg;
ce5db1eb 157 break;
ce5db1eb 158 case 'r':
a5c64120 159 Role = atoi(optarg);
ce5db1eb 160 break;
88db71e9
RC
161 case 'R':
162 ReverseRole++;
163 Role = MASTER;
164 break;
ce5db1eb 165 case 's':
a5c64120 166 strncpy(Rmtname, optarg, MAXBASENAME);
4b31fbb4 167 Rmtname[MAXBASENAME] = '\0';
ce5db1eb
SL
168 if (Rmtname[0] != '\0')
169 onesys = 1;
170 break;
171 case 'x':
a5c64120 172 Debug = atoi(optarg);
ce5db1eb
SL
173 if (Debug <= 0)
174 Debug = 1;
a5c64120 175 strcat(rflags, argv[optind-1]);
ce5db1eb 176 break;
1a85e9d2 177 case 't':
a5c64120 178 turntime = atoi(optarg)*60;/* minutes to seconds */
1a85e9d2 179 break;
88db71e9
RC
180 case 'L': /* local calls only */
181 LocalOnly++;
182 break;
4b31fbb4 183#ifdef NOGETPEER
88db71e9
RC
184 case 'h':
185 Hostnumber = inet_addr(&argv[1][2]);
186 break;
4b31fbb4 187#endif NOGETPEER
a5c64120 188 case '?':
ce5db1eb 189 default:
a5c64120
RA
190 fprintf(stderr, "unknown flag %s (ignored)\n",
191 argv[optind-1]);
ce5db1eb
SL
192 break;
193 }
ce5db1eb 194
a5c64120
RA
195 while (optind < argc)
196 fprintf(stderr, "unknown argument %s (ignored)\n",
197 argv[optind++]);
ce5db1eb 198
f18f4128
JB
199 if (Debug && Role == MASTER)
200 chkdebug();
201
274cf361
RA
202#ifdef SETPROCTITLE
203 /*
204 * Save start and extent of argv for setproctitle.
205 */
206
207 Argv = argv;
208 LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
209#endif SETPROCTITLE
210
01af9d69 211 /* Try to run as uucp */
88db71e9
RC
212 setgid(getegid());
213 setuid(geteuid());
214#ifdef TIOCNOTTY
215 /*
216 * detach uucico from controlling terminal
217 * to defend against rlogind sending us a SIGKILL (!!!)
218 */
c861cac9 219 if (Role == MASTER && (ret = open(_PATH_TTY, 2)) >= 0) {
88db71e9
RC
220 ioctl(ret, TIOCNOTTY, STBNULL);
221 close(ret);
ce5db1eb 222 }
88db71e9
RC
223#endif TIOCNOTTY
224#ifdef BSD4_2
7ebaa22e 225 if (getpgrp(0) == 0) { /* We have no controlling terminal */
88db71e9
RC
226 setpgrp(0, getpid());
227 }
a5c64120
RA
228#ifdef USE_SYSLOG
229#ifdef BSD4_3
230 openlog("uucico", LOG_PID, LOG_UUCP);
231#else /* !BSD4_3 */
232 openlog("uucico", LOG_PID);
233#endif /* !BSD4_3 */
234#endif /* USE_SYSLOG */
88db71e9
RC
235#endif BSD4_2
236
a5c64120
RA
237#ifdef BSD4_3
238 unsetenv("TZ"); /* We don't want him resetting our time zone */
239#endif /* !BSD4_3 */
240
241 if (subchdir(Spool) < 0) {
242 syslog(LOG_ERR, "chdir(%s) failed: %m", Spool);
243 cleanup(FAIL);
244 }
245
88db71e9
RC
246 strcpy(Wrkdir, Spool);
247
2af814a5 248 if (Debug) {
2af814a5
JB
249 setdebug ((Role == SLAVE) ? DBG_TEMP : DBG_PERM);
250 if (Debug > 0)
251 logent ("Local Enabled", "DEBUG");
252 }
253
254 /*
255 * First time through: If we're the slave, do initial checking.
256 */
ce5db1eb 257 if (Role == SLAVE) {
88db71e9 258 /* check for /etc/nologin */
01af9d69 259 if (access(NOLOGIN, 0) == 0) {
88db71e9 260 logent(NOLOGIN, "UUCICO SHUTDOWN");
4b31fbb4 261 if (Debug > 4)
88db71e9
RC
262 logent("DEBUGGING", "continuing anyway");
263 else
264 cleanup(1);
265 }
2af814a5
JB
266 Ifn = 0;
267 Ofn = 1;
88db71e9
RC
268#ifdef TCPIP
269 /*
270 * Determine if we are on TCPIP
271 */
9c672c90 272 if (isatty(Ifn) == 0) {
88db71e9
RC
273 IsTcpIp = 1;
274 DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
4b31fbb4
JB
275 } else
276 IsTcpIp = 0;
88db71e9 277#endif TCPIP
ce5db1eb
SL
278 /* initial handshake */
279 onesys = 1;
88db71e9
RC
280 if (!IsTcpIp) {
281#ifdef USG
2af814a5 282 ret = ioctl(Ifn, TCGETA, &Savettyb);
ce5db1eb
SL
283 Savettyb.c_cflag = (Savettyb.c_cflag & ~CS8) | CS7;
284 Savettyb.c_oflag |= OPOST;
285 Savettyb.c_lflag |= (ISIG|ICANON|ECHO);
88db71e9 286#else !USG
2af814a5 287 ret = ioctl(Ifn, TIOCGETP, &Savettyb);
ce5db1eb
SL
288 Savettyb.sg_flags |= ECHO;
289 Savettyb.sg_flags &= ~RAW;
88db71e9 290#endif !USG
2af814a5 291 ttyn = ttyname(Ifn);
ce5db1eb 292 }
ce5db1eb 293 fixmode(Ifn);
2af814a5
JB
294
295 /*
296 * Initial Message -- tell them we're here, and who we are.
297 */
1a85e9d2 298 sprintf(msg, "here=%s", Myfullname);
88db71e9 299 omsg('S', msg, Ofn);
ce5db1eb 300 signal(SIGALRM, timeout);
9c672c90 301 alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
ce5db1eb
SL
302 if (setjmp(Sjbuf)) {
303 /* timed out */
88db71e9
RC
304 if (!IsTcpIp) {
305#ifdef USG
2af814a5
JB
306 ret = ioctl(Ifn, TCSETA, &Savettyb);
307
4b31fbb4 308#else !USG
2af814a5 309 ret = ioctl(Ifn, TIOCSETP, &Savettyb);
4b31fbb4 310#endif !USG
ce5db1eb 311 }
88db71e9 312 cleanup(0);
ce5db1eb
SL
313 }
314 for (;;) {
315 ret = imsg(msg, Ifn);
2af814a5 316 if (ret != SUCCESS) {
ce5db1eb 317 alarm(0);
88db71e9
RC
318 if (!IsTcpIp) {
319#ifdef USG
2af814a5 320 ret = ioctl(Ifn, TCSETA, &Savettyb);
4b31fbb4 321#else !USG
2af814a5 322 ret = ioctl(Ifn, TIOCSETP, &Savettyb);
4b31fbb4 323#endif !USG
ce5db1eb 324 }
88db71e9 325 cleanup(0);
ce5db1eb
SL
326 }
327 if (msg[0] == 'S')
328 break;
329 }
330 alarm(0);
331 q = &msg[1];
332 p = pskip(q);
4b31fbb4
JB
333 strncpy(Rmtname, q, MAXBASENAME);
334 Rmtname[MAXBASENAME] = '\0';
2af814a5
JB
335
336 /*
337 * Now that we know who they are, give the audit file the right
338 * name.
339 */
340 setdebug (DBG_PERM);
ce5db1eb 341 DEBUG(4, "sys-%s\n", Rmtname);
a534f0fb 342 /* The versys will also do an alias on the incoming name */
4b31fbb4 343 if (versys(&Rmtname)) {
a534f0fb 344#ifdef NOSTRANGERS
9c672c90 345 /* If we don't know them, we won't talk to them... */
a5c64120 346 syslog(LOG_WARNING, "Unknown host: %s", Rmtname);
4b31fbb4
JB
347 omsg('R', "You are unknown to me", Ofn);
348 cleanup(0);
4b31fbb4 349#endif NOSTRANGERS
a534f0fb 350 }
88db71e9
RC
351#ifdef BSDTCP
352 /* we must make sure they are really who they say they
353 * are. We compare the hostnumber with the number in the hosts
354 * table for the site they claim to be.
355 */
356 if (IsTcpIp) {
357 struct hostent *hp;
358 char *cpnt, *inet_ntoa();
2af814a5 359 int fromlen;
88db71e9 360 struct sockaddr_in from;
01af9d69 361 extern char PhoneNumber[];
88db71e9 362
4b31fbb4
JB
363#ifdef NOGETPEER
364 from.sin_addr.s_addr = Hostnumber;
365 from.sin_family = AF_INET;
366#else !NOGETPEER
2af814a5 367 fromlen = sizeof(from);
41654125
KB
368 if (getpeername(Ifn,
369 (struct sockaddr *)&from, &fromlen) < 0) {
88db71e9
RC
370 logent(Rmtname, "NOT A TCP CONNECTION");
371 omsg('R', "NOT TCP", Ofn);
372 cleanup(0);
373 }
4b31fbb4 374#endif !NOGETPEER
41654125 375 hp = gethostbyaddr((char *)&from.sin_addr,
88db71e9 376 sizeof (struct in_addr), from.sin_family);
2af814a5 377 if (hp == NULL) {
88db71e9
RC
378 /* security break or just old host table? */
379 logent(Rmtname, "UNKNOWN IP-HOST Name =");
380 cpnt = inet_ntoa(from.sin_addr),
381 logent(cpnt, "UNKNOWN IP-HOST Number =");
382 sprintf(wkpre, "%s/%s isn't in my host table",
383 Rmtname, cpnt);
384 omsg('R' ,wkpre ,Ofn);
385 cleanup(0);
386 }
2af814a5 387 if (Debug > 99)
88db71e9 388 logent(Rmtname,"Request from IP-Host name =");
01af9d69
JB
389 /*
390 * The following is to determine if the name given us by
391 * the Remote uucico matches any of the names
88db71e9
RC
392 * given its network number (remote machine) in our
393 * host table.
01af9d69
JB
394 * We could check the aliases, but that won't work in
395 * all cases (like if you are running the domain
396 * server, where you don't get any aliases). The only
397 * reliable way I can think of that works in ALL cases
398 * is too look up the site in L.sys and see if the
399 * sitename matches what we would call him if we
400 * originated the call.
88db71e9 401 */
01af9d69
JB
402 /* PhoneNumber contains the official network name of the host we are checking. (set in versys.c) */
403 if (sncncmp(PhoneNumber, hp->h_name, SYSNSIZE) == 0) {
88db71e9
RC
404 if (Debug > 99)
405 logent(q,"Found in host Tables");
01af9d69
JB
406 } else {
407 logent(hp->h_name, "FORGED HOSTNAME");
408 logent(inet_ntoa(from.sin_addr), "ORIGINATED AT");
409 logent(PhoneNumber, "SHOULD BE");
410 sprintf(wkpre, "You're not who you claim to be: %s != %s", hp->h_name, PhoneNumber);
411 omsg('R', wkpre, Ofn);
412 cleanup(0);
88db71e9
RC
413 }
414 }
415#endif BSDTCP
416
2af814a5 417 if (mlock(Rmtname)) {
ce5db1eb
SL
418 omsg('R', "LCK", Ofn);
419 cleanup(0);
420 }
421 else if (callback(Loginuser)) {
422 signal(SIGINT, SIG_IGN);
423 signal(SIGHUP, SIG_IGN);
424 omsg('R', "CB", Ofn);
425 logent("CALLBACK", "REQUIRED");
426 /* set up for call back */
88db71e9 427 systat(Rmtname, SS_CALLBACK, "CALLING BACK");
ce5db1eb
SL
428 gename(CMDPRE, Rmtname, 'C', file);
429 close(creat(subfile(file), 0666));
430 xuucico(Rmtname);
431 cleanup(0);
432 }
433 seq = 0;
434 while (*p == '-') {
435 q = pskip(p);
436 switch(*(++p)) {
ce5db1eb 437 case 'x':
2af814a5
JB
438 if (Debug == 0) {
439 Debug = atoi(++p);
440 if (Debug <= 0)
441 Debug = 1;
442 setdebug(DBG_PERM);
443 if (Debug > 0)
444 logent("Remote Enabled", "DEBUG");
445 } else {
446 DEBUG(1, "Remote debug request ignored\n",
447 CNULL);
448 }
ce5db1eb
SL
449 break;
450 case 'Q':
451 seq = atoi(++p);
452 break;
1a85e9d2
RC
453 case 'p':
454 MaxGrade = DefMaxGrade = *++p;
455 DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
456 break;
4b31fbb4
JB
457 case 'v':
458 if (strncmp(p, "grade", 5) == 0) {
459 p += 6;
460 MaxGrade = DefMaxGrade = *p++;
461 DEBUG(4, "MaxGrade set to %c\n", MaxGrade);
462 }
463 break;
ce5db1eb
SL
464 default:
465 break;
466 }
467 p = q;
468 }
274cf361 469 setproctitle("%s: startup", Rmtname);
ce5db1eb
SL
470 if (callok(Rmtname) == SS_BADSEQ) {
471 logent("BADSEQ", "PREVIOUS");
472 omsg('R', "BADSEQ", Ofn);
473 cleanup(0);
474 }
88db71e9 475#ifdef GNXSEQ
ce5db1eb
SL
476 if ((ret = gnxseq(Rmtname)) == seq) {
477 omsg('R', "OK", Ofn);
478 cmtseq();
88db71e9
RC
479 } else {
480#else !GNXSEQ
481 if (seq == 0)
482 omsg('R', "OK", Ofn);
ce5db1eb 483 else {
88db71e9 484#endif !GNXSEQ
ce5db1eb 485 systat(Rmtname, Stattype[7], Stattext[7]);
4b31fbb4 486 logent("BAD SEQ", "FAILED HANDSHAKE");
88db71e9 487#ifdef GNXSEQ
ce5db1eb 488 ulkseq();
88db71e9 489#endif GNXSEQ
ce5db1eb
SL
490 omsg('R', "BADSEQ", Ofn);
491 cleanup(0);
492 }
ce5db1eb
SL
493 if (ttyn != NULL)
494 chmod(ttyn, 0600);
495 }
88db71e9 496
ce5db1eb 497loop:
88db71e9
RC
498 if(setjmp(Pipebuf)) { /* come here on SIGPIPE */
499 clsacu();
274cf361 500 logcls();
88db71e9
RC
501 close(Ofn);
502 close(Ifn);
503 Ifn = Ofn = -1;
504 rmlock(CNULL);
505 sleep(3);
506 }
ce5db1eb 507 if (!onesys) {
9c672c90 508 do_connect_accounting();
a5c64120
RA
509#ifdef DIALINOUT
510 /* reenable logins on dialout */
511 reenable();
512#endif DIALINOUT
9c672c90 513 StartTime = 0;
274cf361 514 setproctitle("looking for work");
ce5db1eb 515 ret = gnsys(Rmtname, Spool, CMDPRE);
274cf361 516 setproctitle("%s: startup", Rmtname);
2af814a5 517 setdebug(DBG_PERM);
ce5db1eb
SL
518 if (ret == FAIL)
519 cleanup(100);
9c672c90 520 else if (ret == SUCCESS)
ce5db1eb 521 cleanup(0);
274cf361 522 logcls();
88db71e9 523 } else if (Role == MASTER && callok(Rmtname) != 0) {
ce5db1eb
SL
524 logent("SYSTEM STATUS", "CAN NOT CALL");
525 cleanup(0);
526 }
527
4b31fbb4 528 sprintf(wkpre, "%c.%.*s", CMDPRE, SYSNSIZE, Rmtname);
9c672c90
RA
529 StartTime = 0;
530 Bytes_Sent = Bytes_Received = 0L;
ce5db1eb 531
88db71e9
RC
532 signal(SIGINT, SIG_IGN);
533 signal(SIGQUIT, SIG_IGN);
ce5db1eb 534 if (Role == MASTER) {
9c672c90 535 extern char LineType[];
88db71e9 536 /* check for /etc/nologin */
01af9d69 537 if (access(NOLOGIN, 0) == 0) {
88db71e9 538 logent(NOLOGIN, "UUCICO SHUTDOWN");
4b31fbb4 539 if (Debug > 4)
88db71e9
RC
540 logent("DEBUGGING", "continuing anyway");
541 else
542 cleanup(1);
543 }
ce5db1eb 544 /* master part */
ce5db1eb 545 signal(SIGHUP, SIG_IGN);
ce5db1eb
SL
546 if (Ifn != -1 && Role == MASTER) {
547 write(Ofn, EOTMSG, strlen(EOTMSG));
548 clsacu();
549 close(Ofn);
550 close(Ifn);
551 Ifn = Ofn = -1;
552 rmlock(CNULL);
553 sleep(3);
554 }
01af9d69 555 if (mlock(Rmtname) != SUCCESS) {
9c672c90 556 DEBUG(1, "LOCKED: call to %s\n", Rmtname);
88db71e9 557 US_SST(us_s_lock);
ce5db1eb
SL
558 goto next;
559 }
274cf361 560 setproctitle("%s: starting call", Rmtname);
ce5db1eb 561 Ofn = Ifn = conn(Rmtname);
274cf361 562 sprintf(msg, "(call to %s via %s)", Rmtname, LineType);
ce5db1eb 563 if (Ofn < 0) {
88db71e9
RC
564 if (Ofn != CF_TIME)
565 logent(msg, _FAILED);
566 /* avoid excessive 'wrong time' info */
4b31fbb4 567 if (Stattype[-Ofn] != SS_WRONGTIME){
88db71e9
RC
568 systat(Rmtname, Stattype[-Ofn], Stattext[-Ofn]);
569 US_SST(-Ofn);
570 UB_SST(-Ofn);
571 }
ce5db1eb 572 goto next;
88db71e9 573 } else {
ce5db1eb 574 logent(msg, "SUCCEEDED");
88db71e9
RC
575 US_SST(us_s_cok);
576 UB_SST(ub_ok);
577 }
9c672c90 578 InitialRole = MASTER;
88db71e9
RC
579#ifdef TCPIP
580 /*
581 * Determine if we are on TCPIP
582 */
2af814a5 583 if (isatty(Ifn) == 0) {
88db71e9
RC
584 IsTcpIp = 1;
585 DEBUG(4, "TCPIP connection -- ioctl-s disabled\n", CNULL);
4b31fbb4
JB
586 } else
587 IsTcpIp = 0;
88db71e9
RC
588#endif
589
ce5db1eb
SL
590 if (setjmp(Sjbuf))
591 goto next;
592 signal(SIGALRM, timeout);
9c672c90 593 alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME*2);
ce5db1eb
SL
594 for (;;) {
595 ret = imsg(msg, Ifn);
9c672c90 596 if (ret != SUCCESS) {
ce5db1eb 597 alarm(0);
9c672c90 598 DEBUG(4,"\nimsg failed: errno %d\n", errno);
88db71e9
RC
599 logent("imsg 1", _FAILED);
600 goto Failure;
ce5db1eb
SL
601 }
602 if (msg[0] == 'S')
603 break;
604 }
9c672c90 605 alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
88db71e9 606#ifdef GNXSEQ
ce5db1eb 607 seq = gnxseq(Rmtname);
88db71e9
RC
608#else !GNXSEQ
609 seq = 0;
610#endif !GNXSEQ
1a85e9d2 611 if (MaxGrade != '\177') {
4b31fbb4 612 DEBUG(2, "Max Grade this transfer is %c\n", MaxGrade);
9313cec6
JB
613 sprintf(msg, "%s -Q%d -p%c -vgrade=%c %s",
614 Myname, seq, MaxGrade, MaxGrade, rflags);
615 } else
616 sprintf(msg, "%s -Q%d %s", Myname, seq, rflags);
ce5db1eb
SL
617 omsg('S', msg, Ofn);
618 for (;;) {
619 ret = imsg(msg, Ifn);
620 DEBUG(4, "msg-%s\n", msg);
88db71e9 621 if (ret != SUCCESS) {
ce5db1eb 622 alarm(0);
88db71e9 623#ifdef GNXSEQ
ce5db1eb 624 ulkseq();
88db71e9
RC
625#endif GNXSEQ
626 logent("imsg 2", _FAILED);
627 goto Failure;
ce5db1eb
SL
628 }
629 if (msg[0] == 'R')
630 break;
631 }
632 alarm(0);
633 if (msg[1] == 'B') {
634 /* bad sequence */
4b31fbb4 635 logent("BAD SEQ", "FAILED HANDSHAKE");
88db71e9
RC
636 US_SST(us_s_hand);
637 systat(Rmtname, SS_BADSEQ, Stattext[SS_BADSEQ]);
638#ifdef GNXSEQ
ce5db1eb 639 ulkseq();
88db71e9 640#endif GNXSEQ
ce5db1eb
SL
641 goto next;
642 }
643 if (strcmp(&msg[1], "OK") != SAME) {
4b31fbb4 644 logent(&msg[1], "FAILED HANDSHAKE");
88db71e9
RC
645 US_SST(us_s_hand);
646#ifdef GNXSEQ
ce5db1eb 647 ulkseq();
88db71e9
RC
648#endif GNXSEQ
649 systat(Rmtname, SS_INPROGRESS,
650 strcmp(&msg[1], "CB") == SAME?
4b31fbb4 651 "AWAITING CALLBACK": "FAILED HANDSHAKE");
ce5db1eb
SL
652 goto next;
653 }
88db71e9 654#ifdef GNXSEQ
ce5db1eb 655 cmtseq();
88db71e9 656#endif GNXSEQ
ce5db1eb 657 }
88db71e9 658 DEBUG(1, "Rmtname %s, ", Rmtname);
ce5db1eb
SL
659 DEBUG(1, "Role %s, ", Role ? "MASTER" : "SLAVE");
660 DEBUG(1, "Ifn - %d, ", Ifn);
661 DEBUG(1, "Loginuser - %s\n", Loginuser);
274cf361 662 setproctitle("%s: %s", Rmtname, Role ? "MASTER" : "SLAVE");
ce5db1eb 663
2af814a5
JB
664 ttyn = ttyname(Ifn);
665
9c672c90 666 alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
1a85e9d2 667 if (ret=setjmp(Sjbuf))
ce5db1eb
SL
668 goto Failure;
669 ret = startup(Role);
670 alarm(0);
671 if (ret != SUCCESS) {
274cf361 672 logent("(startup)", _FAILED);
ce5db1eb 673Failure:
88db71e9 674 US_SST(us_s_start);
1a85e9d2
RC
675 systat(Rmtname, SS_FAIL, ret > 0 ? "CONVERSATION FAILED" :
676 "STARTUP FAILED");
ce5db1eb 677 goto next;
88db71e9 678 } else {
9c672c90
RA
679 char smsg[BUFSIZ], gmsg[10], pmsg[20], bpsmsg[20];
680 extern char UsingProtocol;
681 extern int linebaudrate;
682 if (ttyn != NULL)
683 sprintf(bpsmsg, " %s %d bps", &ttyn[5], linebaudrate);
684 else
685 bpsmsg[0] = '\0';
686 if (UsingProtocol != 'g')
687 sprintf(pmsg, " %c protocol", UsingProtocol);
688 else
689 pmsg[0] = '\0';
690 if (MaxGrade != '\177')
691 sprintf(gmsg, " grade %c", MaxGrade);
692 else
693 gmsg[0] = '\0';
274cf361 694 sprintf(smsg, "(startup%s%s%s)", bpsmsg, pmsg, gmsg);
9c672c90 695 logent(smsg, "OK");
88db71e9 696 US_SST(us_s_gress);
9c672c90 697 StartTime = Now.time;
ce5db1eb
SL
698 systat(Rmtname, SS_INPROGRESS, "TALKING");
699 ret = cntrl(Role, wkpre);
700 DEBUG(1, "cntrl - %d\n", ret);
701 signal(SIGINT, SIG_IGN);
702 signal(SIGHUP, SIG_IGN);
703 signal(SIGALRM, timeout);
274cf361 704 sprintf(smsg, "(conversation complete %ld sent %ld received)",
9c672c90 705 Bytes_Sent, Bytes_Received);
88db71e9 706 if (ret == SUCCESS) {
9c672c90 707 logent(smsg, "OK");
88db71e9 708 US_SST(us_s_ok);
ce5db1eb
SL
709 rmstat(Rmtname);
710
88db71e9 711 } else {
9c672c90 712 logent(smsg, _FAILED);
88db71e9
RC
713 US_SST(us_s_cf);
714 systat(Rmtname, SS_FAIL, "CONVERSATION FAILED");
ce5db1eb 715 }
9c672c90 716 alarm(IsTcpIp?MAXMSGTIME*4:MAXMSGTIME);
ce5db1eb
SL
717 DEBUG(4, "send OO %d,", ret);
718 if (!setjmp(Sjbuf)) {
719 for (;;) {
720 omsg('O', "OOOOO", Ofn);
721 ret = imsg(msg, Ifn);
722 if (ret != 0)
723 break;
724 if (msg[0] == 'O')
725 break;
726 }
727 }
728 alarm(0);
88db71e9
RC
729 clsacu();
730 rmlock(CNULL);
9c672c90 731
ce5db1eb
SL
732 }
733next:
734 if (!onesys) {
735 goto loop;
736 }
737 cleanup(0);
738}
739
88db71e9 740#ifndef USG
ce5db1eb
SL
741struct sgttyb Hupvec;
742#endif
743
2af814a5
JB
744/*
745 * cleanup and exit with "code" status
ce5db1eb 746 */
ce5db1eb
SL
747cleanup(code)
748register int code;
749{
ce5db1eb
SL
750 signal(SIGINT, SIG_IGN);
751 signal(SIGHUP, SIG_IGN);
752 rmlock(CNULL);
2af814a5 753 sleep(5); /* Wait for any pending output */
ce5db1eb
SL
754 clsacu();
755 logcls();
756 if (Role == SLAVE) {
88db71e9
RC
757 if (!IsTcpIp) {
758#ifdef USG
ce5db1eb 759 Savettyb.c_cflag |= HUPCL;
4b31fbb4 760 (void) ioctl(0, TCSETA, &Savettyb);
88db71e9 761#else !USG
4b31fbb4 762 (void) ioctl(0, TIOCHPCL, STBNULL);
1a85e9d2 763#ifdef TIOCSDTR
4b31fbb4 764 (void) ioctl(0, TIOCCDTR, STBNULL);
1a85e9d2 765 sleep(2);
4b31fbb4 766 (void) ioctl(0, TIOCSDTR, STBNULL);
1a85e9d2 767#else !TIOCSDTR
4b31fbb4 768 (void) ioctl(0, TIOCGETP, &Hupvec);
ce5db1eb
SL
769 Hupvec.sg_ispeed = B0;
770 Hupvec.sg_ospeed = B0;
4b31fbb4 771 (void) ioctl(0, TIOCSETP, &Hupvec);
2af814a5 772#endif !TIOCSDTR
ce5db1eb 773 sleep(2);
4b31fbb4 774 (void) ioctl(0, TIOCSETP, &Savettyb);
88db71e9 775 /* make *sure* exclusive access is off */
4b31fbb4 776 (void) ioctl(0, TIOCNXCL, STBNULL);
88db71e9 777#endif !USG
ce5db1eb 778 }
ce5db1eb
SL
779 if (ttyn != NULL)
780 chmod(ttyn, 0600);
781 }
782 if (Ofn != -1) {
783 if (Role == MASTER)
784 write(Ofn, EOTMSG, strlen(EOTMSG));
785 close(Ifn);
786 close(Ofn);
787 }
1a85e9d2
RC
788#ifdef DIALINOUT
789 /* reenable logins on dialout */
790 reenable();
791#endif DIALINOUT
ce5db1eb
SL
792 if (code == 0)
793 xuuxqt();
88db71e9
RC
794 else
795 DEBUG(1, "exit code %d\n", code);
2af814a5 796 setdebug (DBG_CLEAN);
9c672c90 797 do_connect_accounting();
ce5db1eb
SL
798 exit(code);
799}
800
9c672c90
RA
801do_connect_accounting()
802{
a5c64120 803#ifdef DO_CONNECT_ACCOUNTING
9c672c90
RA
804 register FILE *fp;
805 struct tm *localtime();
806 register struct tm *tm;
807 int flags;
808
809 if (StartTime == 0)
810 return;
811
a5c64120
RA
812 fp = fopen(DO_CONNECT_ACCOUNTING, "a");
813 if (fp == NULL) {
814 syslog(LOG_ALERT, "fopen(%s) failed: %m",DO_CONNECT_ACCOUNTING);
815 cleanup(FAIL);
816 }
9c672c90
RA
817
818 tm = localtime(&StartTime);
819#ifdef F_SETFL
820 flags = fcntl(fileno(fp), F_GETFL, 0);
821 fcntl(fileno(fp), F_SETFL, flags|O_APPEND);
822#endif
823#ifdef USG
824 fprintf(fp,"%s %d %d%.2d%.2d %.2d%.2d %d %ld %s %ld %ld\n",
825#else /* V7 */
826 fprintf(fp,"%s %d %d%02d%02d %02d%02d %d %ld %s %ld %ld\n",
827#endif /* V7 */
828 Rmtname, InitialRole, tm->tm_year, tm->tm_mon + 1,
829 tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_wday,
830 (Now.time - StartTime + 59) / 60,
831 ttyn == NULL ? "ttyp0" : &ttyn[5],
832 Bytes_Sent, Bytes_Received);
833 fclose(fp);
834#endif /* DO_CONNECT_ACCOUNTING */
835}
836
2af814a5
JB
837/*
838 * on interrupt - remove locks and exit
ce5db1eb
SL
839 */
840
41654125 841static void
ce5db1eb
SL
842onintr(inter)
843register int inter;
844{
9c672c90 845 char str[BUFSIZ];
ce5db1eb 846 signal(inter, SIG_IGN);
274cf361 847 sprintf(str, "(SIGNAL %d)", inter);
ce5db1eb 848 logent(str, "CAUGHT");
88db71e9 849 US_SST(us_s_intr);
4b31fbb4 850 if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME))
88db71e9 851 systat(Rmtname, SS_FAIL, str);
274cf361 852 sprintf(str, "(conversation complete %ld sent %ld received)",
9c672c90
RA
853 Bytes_Sent, Bytes_Received);
854 logent(str, _FAILED);
88db71e9
RC
855 if (inter == SIGPIPE && !onesys)
856 longjmp(Pipebuf, 1);
ce5db1eb
SL
857 cleanup(inter);
858}
859
ce5db1eb
SL
860/*
861 * Catch a special signal
3d98b35e 862 * (SIGUSR1), and toggle debugging between 0 and 30.
ce5db1eb
SL
863 * Handy for looking in on long running uucicos.
864 */
41654125 865static void
2af814a5 866dbg_signal()
ce5db1eb 867{
2af814a5
JB
868 Debug = (Debug == 0) ? 30 : 0;
869 setdebug(DBG_PERM);
870 if (Debug > 0)
871 logent("Signal Enabled", "DEBUG");
ce5db1eb
SL
872}
873
874
2af814a5
JB
875/*
876 * Check debugging requests, and open RMTDEBUG audit file if necessary. If an
877 * audit file is needed, the parm argument indicates how to create the file:
878 *
879 * DBG_TEMP - Open a temporary file, with filename = RMTDEBUG/pid.
880 * DBG_PERM - Open a permanent audit file, filename = RMTDEBUG/Rmtname.
881 * If a temp file already exists, it is mv'ed to be permanent.
882 * DBG_CLEAN - Cleanup; unlink temp files.
ce5db1eb 883 *
2af814a5
JB
884 * Restrictions - this code can only cope with one open debug file at a time.
885 * Each call creates a new file; if an old one of the same name exists it will
886 * be overwritten.
ce5db1eb 887 */
2af814a5
JB
888setdebug(parm)
889int parm;
ce5db1eb 890{
2af814a5
JB
891 char buf[BUFSIZ]; /* Buffer for building filenames */
892 static char *temp = NULL; /* Ptr to temporary file name */
893 static int auditopen = 0; /* Set to 1 when we open a file */
894 struct stat stbuf; /* File status buffer */
ce5db1eb 895
2af814a5
JB
896 /*
897 * If movement or cleanup of a temp file is indicated, we do it no
898 * matter what.
899 */
900 if (temp != CNULL && parm == DBG_PERM) {
901 sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
902 unlink(buf);
903 if (link(temp, buf) != 0) {
904 Debug = 0;
a5c64120
RA
905 syslog(LOG_ERR, "RMTDEBUG link(%s,%s) failed: %m",
906 temp, buf);
907 cleanup(FAIL);
2af814a5
JB
908 }
909 parm = DBG_CLEAN;
910 }
911 if (parm == DBG_CLEAN) {
912 if (temp != CNULL) {
913 unlink(temp);
914 free(temp);
915 temp = CNULL;
916 }
ce5db1eb 917 return;
2af814a5 918 }
ce5db1eb 919
2af814a5
JB
920 if (Debug == 0)
921 return; /* Gotta be in debug to come here. */
922
923 /*
924 * If we haven't opened a file already, we can just return if it's
925 * alright to use the stderr we came in with. We can if:
926 *
927 * Role == MASTER, and Stderr is a regular file, a TTY or a pipe.
928 *
929 * Caution: Detecting when stderr is a pipe is tricky, because the 4.2
930 * man page for fstat(2) disagrees with reality, and System V leaves it
931 * undefined, which means different implementations act differently.
932 */
933 if (!auditopen && Role == MASTER) {
934 if (isatty(fileno(stderr)))
935 return;
936 else if (fstat(fileno(stderr), &stbuf) == 0) {
937#ifdef USG
938 /* Is Regular File or Fifo */
939 if ((stbuf.st_mode & 0060000) == 0)
940 return;
941#else !USG
942#ifdef BSD4_2
943 /* Is Regular File */
944 if ((stbuf.st_mode & S_IFMT) == S_IFREG ||
945 stbuf.st_mode == 0) /* Is a pipe */
946 return;
947#else !BSD4_2
948 /* Is Regular File or Pipe */
949 if ((stbuf.st_mode & S_IFMT) == S_IFREG)
950 return;
951#endif BSD4_2
952#endif USG
953 }
954 }
955
956 /*
957 * We need RMTDEBUG directory to do auditing. If the file doesn't exist,
958 * then we forget about debugging; if it exists but has improper owner-
959 * ship or modes, we gripe about it in ERRLOG.
960 */
961 if (stat(RMTDEBUG, &stbuf) != SUCCESS) {
962 Debug = 0;
963 return;
964 }
965 if ((geteuid() != stbuf.st_uid) || /* We must own it */
966 ((stbuf.st_mode & 0170700) != 040700)) { /* Directory, rwx */
967 Debug = 0;
a5c64120
RA
968 syslog(LOG_ERR, "%s: invalid directory mode: %o", RMTDEBUG,
969 stbuf.st_mode);
2af814a5
JB
970 return;
971 }
972
973 if (parm == DBG_TEMP) {
974 sprintf(buf, "%s/%d", RMTDEBUG, getpid());
975 temp = malloc(strlen (buf) + 1);
976 if (temp == CNULL) {
977 Debug = 0;
a5c64120
RA
978 syslog(LOG_ERR, "RMTDEBUG malloc failed: %m");
979 cleanup(FAIL);
2af814a5
JB
980 }
981 strcpy(temp, buf);
982 } else
983 sprintf(buf, "%s/%s", RMTDEBUG, Rmtname);
984
985 unlink(buf);
986 if (freopen(buf, "w", stderr) != stderr) {
987 Debug = 0;
a5c64120
RA
988 syslog(LOG_ERR, "RMTDEBUG freopen(%s) failed: %m", buf);
989 cleanup(FAIL);
2af814a5
JB
990 }
991 setbuf(stderr, CNULL);
992 auditopen = 1;
993}
ce5db1eb 994
4b31fbb4 995/*
2af814a5 996 * catch SIGALRM routine
ce5db1eb 997 */
41654125 998static void
ce5db1eb
SL
999timeout()
1000{
4b31fbb4
JB
1001 extern int HaveSentHup;
1002 if (!HaveSentHup) {
1003 logent(Rmtname, "TIMEOUT");
1004 if (*Rmtname && strncmp(Rmtname, Myname, MAXBASENAME)) {
1005 US_SST(us_s_tmot);
1006 systat(Rmtname, SS_FAIL, "TIMEOUT");
1007 }
88db71e9 1008 }
ce5db1eb
SL
1009 longjmp(Sjbuf, 1);
1010}
1011
1012static char *
1013pskip(p)
1014register char *p;
1015{
88db71e9 1016 while(*p && *p != ' ')
ce5db1eb 1017 ++p;
4b31fbb4 1018 while(*p && *p == ' ')
88db71e9
RC
1019 *p++ = 0;
1020 return p;
ce5db1eb 1021}
274cf361
RA
1022
1023/*
1024 * clobber argv so ps will show what we're doing.
1025 * stolen from sendmail
1026 */
1027/*VARARGS1*/
1028setproctitle(fmt, a, b, c)
1029char *fmt;
1030{
1031#ifdef SETPROCTITLE
1032 register char *p;
1033 register int i;
1034 extern char **Argv;
1035 extern char *LastArgv;
1036 char buf[BUFSIZ];
1037
1038 (void) sprintf(buf, fmt, a, b, c);
1039
1040 /* make ps print "(sendmail)" */
1041 p = Argv[0];
1042 *p++ = '-';
1043
1044 i = strlen(buf);
1045 if (i > LastArgv - p - 2) {
1046 i = LastArgv - p - 2;
1047 buf[i] = '\0';
1048 }
1049 (void) strcpy(p, buf);
1050 p += i;
1051 while (p < LastArgv)
1052 *p++ = ' ';
1053#endif SETPROCTITLE
1054}