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