source: rtems/cpukit/pppd/chat.c @ f26145b

4.104.114.84.95
Last change on this file since f26145b was 9c858e56, checked in by Joel Sherrill <joel.sherrill@…>, on 01/31/05 at 22:21:19

2005-01-31 Sergei Organov <osv@…>

PR 771/pppd

  • libnetworking/pppd/chat.c, libnetworking/pppd/rtemsmain.c: The fix committed to fix PR736 breaks pppd. chat.c should have its own static ttyfd for pppd to work correctly. The symptom is that second invokation of chat (for connect script) fails due to pppd_ttyfd set to -1 by previous chat invokation (for init script). In addition, this patch fixes leaving of dangling pointer in the abort_stbring[] by chat_send().
  • Property mode set to 100644
File size: 16.2 KB
Line 
1/*
2 *      Chat -- a program for automatic session establishment (i.e. dial
3 *              the phone and log in).
4 *
5 * Standard termination codes:
6 *  0 - successful completion of the script
7 *  1 - invalid argument, expect string too large, etc.
8 *  2 - error on an I/O operation or fatal error condition.
9 *  3 - timeout waiting for a simple string.
10 *  4 - the first string declared as "ABORT"
11 *  5 - the second string declared as "ABORT"
12 *  6 - ... and so on for successive ABORT strings.
13 *
14 *      This software is in the public domain.
15 *
16 * -----------------
17 *      22-May-99 added environment substitutuion, enabled with -E switch.
18 *      Andreas Arens <andras@cityweb.de>.
19 *
20 *      12-May-99 added a feature to read data to be sent from a file,
21 *      if the send string starts with @.  Idea from gpk <gpk@onramp.net>.
22 *
23 *      added -T and -U option and \T and \U substitution to pass a phone
24 *      number into chat script. Two are needed for some ISDN TA applications.
25 *      Keith Dart <kdart@cisco.com>
26 *     
27 *
28 *      Added SAY keyword to send output to stderr.
29 *      This allows to turn ECHO OFF and to output specific, user selected,
30 *      text to give progress messages. This best works when stderr
31 *      exists (i.e.: pppd in nodetach mode).
32 *
33 *      Added HANGUP directives to allow for us to be called
34 *      back. When HANGUP is set to NO, chat will not hangup at HUP signal.
35 *      We rely on timeouts in that case.
36 *
37 *      Added CLR_ABORT to clear previously set ABORT string. This has been
38 *      dictated by the HANGUP above as "NO CARRIER" (for example) must be
39 *      an ABORT condition until we know the other host is going to close
40 *      the connection for call back. As soon as we have completed the
41 *      first stage of the call back sequence, "NO CARRIER" is a valid, non
42 *      fatal string. As soon as we got called back (probably get "CONNECT"),
43 *      we should re-arm the ABORT "NO CARRIER". Hence the CLR_ABORT command.
44 *      Note that CLR_ABORT packs the abort_strings[] array so that we do not
45 *      have unused entries not being reclaimed.
46 *
47 *      In the same vein as above, added CLR_REPORT keyword.
48 *
49 *      Allow for comments. Line starting with '#' are comments and are
50 *      ignored. If a '#' is to be expected as the first character, the
51 *      expect string must be quoted.
52 *
53 *
54 *              Francis Demierre <Francis@SwissMail.Com>
55 *              Thu May 15 17:15:40 MET DST 1997
56 *
57 *
58 *      Added -r "report file" switch & REPORT keyword.
59 *              Robert Geer <bgeer@xmission.com>
60 *
61 *      Added -s "use stderr" and -S "don't use syslog" switches.
62 *              June 18, 1997
63 *              Karl O. Pinc <kop@meme.com>
64 *
65 *
66 *      Added -e "echo" switch & ECHO keyword
67 *              Dick Streefland <dicks@tasking.nl>
68 *
69 *
70 *      Considerable updates and modifications by
71 *              Al Longyear <longyear@pobox.com>
72 *              Paul Mackerras <paulus@cs.anu.edu.au>
73 *
74 *
75 *      The original author is:
76 *
77 *              Karl Fox <karl@MorningStar.Com>
78 *              Morning Star Technologies, Inc.
79 *              1760 Zollinger Road
80 *              Columbus, OH  43221
81 *              (614)451-1883
82 *
83 */
84
85/*      $Id$ */
86
87/*
88        Fixes and some Changes by Wilfried Busalski Lancier-Monitoring GmbH Germany
89        wilfried.busalski@muenster.de
90       
91        Fixes:  put_string()            Free memory allocated by clean()
92                        get_string()            Free memory allocated by clean()
93                        chat_main()                     Will Distroy's no more the chat-script
94                        getnextcommand()        sepatator changed to '@'
95*/
96
97#include <stdio.h>
98#include <ctype.h>
99#include <time.h>
100#include <fcntl.h>
101#include <errno.h>
102#include <string.h>
103#include <stdlib.h>
104#include <unistd.h>
105#include <sys/types.h>
106#include <sys/stat.h>
107#include <syslog.h>
108#include <termios.h>
109#include "pppd.h"
110
111#undef  TERMIOS
112#define TERMIOS
113
114
115#define STR_LEN 1024
116char temp2[STR_LEN];
117
118#ifndef SIGTYPE
119#define SIGTYPE void
120#endif
121
122#undef __P
123#undef __V
124
125#ifdef __STDC__
126#include <stdarg.h>
127#define __V(x)  x
128#define __P(x)  x
129#else
130#include <varargs.h>
131#define __V(x)  (va_alist) va_dcl
132#define __P(x)  ()
133#define const
134#endif
135
136#ifndef O_NONBLOCK
137#define O_NONBLOCK      O_NDELAY
138#endif
139
140
141/*************** Micro getopt() *********************************************/
142#define OPTION(c,v)     (_O&2&&**v?*(*v)++:!c||_O&4?0:(!(_O&1)&& \
143                                (--c,++v),_O=4,c&&**v=='-'&&v[0][1]?*++*v=='-'\
144                                &&!v[0][1]?(--c,++v,0):(_O=2,*(*v)++):0))
145#define OPTARG(c,v)     (_O&2?**v||(++v,--c)?(_O=1,--c,*v++): \
146                                (_O=4,(char*)0):(char*)0)
147#define OPTONLYARG(c,v) (_O&2&&**v?(_O=1,--c,*v++):(char*)0)
148#define ARG(c,v)        (c?(--c,*v++):(char*)0)
149
150#if 0
151static int _O = 0;              /* Internal state */
152#endif
153/*************** Micro getopt() *********************************************/
154
155#define MAX_ABORTS              16
156#define MAX_REPORTS             16
157#define DEFAULT_CHAT_TIMEOUT    45
158#define MAX_TIMEOUTS            10
159
160static int echo             = 0;
161static int quiet            = 0;
162static int use_env          = 0;
163static int exit_code        = 0;
164static char *phone_num      = (char *) 0;
165static char *phone_num2     = (char *) 0;
166static int ttyfd;
167static int timeout   = DEFAULT_CHAT_TIMEOUT;
168
169#ifdef TERMIOS
170#define term_parms struct termios
171#define get_term_param(param) tcgetattr(0, param)
172#define set_term_param(param) tcsetattr(0, TCSANOW, param)
173struct termios saved_tty_parameters;
174#endif
175
176char *fail_reason = (char *)0;
177char  fail_buffer[50];
178char *abort_string[MAX_ABORTS]={"BUSY","NO DIALTONE","NO CARRIER","NO ANSWER","RING\r\nRING"};
179int n_aborts = 5;
180int abort_next = 0, timeout_next = 0, echo_next = 0;
181int clear_abort_next = 0;
182
183char *report_string[MAX_REPORTS] ;
184char  report_buffer[50] ;
185int n_reports = 0, report_next = 0, report_gathering = 0 ;
186int clear_report_next = 0;
187
188int say_next = 0, hup_next = 0;
189
190void *dup_mem __P((void *b, size_t c));
191void *copy_of __P((char *s));
192void break_sequence __P((void));
193static int  get_string __P((register char *string));
194static int  put_string __P((register char *s));
195static int  write_char __P((int c));
196static int  put_char __P((int c));
197static int  get_char __P((void));
198void chat_send __P((register char *s));
199/* static char *character __P((int c)); */
200void chat_expect __P((register char *s));
201static char *clean __P((register char *s, int sending));
202char *expect_strtok __P((char *, char *));
203int chatmain __P((int, int, char *));
204
205
206void *dup_mem(b, c)
207void *b;
208size_t c;
209{
210    void *ans = malloc (c);
211    if (!ans)
212        return NULL;
213
214    memcpy(ans, b, c);
215    return ans;
216}
217
218void *copy_of (s)
219char *s;
220{
221    return dup_mem(s, strlen (s) + 1);
222}
223
224char *getnextcommand(char *string,char *buff)
225{
226        char *token;
227        int len;
228       
229        token=strchr(string,'@');
230        if (token==NULL){
231                return NULL;
232        }
233        len=token-string;
234        if(len > 78 ){
235                len=78;
236        }
237        memcpy(buff,string,len);
238        buff[len]=0;
239        return(token+1);
240}
241
242int chatmain(int fd, int mode, char *pScript)
243{
244  char    arg[80];
245  char    *script;
246
247  /* initialize exit code */
248  exit_code = 0;
249  ttyfd     = fd;
250
251  script=pScript;
252 
253  if ( debug ) {
254    dbglog("chat_main: %s\n", script);
255  }
256
257  /* get first expect string */
258  script = getnextcommand(script,arg);
259  while (( script != NULL ) && ( exit_code == 0 )) {
260    /* process the expect string */
261    chat_expect(arg);
262    if ( exit_code == 0 ) {
263      /* get the next send string */
264      script = getnextcommand(script,arg);
265      if ( script != NULL ) {
266        /* process the send string */
267        chat_send(arg);
268
269        /* get the next expect string */
270        script = getnextcommand(script,arg);
271      }
272    }
273  }
274  ttyfd = (int)-1;
275
276  return ( exit_code );
277}
278
279void break_sequence()
280{
281  tcsendbreak(ttyfd, 0);
282}
283
284/*
285 *      'Clean up' this string.
286 */
287static char *clean(s, sending)
288register char *s;
289int sending;  /* set to 1 when sending (putting) this string. */
290{
291    char temp[STR_LEN], env_str[STR_LEN], cur_chr;
292    register char *s1, *phchar;
293    int add_return = sending;
294#define isoctal(chr)    (((chr) >= '0') && ((chr) <= '7'))
295#define isalnumx(chr)   ((((chr) >= '0') && ((chr) <= '9')) \
296                         || (((chr) >= 'a') && ((chr) <= 'z')) \
297                         || (((chr) >= 'A') && ((chr) <= 'Z')) \
298                         || (chr) == '_')
299
300    s1 = temp;
301    while (*s) {
302        cur_chr = *s++;
303        if (cur_chr == '^') {
304            cur_chr = *s++;
305            if (cur_chr == '\0') {
306                *s1++ = '^';
307                break;
308            }
309            cur_chr &= 0x1F;
310            if (cur_chr != 0) {
311                *s1++ = cur_chr;
312            }
313            continue;
314        }
315       
316        if (use_env && cur_chr == '$') {                /* ARI */
317            phchar = env_str;
318            while (isalnumx(*s))
319                *phchar++ = *s++;
320            *phchar = '\0';
321            phchar = getenv(env_str);
322            if (phchar)
323                while (*phchar)
324                    *s1++ = *phchar++;
325            continue;
326        }
327
328        if (cur_chr != '\\') {
329            *s1++ = cur_chr;
330            continue;
331        }
332
333        cur_chr = *s++;
334        if (cur_chr == '\0') {
335            if (sending) {
336                *s1++ = '\\';
337                *s1++ = '\\';
338            }
339            break;
340        }
341
342        switch (cur_chr) {
343        case 'b':
344            *s1++ = '\b';
345            break;
346
347        case 'c':
348            if (sending && *s == '\0')
349                add_return = 0;
350            else
351                *s1++ = cur_chr;
352            break;
353
354        case '\\':
355        case 'K':
356        case 'p':
357        case 'd':
358            if (sending)
359                *s1++ = '\\';
360            *s1++ = cur_chr;
361            break;
362
363        case 'T':
364            if (sending && phone_num) {
365                for (phchar = phone_num; *phchar != '\0'; phchar++)
366                    *s1++ = *phchar;
367            }
368            else {
369                *s1++ = '\\';
370                *s1++ = 'T';
371            }
372            break;
373
374        case 'U':
375            if (sending && phone_num2) {
376                for (phchar = phone_num2; *phchar != '\0'; phchar++)
377                    *s1++ = *phchar;
378            }
379            else {
380                *s1++ = '\\';
381                *s1++ = 'U';
382            }
383            break;
384
385        case 'q':
386            quiet = 1;
387            break;
388
389        case 'r':
390            *s1++ = '\r';
391            break;
392
393        case 'n':
394            *s1++ = '\n';
395            break;
396
397        case 's':
398            *s1++ = ' ';
399            break;
400
401        case 't':
402            *s1++ = '\t';
403            break;
404
405        case 'N':
406            if (sending) {
407                *s1++ = '\\';
408                *s1++ = '\0';
409            }
410            else
411                *s1++ = 'N';
412            break;
413           
414        case '$':                       /* ARI */
415            if (use_env) {
416                *s1++ = cur_chr;
417                break;
418            }
419            /* FALL THROUGH */
420
421        default:
422            if (isoctal (cur_chr)) {
423                cur_chr &= 0x07;
424                if (isoctal (*s)) {
425                    cur_chr <<= 3;
426                    cur_chr |= *s++ - '0';
427                    if (isoctal (*s)) {
428                        cur_chr <<= 3;
429                        cur_chr |= *s++ - '0';
430                    }
431                }
432
433                if (cur_chr != 0 || sending) {
434                    if (sending && (cur_chr == '\\' || cur_chr == 0))
435                        *s1++ = '\\';
436                    *s1++ = cur_chr;
437                }
438                break;
439            }
440
441            if (sending)
442                *s1++ = '\\';
443            *s1++ = cur_chr;
444            break;
445        }
446    }
447
448    if (add_return)
449        *s1++ = '\r';
450
451    *s1++ = '\0'; /* guarantee closure */
452    *s1++ = '\0'; /* terminate the string */
453    return dup_mem (temp, (size_t) (s1 - temp)); /* may have embedded nuls */
454}
455
456/*
457 * A modified version of 'strtok'. This version skips \ sequences.
458 */
459char *expect_strtok (s, term)
460     char *s, *term;
461{
462    static  char *str   = "";
463    int     escape_flag = 0;
464    char   *result;
465
466/*
467 * If a string was specified then do initial processing.
468 */
469    if (s)
470        str = s;
471
472/*
473 * If this is the escape flag then reset it and ignore the character.
474 */
475    if (*str)
476        result = str;
477    else
478        result = (char *) 0;
479
480    while (*str) {
481        if (escape_flag) {
482            escape_flag = 0;
483            ++str;
484            continue;
485        }
486
487        if (*str == '\\') {
488            ++str;
489            escape_flag = 1;
490            continue;
491        }
492
493/*
494 * If this is not in the termination string, continue.
495 */
496        if (strchr (term, *str) == (char *) 0) {
497            ++str;
498            continue;
499        }
500
501/*
502 * This is the terminator. Mark the end of the string and stop.
503 */
504        *str++ = '\0';
505        break;
506    }
507    return (result);
508}
509
510/*
511 * Process the expect string
512 */
513void chat_expect (s)
514char *s;
515{
516    char *expect;
517    char *reply;
518
519    if (strcmp(s, "HANGUP") == 0) {
520                ++hup_next;
521        return;
522    }
523 
524    if (strcmp(s, "ABORT") == 0) {
525                ++abort_next;
526                return;
527    }
528
529    if (strcmp(s, "CLR_ABORT") == 0) {
530                ++clear_abort_next;
531                return;
532    }
533
534    if (strcmp(s, "REPORT") == 0) {
535                ++report_next;
536                return;
537    }
538
539    if (strcmp(s, "CLR_REPORT") == 0) {
540                ++clear_report_next;
541                return;
542    }
543
544    if (strcmp(s, "TIMEOUT") == 0) {
545                ++timeout_next;
546                return;
547    }
548
549    if (strcmp(s, "ECHO") == 0) {
550                ++echo_next;
551                return;
552    }
553
554    if (strcmp(s, "SAY") == 0) {
555                ++say_next;
556                return;
557    }
558
559/*
560 * Fetch the expect and reply string.
561 */
562    for (;;) {
563        expect = expect_strtok (s, "-");
564        s      = (char *) 0;
565
566        if (expect == (char *) 0)
567            return;
568
569        reply = expect_strtok (s, "-");
570
571/*
572 * Handle the expect string. If successful then exit.
573 */
574        if (get_string (expect))
575            return;
576
577/*
578 * If there is a sub-reply string then send it. Otherwise any condition
579 * is terminal.
580 */
581        if (reply == (char *) 0 || exit_code != 3)
582            break;
583
584        chat_send (reply);
585    }
586}
587
588#if 0
589/*
590 * Translate the input character to the appropriate string for printing
591 * the data.
592 */
593
594static char *character(c)
595int c;
596{
597    static char string[10];
598    char *meta;
599
600    meta = (c & 0x80) ? "M-" : "";
601    c &= 0x7F;
602
603    if (c < 32)
604        sprintf(string, "%s^%c", meta, (int)c + '@');
605    else if (c == 127)
606        sprintf(string, "%s^?", meta);
607    else
608        sprintf(string, "%s%c", meta, c);
609
610    return (string);
611}
612#endif
613
614/*
615 *  process the reply string
616 */
617void chat_send (s)
618register char *s;
619{
620/*  char file_data[STR_LEN];  */
621
622    if (say_next) {
623                say_next = 0;
624                s = clean(s, 1);
625                write(2, s, strlen(s));
626        free(s);
627                return;
628    }
629
630    if (hup_next) {
631        hup_next = 0;
632        return;
633    }
634
635    if (echo_next) {
636        echo_next = 0;
637        echo = (strcmp(s, "ON") == 0);
638        return;
639    }
640
641    if (abort_next) {
642                abort_next = 0;
643                if ( n_aborts < MAX_ABORTS ) {
644                        char *s1;
645                        s1 = clean(s, 0);
646                        if (( strlen(s1) <= strlen(s) ) && ( strlen(s1) <  sizeof(fail_buffer)))
647                                abort_string[n_aborts++] = s1;
648                        else
649                                free(s1);
650                }
651                return;
652    }
653
654    if (clear_abort_next) {
655                clear_abort_next = 0;
656                return;
657    }
658
659    if (report_next) {
660                report_next = 0;
661                return;
662    }
663
664    if (clear_report_next) {
665                clear_report_next = 0;
666                return;
667    }
668
669    if (timeout_next) {
670                timeout_next = 0;
671                timeout = atoi(s);
672       
673                if (timeout <= 0){
674                timeout = DEFAULT_CHAT_TIMEOUT;
675            }
676                return;
677    }
678
679    if (strcmp(s, "EOT") == 0){
680                s = "^D\\c";
681        }
682    else{
683        if (strcmp(s, "BREAK") == 0){
684                        s = "\\K\\c";
685                }
686
687        if (!put_string(s)) {
688                exit_code = 2;
689        }
690        }
691}
692
693static int get_char()
694{
695    int status;
696    char c;
697    int tries=MAX_TIMEOUTS;
698
699        while(tries)
700        {
701            status = read(ttyfd, &c, 1);
702            switch (status) {
703                   case 1:
704                                return ((int)c & 0x7F);
705                    default:
706                                tries--;                       
707            }
708    }
709        return -1;                                             
710}
711
712static int put_char(c)
713int c;
714{
715  char ch = c;
716
717  return(write(ttyfd, &ch, 1));
718}
719
720static int write_char (c)
721int c;
722{
723    if (put_char(c) < 1) {
724                return (0);
725    }
726    return (1);
727}
728
729static int put_string (s)
730register char *s;
731{
732        char *out,*free_ptr=0;
733       
734    quiet = 0;
735    out = free_ptr = clean(s, 1);
736    while (*out) {
737                register char c = *out++;
738
739                if (c != '\\') {
740                if (!write_char (c)){
741                        free(free_ptr);
742                                return 0;
743                        }
744                continue;
745                }
746
747                c = *out++;
748
749                switch (c) {
750                        case 'd':
751                        sleep(1);
752                    break;
753
754                        case 'K':
755                        break_sequence();
756                break;
757
758                        case 'p':
759#if 0 /* FIXME!!! */
760                        usleep(10000);  /* 1/100th of a second (arg is microseconds) */
761#else
762                        sleep(1);
763#endif
764                break;
765
766                        default:
767                        if (!write_char (c)){
768                                free(free_ptr);
769                                        return 0;
770                                }
771                break;
772                }
773    }
774    free(free_ptr);
775
776    return (1);
777}
778
779/*
780 *      'Wait for' this string to appear on this file descriptor.
781 */
782static int get_string(in_string)
783register char *in_string;
784{
785    int c, len, minlen;
786    register char *s = temp2, *end = s + STR_LEN;
787    char *logged = temp2;
788    char *string=0;
789    struct termios tios;
790
791    memset(temp2, 0, sizeof(temp2));
792
793    tcgetattr(ttyfd, &tios);
794    tios.c_cc[VMIN] = 0;
795    tios.c_cc[VTIME] = timeout*10/MAX_TIMEOUTS;
796    tcsetattr(ttyfd, TCSANOW, &tios);
797               
798    string = clean(in_string, 0);
799    len = strlen(string);
800    minlen = (len > sizeof(fail_buffer)? len: sizeof(fail_buffer)) - 1;
801       
802    if (len > STR_LEN) {
803                exit_code = 1;
804                free(string);
805                return 0;
806    }
807
808    if (len == 0) {
809        free(string);
810        return (1);
811    }
812
813   while ( (c = get_char()) >= 0) {
814                int n, abort_len;
815
816        if(c == '\n' || c == '\r'){
817                s = temp2;
818                *s=0;
819        }
820        else{
821                *s++ = c;
822                *s=0;
823        }
824
825        if (s - temp2 >= len &&
826            c == string[len - 1] &&
827            strncmp(s - len, string, len) == 0) {
828            free(string);
829            return (1);
830        }
831
832        for (n = 0; n < n_aborts; ++n) {
833            if (s - temp2 >= (abort_len = strlen(abort_string[n])) &&
834                strncmp(s - abort_len, abort_string[n], abort_len) == 0) {
835
836                exit_code = n + 4;
837                strcpy(fail_reason = fail_buffer, abort_string[n]);
838                free(string);
839                return (0);
840            }
841        }
842
843        if (s >= end) {
844            if (logged < s - minlen) {
845                logged = s;
846            }
847            s -= minlen;
848            memmove(temp2, s, minlen);
849            logged = temp2 + (logged - s);
850            s = temp2 + minlen;
851        }
852    }
853
854    exit_code = 3;
855    free(string);
856    return (0);
857}
Note: See TracBrowser for help on using the repository browser.