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