|
|
1.1 root 1: #ifndef NOICP
2: #ifndef NOSCRIPT
3: char *loginv = "Script Command, 5A(015) 2 Nov 92";
4:
5: /* C K U S C R -- Login script for logging onto remote system */
6:
7: /*
8: Copyright (C) 1985, 1992, Trustees of Columbia University in the City of New
9: York. Permission is granted to any individual or institution to use this
10: software as long as it is not sold for profit. This copyright notice must be
11: retained. This software may not be included in commercial products without
12: written permission of Columbia University.
13:
14: Original (version 1, 1985) author: Herm Fischer, Encino, CA.
15: Contributed to Columbia University in 1985 for inclusion in C-Kermit 4.0.
16: Author and maintainer since 1985: Frank da Cruz, Columbia University,
17: [email protected].
18: */
19:
20: /*
21: The module expects a login string of the expect send [expect send] ...
22: format. It is intended to operate similarly to the way the common
23: uucp "L.sys" login entries work. Conditional responses are supported
24: expect[-send-expect[...]] as with uucp. The send keyword EOT sends a
25: control-d, and the keyword BREAK sends a break. Letters prefixed
26: by '~' are '~b' backspace, '~s' space, '~n' linefeed, '~r' return, '~x' xon,
27: '~t' tab, '~q' ? (not allowed on kermit command lines), '~' ~, '~'',
28: '~"', '~c' don't append return, '~o[o[o]]' octal character. As with
29: some uucp systems, sent strings are followed by ~r (not ~n) unless they
30: end with ~c. Null expect strings (e.g., ~0 or --) cause a short
31: delay, and are useful for sending sequences requiring slight pauses.
32:
33: This module calls externally defined system-dependent functions for
34: communications i/o, as defined in CKCPLM.DOC, the C-Kermit Program Logic
35: Manual, and thus should be portable to all systems that implement those
36: functions, and where alarm() and signal() work as they do in UNIX.
37: */
38:
39: #include "ckcdeb.h"
40: #include <signal.h>
41: #include <setjmp.h>
42: #include "ckcasc.h"
43: #include "ckcker.h"
44: #include "ckuusr.h"
45: #include "ckcnet.h"
46:
47: _PROTOTYP( VOID flushi, (void) );
48:
49: #ifdef MAC
50: #define SIGALRM (1<<10)
51: #undef SIGTYP /* put in ckcdeb.h later */
52: #define SIGTYP void
53: #endif /* MAC */
54:
55: extern int local, flow, seslog, mdmtyp, msgflg, duplex, backgrd, secho, quiet;
56: #ifdef NETCONN
57: extern int network, ttnproto;
58: #endif /* NETCONN */
59: extern long speed;
60: extern char ttname[];
61:
62: #ifndef NOSPL
63: extern struct cmdptr cmdstk[];
64: extern int techo, cmdlvl;
65: extern int mecho;
66: #endif /* NOSPL */
67:
68: static int scr_echo; /* Whether to echo script commands */
69:
70: static int exp_alrm = 15; /* Time to wait for expect string */
71: #define SND_ALRM 15 /* Time to allow for sending string */
72: #define NULL_EXP 2 /* Time to pause on null expect strg*/
73: #define DEL_MSEC 300 /* milliseconds to pause on ~d */
74:
75: #define SBUFL 512
76: static char seq_buf[SBUFL], *s; /* Login Sequence buffer */
77: static char fls_buf[SBUFL]; /* Flush buffer */
78: static int got_it, no_cr;
79:
80: /* connect state parent/child communication signal handlers */
81:
82: static jmp_buf alrmrng; /* Envir ptr for connect errors */
83:
84: SIGTYP
85: scrtime(foo) int foo; { /* modem read failure handler, */
86: longjmp(alrmrng,1); /* notifies parent process to stop */
87: }
88:
89: /*
90: Sequence interpreter -- pick up next sequence from command string,
91: decode escapes and place into seq_buf.
92:
93: If string contains a ~d (delay) then sequenc returns a 1 expecting
94: to be called again after the ~d executes.
95: */
96: static int
97: sequenc() {
98: int i;
99: char c, oct_char;
100:
101: no_cr = 0; /* output needs cr appended */
102: for (i = 0; i < SBUFL; ) {
103: if (*s == '\0' || *s == '-' || isspace(*s) ) { /* done */
104: seq_buf[i] = '\0';
105: return(0) ;
106: }
107: if (*s == '~') { /* escape character */
108: s++;
109: switch (c = *s) {
110: case 'n': seq_buf[i++] = LF; break;
111: case 'r': seq_buf[i++] = CR; break;
112: case 't': seq_buf[i++] = '\t'; break;
113: case 'b': seq_buf[i++] = '\b'; break;
114: case 'q': seq_buf[i++] = '?'; break;
115: #ifdef COMMENT
116: /* The default case should catch these now... */
117: case '~': seq_buf[i++] = '~'; break;
118: case '-': seq_buf[i++] = '-'; break;
119: #endif /* COMMENT */
120: case '\'': seq_buf[i++] = '\''; break;
121: case '\"': seq_buf[i++] = '\"'; break;
122: case 's': seq_buf[i++] = ' '; break;
123: case 'x': seq_buf[i++] = '\021'; break;
124: case 'c': no_cr = 1; break;
125: case 'd': { /* send what we have & then */
126: seq_buf[i] = '\0'; /* expect to send rest after */
127: no_cr = 1; /* sender delays a little */
128: s++;
129: return(1);
130: }
131: case 'w': { /* wait count */
132: exp_alrm = 15; /* default to 15 sec */
133: if (isdigit(*(s+1))) {
134: s++;
135: exp_alrm = *s & 15;
136: if (isdigit(*(s+1)) ) {
137: s++;
138: exp_alrm = exp_alrm * 10 + (*s & 15);
139: }
140: }
141: break;
142: }
143: default:
144: if ( isdigit(c) ) { /* octal character */
145: oct_char = (c & 7); /* most significant digit */
146: if (isdigit( *(s+1) ) ) {
147: s++;
148: oct_char = (oct_char<<3) | ( *s & 7 ) ;
149: if (isdigit( *(s+1) ) ) {
150: s++;
151: oct_char = (oct_char<<3) | ( *s & 7 ) ;
152: }
153: }
154: seq_buf[i++] = oct_char;
155: break;
156: } else seq_buf[i++] = *s; /* Treat ~ as quote */
157: }
158: } else seq_buf[i++] = *s; /* Plain old character */
159: s++;
160: }
161: seq_buf[i] = '\0';
162: return(0); /* end of space, return anyway */
163: }
164:
165: /*
166: Receive sequence -- see if expected response comes,
167: return success (or failure) in got_it.
168: */
169: static VOID
170: recvseq() {
171:
172: char *e, got[7], trace[SBUFL];
173: int i, l, x;
174:
175: sequenc();
176: l = (int)strlen(e=seq_buf); /* no more than 7 chars allowed */
177: if (l > 7) {
178: e += l-7;
179: l = 7;
180: }
181: tlog(F111,"expecting sequence",e,(long) l);
182: if (l == 0) { /* null sequence, just delay a little */
183: sleep (NULL_EXP);
184: got_it = 1;
185: tlog(F100,"got it (null sequence)","",0L);
186: return;
187: }
188: *trace = '\0';
189: for (i = 0; i < 7; i++) got[i]='\0';
190:
191: signal(SIGALRM,scrtime); /* did we get it? */
192: if (!setjmp(alrmrng)) { /* not timed out yet */
193: alarm(exp_alrm);
194: while (!got_it) {
195: for (i = 0; i < l-1; i++) got[i] = got[i+1]; /* Shift over */
196: x = ttinc(0); /* Read a character */
197: debug(F101,"recvseq","",x);
198: if (x < 0) goto rcvx; /* Check for error */
199: #ifdef NETCONN
200: #ifdef TNCODE
201: /* Check for telnet protocol negotiation */
202: if (network &&
203: (ttnproto == NP_TELNET) &&
204: ( (x & 0xff) == IAC) ) {
205: switch (tn_doop((CHAR)(x & 0xff),duplex,ttinc)) {
206: case 2: duplex = 0; continue;
207: case 1: duplex = 1;
208: default: continue;
209: }
210: }
211: #endif /* TNCODE */
212: #endif /* NETCONN */
213: got[l-1] = x & 0x7f; /* Got a character */
214: if (scr_echo) conoc(got[l-1]); /* Echo it */
215: if (seslog) /* Log it in session log */
216: if (zchout(ZSFILE,got[l-1]) < 0) seslog = 0;
217: if ((int)strlen(trace) < sizeof(trace)-2 )
218: strcat(trace,dbchr(got[l-1]));
219: got_it = (!strncmp(e, got, l));
220: }
221: } else got_it = 0; /* timed out here */
222: rcvx:
223: alarm(0);
224: signal(SIGALRM,SIG_IGN);
225: tlog(F110,"received sequence: ",trace,0L);
226: tlog(F101,"returning with got-it code","",(long) got_it);
227: return;
228: }
229:
230: /*
231: Output A Sequence starting at pointer s,
232: return 0 if okay,
233: 1 if failed to read (modem hangup or whatever)
234: */
235: static int oseqret = 0; /* Return code for outseq */
236: /* Out here to prevent clobbering */
237: /* by longjmp. */
238: static int
239: outseq() {
240: char *sb;
241: int l;
242: int delay;
243:
244: oseqret = 0; /* Initialize return code */
245: while(1) {
246: delay = sequenc();
247: l = (int)strlen(seq_buf);
248: tlog(F111,"sending sequence ",seq_buf,(long) l);
249: signal(SIGALRM,scrtime);
250: if (!setjmp(alrmrng)) {
251: alarm(SND_ALRM);
252: if (!strcmp(seq_buf,"EOT")) {
253: ttoc(dopar('\004'));
254: if (scr_echo) conol("<EOT>");
255: if (seslog && duplex) if (zsout(ZSFILE,"<EOT>") < 0)
256: seslog = 0;
257: } else if (!strcmp(seq_buf,"BREAK") ||
258: !strcmp(seq_buf,"\\b") ||
259: !strcmp(seq_buf,"\\B")) {
260: ttsndb();
261: if (scr_echo) conol("<BREAK>");
262: if (seslog) if (zsout(ZSFILE,"{BREAK}") < 0) seslog = 0;
263: } else {
264: if (l > 0) {
265: for ( sb = seq_buf; *sb; sb++)
266: *sb = dopar(*sb); /* add parity */
267: ttol((CHAR *)seq_buf,l); /* send it */
268: if (scr_echo && duplex) conxo(l,seq_buf);
269: if (seslog && duplex) /* log it */
270: if (zsout(ZSFILE,seq_buf) < 0)
271: seslog=0;
272: }
273: if (!no_cr) {
274: ttoc( dopar(CR) );
275: if (seslog && duplex)
276: if (zchout(ZSFILE,dopar(CR)) < 0)
277: seslog = 0;
278: }
279: }
280: } else oseqret |= -1; /* else -- alarm rang */
281: alarm(0);
282: signal(SIGALRM,SIG_IGN);
283: if (!delay) return(oseqret);
284: #ifndef MAC
285: msleep(DEL_MSEC); /* delay, loop to next send */
286: #endif /* MAC */
287: }
288: }
289:
290: /* L O G I N -- Login to remote system */
291:
292: int
293: dologin(cmdstr) char *cmdstr; {
294:
295: SIGTYP (*savealm)(); /* save incoming alarm function */
296: char *e;
297:
298: s = cmdstr; /* make global to ckuscr.c */
299:
300: tlog(F100,loginv,"",0L);
301:
302: if (speed < 0L) speed = ttgspd();
303: if (ttopen(ttname,&local,mdmtyp,0) < 0) {
304: sprintf(seq_buf,"Sorry, can't open %s",ttname);
305: perror(seq_buf);
306: return(0);
307: }
308: /* Whether to echo script cmds */
309: scr_echo = (!quiet && !backgrd && secho);
310: #ifndef NOSPL
311: if (scr_echo && cmdlvl > 1) {
312: if (cmdstk[cmdlvl].src == CMD_TF)
313: scr_echo = techo;
314: if (cmdstk[cmdlvl].src == CMD_MD)
315: scr_echo = mecho;
316: }
317: #endif /* NOSPL */
318: if (scr_echo) {
319: #ifdef NETCONN
320: if (network)
321: printf("Executing SCRIPT to host %s.\n",ttname);
322: else
323: #endif /* NETCONN */
324: printf("Executing SCRIPT through %s, speed %ld.\n",ttname,speed);
325: }
326: *seq_buf=0;
327: for (e = s; *e; e++) strcat(seq_buf, dbchr(*e) );
328: #ifdef COMMENT
329: /* Skip this because it tends to contain a password... */
330: if (scr_echo) printf("SCRIPT string: %s\n",seq_buf);
331: #endif /* COMMENT */
332: tlog(F110,"SCRIPT string: ",seq_buf, 0L);
333:
334: /* Condition console terminal and communication line */
335:
336: if (ttvt(speed,flow) < 0) {
337: printf("Sorry, Can't condition communication line\n");
338: return(0);
339: }
340: /* Save initial timer interrupt value */
341: savealm = signal(SIGALRM,SIG_IGN);
342:
343: flushi(); /* flush stale input */
344:
345: /* start expect - send sequence */
346:
347: while (*s) { /* while not done with buffer */
348:
349: while (*s && isspace(*s)) s++; /* skip over separating whitespaces */
350: /* gather up expect sequence */
351: got_it = 0;
352: recvseq();
353:
354: while (!got_it) { /* Have it yet? */
355: if (*s++ != '-') /* No, is there a conditional send? */
356: goto failret; /* No, return failure */
357: flushi(); /* Yes, flush out input buffer */
358: if (outseq()) /* If unable to send, */
359: goto failret; /* return failure. */
360: if (*s++ != '-') /* If no conditional response here, */
361: goto failret; /* return failure. */
362: recvseq(); /* All OK, read response from host. */
363: } /* Loop back and check got_it */
364:
365: while (*s && !isspace(*s++) ) ; /* Skip over conditionals */
366: while (*s && isspace(*s)) s++; /* Skip over separating whitespaces */
367: flushi(); /* Flush */
368: if (*s) if (outseq()) goto failret; /* If any */
369: }
370: signal(SIGALRM,savealm);
371: if (scr_echo) printf("Script successful.\n");
372: tlog(F100,"Script successful.","",0L);
373: return(1);
374:
375: failret:
376: signal(SIGALRM,savealm);
377: if (scr_echo) printf("Sorry, script failed\n");
378: tlog(F100,"Script failed","",0L);
379: return(0);
380: }
381:
382: /* F L U S H I -- Flush, but log, input buffer */
383:
384: VOID
385: flushi() {
386: int n;
387: if (seslog) { /* Logging session? */
388: n = ttchk(); /* Yes, anything in buffer? */
389: if (n > 0) { /* If so, */
390: if (n > SBUFL) n = SBUFL; /* make sure not too much, */
391: n = ttxin(n,(CHAR *)fls_buf); /* then read it, */
392: if (n > 0) if (zsout(ZSFILE,fls_buf) < 0) seslog = 0;
393: }
394: } else ttflui(); /* Otherwise just flush. */
395: }
396:
397: #ifdef MAC
398: alarm (s) int s; { /* Fix this later */
399: }
400: #endif /* MAC */
401: #else
402: char *loginv = "Script Command Disabled";
403: #endif /* NOSCRIPT */
404: #endif /* NOICP */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.