pppctl.c revision 31914
1/*
2 * $Id: pppctl.c,v 1.12 1997/12/18 00:29:56 brian Exp $
3 */
4
5#include <sys/types.h>
6
7#include <sys/socket.h>
8#include <netinet/in.h>
9#include <arpa/inet.h>
10#include <sys/un.h>
11#include <netdb.h>
12
13#include <sys/time.h>
14#include <errno.h>
15#include <histedit.h>
16#include <setjmp.h>
17#include <signal.h>
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <time.h>
22#include <unistd.h>
23
24#define LINELEN 2048
25static char Buffer[LINELEN], Command[LINELEN];
26
27static int
28Usage()
29{
30    fprintf(stderr, "Usage: pppctl [-v] [ -t n ] [ -p passwd ] "
31            "Port|LocalSock [command[;command]...]\n");
32    fprintf(stderr, "              -v tells pppctl to output all"
33            " conversation\n");
34    fprintf(stderr, "              -t n specifies a timeout of n"
35            " seconds when connecting (default 2)\n");
36    fprintf(stderr, "              -p passwd specifies your password\n");
37    return 1;
38}
39
40static int TimedOut = 0;
41static void
42Timeout(int Sig)
43{
44    TimedOut = 1;
45}
46
47#define REC_PASSWD  (1)
48#define REC_SHOW    (2)
49#define REC_VERBOSE (4)
50
51static char *passwd;
52static char *prompt;
53
54static char *
55GetPrompt(EditLine *e)
56{
57    if (prompt == NULL)
58        prompt = "";
59    return prompt;
60}
61
62static int
63Receive(int fd, int display)
64{
65    int Result;
66    int len;
67    char *last;
68
69    prompt = Buffer;
70    len = 0;
71    while (Result = read(fd, Buffer+len, sizeof(Buffer)-len-1), Result != -1) {
72        if (Result == 0 && errno != EINTR) {
73          Result = -1;
74          break;
75        }
76        len += Result;
77        Buffer[len] = '\0';
78        if (TimedOut) {
79            if (display & REC_VERBOSE)
80                write(1,Buffer,len);
81            Result = -1;
82            break;
83        } else if (len > 2 && !strcmp(Buffer+len-2, "> ")) {
84            prompt = strrchr(Buffer, '\n');
85            if (display & (REC_SHOW|REC_VERBOSE)) {
86                if (display & REC_VERBOSE)
87                    last = Buffer+len-1;
88                else
89                    last = prompt;
90                if (last) {
91                    last++;
92                    write(1, Buffer, last-Buffer);
93                }
94            }
95            prompt = prompt == NULL ? Buffer : prompt+1;
96            for (last = Buffer+len-2; last > Buffer && *last != ' '; last--)
97                ;
98            if (last > Buffer+3 && !strncmp(last-3, " on", 3)) {
99                 /* a password is required ! */
100                 if (display & REC_PASSWD) {
101                    /* password time */
102                    if (!passwd)
103                        passwd = getpass("Password: ");
104                    sprintf(Buffer, "passwd %s\n", passwd);
105                    memset(passwd, '\0', strlen(passwd));
106                    if (display & REC_VERBOSE)
107                        write(1, Buffer, strlen(Buffer));
108                    write(fd, Buffer, strlen(Buffer));
109                    memset(Buffer, '\0', strlen(Buffer));
110                    return Receive(fd, display & ~REC_PASSWD);
111                }
112                Result = 1;
113            } else
114                Result = 0;
115            break;
116        }
117    }
118
119    return Result;
120}
121
122static int data = -1;
123static jmp_buf pppdead;
124
125static void
126check_fd(int sig)
127{
128  if (data != -1) {
129    struct timeval t;
130    fd_set f;
131    static char buf[LINELEN];
132    int len;
133
134    FD_ZERO(&f);
135    FD_SET(data, &f);
136    t.tv_sec = t.tv_usec = 0;
137    if (select(data+1, &f, NULL, NULL, &t) > 0) {
138      len = read(data, buf, sizeof buf);
139      if (len > 0)
140        write(1, buf, len);
141      else
142        longjmp(pppdead, -1);
143    }
144  }
145}
146
147static const char *
148smartgets(EditLine *e, int *count, int fd)
149{
150  const char *result;
151
152  data = fd;
153  signal(SIGALRM, check_fd);
154  ualarm(500000, 500000);
155  result = setjmp(pppdead) ? NULL : el_gets(e, count);
156  ualarm(0,0);
157  signal(SIGALRM, SIG_DFL);
158  data = -1;
159
160  return result;
161}
162
163int
164main(int argc, char **argv)
165{
166    struct servent *s;
167    struct hostent *h;
168    struct sockaddr *sock;
169    struct sockaddr_in ifsin;
170    struct sockaddr_un ifsun;
171    int socksz, arg, fd, len, verbose;
172    unsigned TimeoutVal;
173    char *DoneWord = "x", *next, *start;
174    struct sigaction act, oact;
175
176    verbose = 0;
177    TimeoutVal = 2;
178
179    for (arg = 1; arg < argc; arg++)
180        if (*argv[arg] == '-') {
181            for (start = argv[arg] + 1; *start; start++)
182                switch (*start) {
183                    case 't':
184                        TimeoutVal = (unsigned)atoi
185                            (start[1] ? start + 1 : argv[++arg]);
186                        start = DoneWord;
187                        break;
188
189                    case 'v':
190                        verbose = REC_VERBOSE;
191                        break;
192
193                    case 'p':
194                        passwd = (start[1] ? start + 1 : argv[++arg]);
195                        start = DoneWord;
196                        break;
197
198                    default:
199                        return Usage();
200                }
201        }
202        else
203            break;
204
205
206    if (argc < arg + 1)
207        return Usage();
208
209    if (*argv[arg] == '/') {
210        sock = (struct sockaddr *)&ifsun;
211        socksz = sizeof ifsun;
212
213        memset(&ifsun, '\0', sizeof ifsun);
214        ifsun.sun_len = strlen(argv[arg]);
215        if (ifsun.sun_len > sizeof ifsun.sun_path - 1) {
216            fprintf(stderr, "%s: Path too long\n", argv[arg]);
217            return 1;
218        }
219        ifsun.sun_family = AF_LOCAL;
220        strcpy(ifsun.sun_path, argv[arg]);
221
222        if (fd = socket(AF_LOCAL, SOCK_STREAM, 0), fd < 0) {
223            fprintf(stderr, "Cannot create local domain socket\n");
224            return 2;
225        }
226    } else {
227        char *port, *host, *colon;
228        int hlen;
229
230        colon = strchr(argv[arg], ':');
231        if (colon) {
232            port = colon + 1;
233            *colon = '\0';
234            host = argv[arg];
235        } else {
236            port = argv[arg];
237            host = "127.0.0.1";
238        }
239        sock = (struct sockaddr *)&ifsin;
240        socksz = sizeof ifsin;
241        hlen = strlen(host);
242
243        memset(&ifsin, '\0', sizeof ifsin);
244        if (strspn(host, "0123456789.") == hlen) {
245            if (!inet_aton(host, &ifsin.sin_addr)) {
246                fprintf(stderr, "Cannot translate %s\n", host);
247                return 1;
248            }
249        } else if ((h = gethostbyname(host)) == 0) {
250            fprintf(stderr, "Cannot resolve %s\n", host);
251            return 1;
252        }
253        else
254            ifsin.sin_addr.s_addr = *(u_long *)h->h_addr_list[0];
255
256        if (colon)
257            *colon = ':';
258
259        if (strspn(port, "0123456789") == strlen(port))
260            ifsin.sin_port = htons(atoi(port));
261        else if (s = getservbyname(port, "tcp"), !s) {
262            fprintf(stderr, "%s isn't a valid port or service!\n", port);
263            return Usage();
264        }
265        else
266            ifsin.sin_port = s->s_port;
267
268        ifsin.sin_len = sizeof(ifsin);
269        ifsin.sin_family = AF_INET;
270
271        if (fd = socket(AF_INET, SOCK_STREAM, 0), fd < 0) {
272            fprintf(stderr, "Cannot create internet socket\n");
273            return 2;
274        }
275    }
276
277    TimedOut = 0;
278    if (TimeoutVal) {
279        act.sa_handler = Timeout;
280        sigemptyset(&act.sa_mask);
281        act.sa_flags = 0;
282        sigaction(SIGALRM, &act, &oact);
283        alarm(TimeoutVal);
284    }
285
286    if (connect(fd, sock, socksz) < 0) {
287        if (TimeoutVal) {
288            alarm(0);
289            sigaction(SIGALRM, &oact, 0);
290        }
291        if (TimedOut)
292            fputs("Timeout: ", stderr);
293        fprintf(stderr, "Cannot connect to socket %s\n", argv[arg]);
294        close(fd);
295        return 3;
296    }
297
298    if (TimeoutVal) {
299        alarm(0);
300        sigaction(SIGALRM, &oact, 0);
301    }
302
303    len = 0;
304    Command[sizeof(Command)-1] = '\0';
305    for (arg++; arg < argc; arg++) {
306        if (len && len < sizeof(Command)-1)
307            strcpy(Command+len++, " ");
308        strncpy(Command+len, argv[arg], sizeof(Command)-len-1);
309        len += strlen(Command+len);
310    }
311
312    switch (Receive(fd, verbose | REC_PASSWD))
313    {
314        case 1:
315            fprintf(stderr, "Password incorrect\n");
316            break;
317
318        case 0:
319            if (len == 0) {
320                EditLine *edit;
321                History *hist;
322                const char *l, *env;
323                int size;
324
325                hist = history_init();
326                if ((env = getenv("EL_SIZE"))) {
327                    size = atoi(env);
328                    if (size < 0)
329                      size = 20;
330                } else
331                    size = 20;
332                history(hist, H_EVENT, size);
333
334                edit = el_init("pppctl", stdin, stdout);
335                el_source(edit, NULL);
336                el_set(edit, EL_PROMPT, GetPrompt);
337                if ((env = getenv("EL_EDITOR")))
338                    if (!strcmp(env, "vi"))
339                        el_set(edit, EL_EDITOR, "vi");
340                    else if (!strcmp(env, "emacs"))
341                        el_set(edit, EL_EDITOR, "emacs");
342                el_set(edit, EL_SIGNAL, 1);
343                el_set(edit, EL_HIST, history, (const char *)hist);
344                while ((l = smartgets(edit, &len, fd))) {
345                    if (len > 1)
346                        history(hist, H_ENTER, l);
347                    write(fd, l, len);
348                    if (Receive(fd, REC_SHOW) != 0)
349                        break;
350                }
351                fprintf(stderr, "Connection closed\n");
352                el_end(edit);
353                history_end(hist);
354            } else {
355                start = Command;
356                do {
357                    next = strchr(start, ';');
358                    while (*start == ' ' || *start == '\t')
359                        start++;
360                    if (next)
361                        *next = '\0';
362                    strcpy(Buffer, start);
363                    Buffer[sizeof(Buffer)-2] = '\0';
364                    strcat(Buffer, "\n");
365                    if (verbose)
366                        write(1, Buffer, strlen(Buffer));
367                    write(fd, Buffer, strlen(Buffer));
368                    if (Receive(fd, verbose | REC_SHOW) != 0) {
369                        fprintf(stderr, "Connection closed\n");
370                        break;
371                    }
372                    if (next)
373                        start = ++next;
374                } while (next && *next);
375                if (verbose)
376                    puts("");
377            }
378            break;
379
380        default:
381            fprintf(stderr, "ppp is not responding\n");
382            break;
383    }
384
385    close(fd);
386
387    return 0;
388}
389