|
|
1.1 root 1: /*
2: * dcpsys.c
3: *
4: * System File Parsing and Initial Login Negotiation Routines for uucico
5: */
6:
7: /* #include <sys/dir.h> */
8: #include "dirent.h"
9: #include <ctype.h>
10: #include "dcp.h"
11: #include "lsys.h"
12:
13: /*
14: * Communication Protocol Declarations and Definitions
15: */
16:
17: #define PROTOS "g"
18: int (*getpkt)(), (*sendpkt)(), (*openpk)(), (*closepk)();
19:
20: extern int ggetpkt(), gsendpkt(), gopenpk(), gclosepk();
21: #if 0
22: extern int kgetpkt(), ksendpkt(), kopenpk(), kclosepk();
23: extern int rgetpkt(), rsendpkt(), ropenpk(), rclosepk();
24: extern int tgetpkt(), tsendpkt(), topenpk(), tclosepk();
25: #endif
26:
27: typedef struct proto {
28: char type; /* One character Protocol Type */
29: int (*getpkt)(); /* Get Packet Function */
30: int (*sendpkt)(); /* Send Packet Function */
31: int (*openpk)(); /* Open Packet Function */
32: int (*closepk)(); /* Close Packet Function */
33: } PROTO;
34:
35: PROTO protolst[] =
36: {
37: { 'g', ggetpkt, gsendpkt, gopenpk, gclosepk },
38: #if 0
39: { 'k', kgetpkt, ksendpkt, kopenpk, kclosepk },
40: { 'r', rgetpkt, rsendpkt, ropenpk, rclosepk },
41: { 't', tgetpkt, tsendpkt, topenpk, tclosepk },
42: #endif
43: { '\0' }
44: };
45:
46: int leavelock = 0; /* Leave the rmtname lock file */
47:
48: /*
49: * getsystem()
50: * Retrieve and Process an "L.sys" file entry.
51: */
52:
53: getsystem()
54: {
55: if ( lsys_next() == 0 )
56: return('A');
57:
58: rmtname = lsys_value(sys_e);
59: if ( strcmp(rmtname, sysname) ) {
60: if ( strcmp(sysname, "all") && strcmp(sysname, "any") )
61: return('I');
62: if ( scandir() != 'S' )
63: return('I');
64: }
65: printmsg(M_CALL, "Thinking of calling system: %s", rmtname);
66: if ( !checktime(lsys_value(sched_e)) )
67: return('I');
68:
69: open_the_logfile("uucico");
70: if (cfp != NULL)
71: fclose(cfp); /* in case matched scandir */
72: if ( lockit(rmtname) < 0 ) {
73: plog(M_CALL, "Site Locked: %s", rmtname);
74: close_logfile();
75: return('I');
76: }
77: return('S');
78: }
79:
80: /*
81: * checkrmt()
82: * Scan through L.sys file to verify that we know about the given
83: * remote system name.
84: * Returns: (1) if we found match, (0) if rmtname unknown.
85: */
86:
87: checkrmt()
88: {
89: lsys_open();
90: while ( lsys_next() ) {
91: if ( strcmp(rmtname, lsys_value(sys_e)) == 0 )
92: return(1);
93: }
94: lsys_close();
95: return(0);
96: }
97:
98: /*
99: * rmsg(msg, maxlen) char *msg; int maxlen;
100: * Read a ^P (DLE) type msg from the remote uucp. (startup negotiation).
101: *
102: * wmsg(msg) char *msg;
103: * Write a ^P (DLE) type msg to the remote uucp. (startup negotiation).
104: */
105:
106: #define MAXDROP 2048 /* Maximum characters to drop waiting for ^P */
107:
108: rmsg(msg, maxlen)
109: char *msg;
110: int maxlen;
111: {
112: char ch;
113: register char *cp;
114: int i;
115:
116: for (i=0; i<MAXDROP; i++) {
117: if ( sread(&ch, 1, MSGTIME) != 1 )
118: goto badrmsg;
119: if ( ch == DLE )
120: break;
121: }
122: if ( ch != DLE )
123: goto nodle;
124:
125: for (cp=msg,i=1; i<maxlen; i++) {
126: if ( sread(&ch, 1, MSGTIME) != 1 )
127: goto badrmsg;
128: if ( (ch == '\0') || (ch == '\r') || (ch == '\n') )
129: break;
130: *cp++ = ch;
131: }
132: *cp = '\0';
133: printmsg(M_DEBUG, "rmsg {%s}", visib(msg));
134: return( strlen(msg) );
135:
136: badrmsg:
137: *cp = '\0';
138: printmsg(M_CALL, "Bad received message {%s}", visib(msg));
139: return(-1);
140: nodle:
141: *cp = '\0';
142: printmsg(M_CALL, "Remote machine not sending DLE startup (uucico)");
143: return(-1);
144: }
145:
146: wmsg(msg)
147: char *msg;
148: {
149: char buf[2] = {'\0', DLE};
150:
151: printmsg(M_DEBUG, "wmsg {%s}", visib(msg));
152: swrite(&buf[0], 2);
153: swrite(msg, strlen(msg));
154: swrite(&buf[0], 1);
155: }
156:
157: /*
158: * startup()
159: *
160: * Initiate communication with a remote uucp.
161: */
162:
163: #define FAIL1(x) {errmsg=(x); errarg=NULL; goto failure;}
164: #define FAIL2(x, y) {errmsg=(x); errarg=(y); goto failure;}
165:
166: startup()
167: {
168: char msg[BUFSIZ];
169: char *errmsg, *errarg, *cp, ch;
170: static char locbuf[SITELEN+1];
171: static char *readymsg = "Ready for transactions";
172:
173: sysended = 0;
174: leavelock = 0;
175: if (role == MASTER) {
176: if ( rmsg(msg, BUFSIZ) < 0 )
177: FAIL1("Logon failed: 1st msg (broken communication?)");
178: printmsg(M_CALLMSG, "1st msg = {%s}", visib(msg));
179:
180: if ( strncmp(msg, "Shere", 5) )
181: FAIL1("Bad format for 1st msg");
182: if ( (msg[5] == '\0') || (msg[5] == '\n') ||
183: (msg[6] == '\0') || (msg[6] == '\n') )
184: plog(M_CALL, "Warning: Null sitename contacted");
185: else if ( strncmp(&msg[6], rmtname, SITESIG) )
186: FAIL2("Incorrect sitename contacted: %s", &msg[6]);
187:
188: sprintf(msg, "S%.*s -Q0 -x%d", SITESIG, nodename, debuglevel);
189: printmsg(M_CALLMSG, "Reply to 1st msg = {%s}", msg);
190: wmsg(msg);
191:
192: if ( rmsg(msg, BUFSIZ) < 0 )
193: FAIL1("Logon failed: 2nd msg (remote site stale LCK?)");
194:
195: printmsg(M_CALLMSG, "2nd msg = {%s}", visib(msg));
196: if ( strncmp(msg, "ROK", 2) )
197: FAIL1("Bad format for 2nd msg");
198:
199: if ( rmsg(msg, BUFSIZ) < 0 )
200: FAIL1("Logon failed: 3rd msg (broken communication?)");
201: printmsg(M_CALLMSG, "3rd msg = {%s}", visib(msg));
202: if ( *msg != 'P' )
203: FAIL1("Bad format for 3rd msg");
204: ch = 'N';
205: for (cp=PROTOS; *cp; cp++)
206: if ( index(&msg[1], *cp) != NULL ) {
207: ch = *cp;
208: break;
209: }
210: sprintf(msg, "U%c", ch);
211: printmsg(M_CALLMSG, "Reply to 3rd msg = {%s}", msg);
212: wmsg(msg);
213: if ( ch == 'N' )
214: FAIL1("No common protocol");
215: setproto(ch);
216: plog(M_CALL, readymsg);
217: return('D');
218: } else {
219: sprintf(msg, "Shere=%s", nodename);
220: printmsg(M_CALLMSG, "1st msg = {%s}", msg);
221: wmsg(msg);
222:
223: if ( rmsg(msg, BUFSIZ) < 0 )
224: FAIL1("Logon failed: 1st reply (wrong sitename?)");
225: printmsg(M_CALLMSG, "Reply to 1st msg = {%s}", visib(msg));
226: if ( *msg != 'S' )
227: FAIL1("Bad format for reply to 1st msg");
228: if ( (cp=index(msg+1, ' ')) != NULL )
229: *cp = '\0';
230: if ( strlen(msg) > (SITELEN+1) )
231: FAIL1("Received sitename to long");
232: strcpy(locbuf, msg+1);
233: rmtname = &locbuf[0];
234: #ifdef BBS
235: #define BBSUSER "bbsuser"
236:
237: /*
238: * For BBS, anonymous caller's sitename is replaced by the
239: * device name, notice we skip over "/dev/".
240: */
241: {
242: char *tmp;
243:
244: if ( (strcmp(rmtname, BBSUSER) == 0) &&
245: ((tmp=ttyname(fileno(stdin))) != NULL) )
246: sprintf(locbuf, "U%s", tmp+5);
247: printmsg(M_DEBUG, "BBS replaced new rmtname: <%s>",
248: rmtname);
249: }
250: #endif
251: open_the_logfile("uucico");
252: plog(M_CALL, "Call received from %s {%d} (V%s)",
253: rmtname, processid, version);
254: plog(M_CALL,"Locking remote site %s",rmtname);
255: if ( lockit(rmtname) < 0 ) {
256: leavelock = 1;
257: FAIL2("Incoming site %s already locked", rmtname);
258: }
259:
260: if ( !checkrmt() )
261: FAIL2("Unknown host %s", rmtname);
262:
263: if ( (rdevname=ttyname(fileno(stdin))) == NULL )
264: FAIL1("No attached tty device.");
265: rdevname += 5;
266:
267: /* The incoming device will already have been locked by login. */
268: if (MASTER == role) {
269: if ( locktty(rdevname) < 0 ) {
270: cp = rdevname;
271: rdevname = NULL;
272: FAIL2("Incoming device locked: %s", cp);
273: }
274: }
275:
276: sprintf(msg, "ROK");
277: printmsg(M_CALLMSG, "2nd msg = {%s}", msg);
278: wmsg(msg);
279: sprintf(msg, "P%s", PROTOS);
280: printmsg(M_CALLMSG, "3rd msg = {%s}", msg);
281: wmsg(msg);
282: if ( rmsg(msg, BUFSIZ) < 0 )
283: FAIL1("Logon failure: 3rd reply (lost communication?)");
284: printmsg(M_CALLMSG, "Reply to 3rd msg = {%s}", visib(msg));
285: if ( (msg[0] != 'U') || (index(PROTOS, msg[1]) == NULL) )
286: FAIL1("No common communications protocol");
287: setproto(msg[1]);
288: plog(M_CALL, readymsg);
289: return('R');
290: }
291:
292: failure:
293: plog(M_CALL, errmsg, errarg);
294: terminatelevel++;
295: return('Y');
296: }
297:
298: /*
299: * Assign the global protocol function variables to the specified
300: * protocol type.
301: */
302:
303: setproto(type)
304: char type;
305: {
306: register PROTO *p;
307:
308: for(p=&protolst[0]; (p->type!='\0') && (p->type!=type); p++) ;
309:
310: if (p->type == '\0')
311: fatal("setproto('%c'): Unknown protocol type", type);
312: printmsg(M_CALL, "Agreed protocol: %c", type);
313: getpkt = p->getpkt;
314: sendpkt = p->sendpkt;
315: openpk = p->openpk;
316: closepk = p->closepk;
317:
318: }
319:
320: /*
321: * expectstr(str, timeout) char *str; int timeout;
322: *
323: * Wait to receive the specified "str" from the serial connection.
324: * Returns: (1) if string received,
325: * (0) for timeout occurred before string received.
326: */
327:
328: expectstr(str, timeout)
329: char *str;
330: int timeout;
331: {
332: register char *cp;
333: char buf[BUFSIZ], ch;
334: int retval = 0;
335: int len;
336:
337: printmsg(M_DEBUG, "waiting for {%s}", str);
338:
339: if ( strcmp(str, "\"\"") == 0 )
340: retval = 1;
341: len = strlen(str);
342:
343: cp = &buf[0];
344: while ( !retval && (sread(&ch, 1, timeout) == 1) ) {
345: *cp++ = ch;
346: if ( (cp-buf) < len )
347: continue;
348: *cp = '\0';
349: if ( strncmp(str, cp-len, len) == 0 )
350: retval = 1;
351: if ( cp == &buf[BUFSIZ-1] )
352: break;
353: }
354: printmsg(M_CALL, "actually received {%s}", visbuf(buf, cp-buf));
355: if ( retval )
356: printmsg(M_CALL, "got that");
357: return(retval);
358: }
359:
360: /*
361: * sendstr(str) char *str;
362: * Send string of chat script out the communications line.
363: */
364:
365: sendstr(str)
366: char *str;
367: {
368: register char *cp = str;
369: char ch;
370: int slash, nocr;
371:
372: sleep(1);
373: if ( strncmp(str, "\"\"", 2) == 0 )
374: str = "";
375:
376: nocr = slash = 0;
377: while ( (ch=*cp++) ) {
378: if ( !slash ) {
379: if ( strncmp(cp-1, "EOT", 3) == 0 ) {
380: swrite("\004", 1);
381: cp += 2;
382: } else if ( strncmp(cp-1, "BREAK", 4) == 0 ) {
383: sendbrk();
384: cp += 4;
385: } else if ( ch == '\\' ) {
386: slash = 1;
387: } else {
388: swrite(&ch, 1);
389: }
390: continue;
391: }
392: switch( ch ) {
393: case 'b':
394: swrite("\b", 1);
395: break;
396: case 'c':
397: nocr = 1;
398: break;
399: case 'd':
400: sleep(2);
401: break;
402: case 'K':
403: sendbrk();
404: break;
405: case 'n':
406: swrite("\n", 1);
407: break;
408: case 'N':
409: swrite("\0", 1);
410: break;
411: case 'p':
412: sleep(1);
413: break;
414: case 'r':
415: swrite("\r", 1);
416: break;
417: case 's':
418: swrite(" ", 1);
419: break;
420: case 't':
421: swrite("\t", 1);
422: break;
423: case '\\':
424: swrite("\\", 1);
425: break;
426: default:
427: if ( !isdigit(ch) ||
428: !isdigit(*cp) ||
429: !isdigit(*(cp+1)) )
430: fatal("Can't parse chat script: {%s}", str);
431: ch = ((ch-'0')<<6) | ((*cp-'0')<<3) | (*(cp+1));
432: swrite(&ch, 1);
433: break;
434: }
435: slash = 0;
436: }
437: if ( !nocr )
438: swrite("\r", 1);
439: }
440:
441: /*
442: * callup()
443: * Initiate the call, and walk through the chat script.
444: */
445:
446: callup()
447: {
448: char *device, *speed, *phone;
449: char *expect, *send, *dsh;
450: int i;
451:
452: plog(M_CALL, "Calling site %s {%d} (V%s)", rmtname, processid, version);
453:
454: device = lsys_value(device_e);
455: speed = lsys_value(speed_e);
456: phone = lsys_value(phone_e);
457:
458: if ( strcmp(device, "ACU") == 0 ) {
459: if ( !dcpdial(NULL, speed, phone) )
460: goto calluperr;
461: } else if ( !dcpdial(device, speed, NULL) )
462: goto calluperr;
463:
464: for (i=0; (expect=lsys_expect(i)) != NULL; i++) {
465: for (;;) {
466: printmsg(M_CALL, "callup: expecting {%s}", expect);
467: if ( (dsh=index(expect, '-')) != NULL )
468: *dsh++ = '\0';
469: if ( expectstr(expect, MSGTIME) )
470: break;
471: if ( dsh == NULL ) {
472: plog(M_CALL, "Login failed.");
473: goto calluperr;
474: }
475: if ( (expect=index(dsh, '-')) == NULL )
476: fatal("Chat script syntax error: %s", dsh);
477: *expect++ = '\0';
478: printmsg(M_CALL, "callup: send alternate {%s}", dsh);
479: sendstr(dsh);
480: }
481: send = lsys_send(i);
482: printmsg(M_CALL, "callup: sending {%s}", send);
483: sendstr(send);
484: }
485: return('P');
486:
487: calluperr:
488: terminatelevel++;
489: return('Y');
490: }
491:
492: /*
493: * sysend()
494: * End UUCP session.
495: */
496:
497: sysend()
498: {
499:
500: /* We may have a problem here. Someone else may be removing the remote
501: * device lock file before we call unlocktty. Tests have shown this to
502: * be unimportant because the lock file IS being removed. A warning
503: * will be printed to the log files for users to check for locks.
504: * Hopefully, this isn't going to be a bug. Bob H. 11/22/91.
505: */
506:
507: /* December 4, 1991: Problem solved(?). When we are in master mode,
508: * we call dcpundial, which calls the hangup, which, in turn, calls
509: * undial. Undial removes the locks on the device. Thie following
510: * code USED to call dcpundial if in master mode, and THEN continued
511: * to call the unlocktty function, which had previously been called
512: * by dcpundial. I snuck in an 'else' statement to get around this.
513: * Tests show that this solves the problem described above, but who
514: * knows if this will cause problems when we are NOT in master mode.
515: */
516:
517: if ( lockttyexist(rdevname) ) {
518: if ( role == MASTER ){
519: printmsg(M_DEBUG,"Sysend: calling undial and hangup routines.");
520: dcpundial();
521: }else{
522: plog(M_CALL,"Sysend: Removing remote device lock file.");
523: if(unlocktty(rdevname) != 0){
524: plog(M_CALL,"sysend: Possible lock file removal failure.");
525: }
526: }
527: }
528:
529: /* May 05, 1992 (Bob H.) problems communicating with a 386 based bbs
530: * and a customer complaint from Germany lead to the discovery of a
531: * condition where undial() was never called, which meant that cicio
532: * NEVER hung up the phone! Adding the dcpundial() in the following
533: * if... resolves this.
534: */
535: if ( !leavelock && lockexist(rmtname) ){
536: dcpundial();
537: plog(M_CALL,"Removing remote site lock");
538: if(lockrm(rmtname) != 0){
539: printmsg(M_LOG,"sysend: Remote site Lock file removal failed!");
540: plog(M_CALL,"sysend: Remote site lock file removal failed!");
541: }
542: }
543: plog(M_CALL, terminatelevel ?
544: "Abnormal completion {%d}" :
545: "Call completing normally {%d}", processid);
546: close_logfile();
547: sysended = 1;
548: return( (role == MASTER) ? 'I': 'A' );
549: }
550:
551: /*
552: * scandir()
553: *
554: * scan work dir for "C." files matching current remote host (rmtname)
555: * return:
556: * Y - can't open file
557: * S - ok
558: * Q - no files
559: */
560:
561: extern DIR *opendir();
562: extern struct direct *readdir();
563:
564: scandir()
565: {
566: char fn[DIRSIZ+1];
567: char dirname[CTLFLEN];
568: DIR *dirp;
569: struct dirent *dp;
570:
571: sprintf(dirname, "%s/%s", SPOOLDIR, rmtname); /* build spool dir name */
572: printmsg(M_INFO, "Scandir: %s", dirname);
573:
574: if ((dirp=opendir(dirname)) == NULL) /* open spool dir */
575: return('Q');
576:
577: fn[0] = fn[DIRSIZ] = '\0';
578: while ( (dp=readdir(dirp)) != NULL ) {
579: printmsg(M_DEBUG, "Scandir: %s", dp->d_name);
580: if ( strncmp("C.", dp->d_name, 2) ) /* is this a C. file? */
581: continue;
582: if ( (fn[0] == '\0') || (strncmp(dp->d_name, fn, DIRSIZ) < 0) )
583: strncpy(fn, dp->d_name, DIRSIZ);
584: }
585: closedir(dirp);
586:
587: if (fn[0] != '\0') {
588: sprintf(cfile, "%s/%s/%s", SPOOLDIR, rmtname, fn);
589: printmsg(M_DEBUG, "Scandir: cfile: %s", cfile);
590: if ((cfp = fopen(cfile, "r")) == NULL) {
591: plog(M_DEBUG, "Unable to open control file %s", cfile);
592: terminatelevel++;
593: return('Y');
594: }
595: return('S');
596: }
597: return('Q');
598: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.