pppctl.c revision 31829
1/*
2 * $Id: pppctl.c,v 1.11 1997/12/17 00:26:58 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        ifsun.sun_len = strlen(argv[arg]);
214        if (ifsun.sun_len > sizeof ifsun.sun_path - 1) {
215            fprintf(stderr, "%s: Path too long\n", argv[arg]);
216            return 1;
217        }
218        ifsun.sun_family = AF_LOCAL;
219        strcpy(ifsun.sun_path, argv[arg]);
220
221        if (fd = socket(AF_LOCAL, SOCK_STREAM, 0), fd < 0) {
222            fprintf(stderr, "Cannot create local domain socket\n");
223            return 2;
224        }
225    } else {
226        char *port, *host, *colon;
227        int hlen;
228
229        colon = strchr(argv[arg], ':');
230        if (colon) {
231            port = colon + 1;
232            *colon = '\0';
233            host = argv[arg];
234        } else {
235            port = argv[arg];
236            host = "127.0.0.1";
237        }
238        sock = (struct sockaddr *)&ifsin;
239        socksz = sizeof ifsin;
240        hlen = strlen(host);
241
242        if (strspn(host, "0123456789.") == hlen) {
243            if (!inet_aton(host, &ifsin.sin_addr)) {
244                fprintf(stderr, "Cannot translate %s\n", host);
245                return 1;
246            }
247        } else if ((h = gethostbyname(host)) == 0) {
248            fprintf(stderr, "Cannot resolve %s\n", host);
249            return 1;
250        }
251        else
252            ifsin.sin_addr.s_addr = *(u_long *)h->h_addr_list[0];
253
254        if (colon)
255            *colon = ':';
256
257        if (strspn(port, "0123456789") == strlen(port))
258            ifsin.sin_port = htons(atoi(port));
259        else if (s = getservbyname(port, "tcp"), !s) {
260            fprintf(stderr, "%s isn't a valid port or service!\n", port);
261            return Usage();
262        }
263        else
264            ifsin.sin_port = s->s_port;
265
266        ifsin.sin_len = sizeof(ifsin);
267        ifsin.sin_family = AF_INET;
268
269        if (fd = socket(AF_INET, SOCK_STREAM, 0), fd < 0) {
270            fprintf(stderr, "Cannot create internet socket\n");
271            return 2;
272        }
273    }
274
275    TimedOut = 0;
276    if (TimeoutVal) {
277        act.sa_handler = Timeout;
278        sigemptyset(&act.sa_mask);
279        act.sa_flags = 0;
280        sigaction(SIGALRM, &act, &oact);
281        alarm(TimeoutVal);
282    }
283
284    if (connect(fd, sock, socksz) < 0) {
285        if (TimeoutVal) {
286            alarm(0);
287            sigaction(SIGALRM, &oact, 0);
288        }
289        if (TimedOut)
290            fputs("Timeout: ", stderr);
291        fprintf(stderr, "Cannot connect to socket %s\n", argv[arg]);
292        close(fd);
293        return 3;
294    }
295
296    if (TimeoutVal) {
297        alarm(0);
298        sigaction(SIGALRM, &oact, 0);
299    }
300
301    len = 0;
302    Command[sizeof(Command)-1] = '\0';
303    for (arg++; arg < argc; arg++) {
304        if (len && len < sizeof(Command)-1)
305            strcpy(Command+len++, " ");
306        strncpy(Command+len, argv[arg], sizeof(Command)-len-1);
307        len += strlen(Command+len);
308    }
309
310    switch (Receive(fd, verbose | REC_PASSWD))
311    {
312        case 1:
313            fprintf(stderr, "Password incorrect\n");
314            break;
315
316        case 0:
317            if (len == 0) {
318                EditLine *edit;
319                History *hist;
320                const char *l, *env;
321                int size;
322
323                hist = history_init();
324                if ((env = getenv("EL_SIZE"))) {
325                    size = atoi(env);
326                    if (size < 0)
327                      size = 20;
328                } else
329                    size = 20;
330                history(hist, H_EVENT, size);
331
332                edit = el_init("pppctl", stdin, stdout);
333                el_source(edit, NULL);
334                el_set(edit, EL_PROMPT, GetPrompt);
335                if ((env = getenv("EL_EDITOR")))
336                    if (!strcmp(env, "vi"))
337                        el_set(edit, EL_EDITOR, "vi");
338                    else if (!strcmp(env, "emacs"))
339                        el_set(edit, EL_EDITOR, "emacs");
340                el_set(edit, EL_SIGNAL, 1);
341                el_set(edit, EL_HIST, history, (const char *)hist);
342                while ((l = smartgets(edit, &len, fd))) {
343                    if (len > 1)
344                        history(hist, H_ENTER, l);
345                    write(fd, l, len);
346                    if (Receive(fd, REC_SHOW) != 0)
347                        break;
348                }
349                fprintf(stderr, "Connection closed\n");
350                el_end(edit);
351                history_end(hist);
352            } else {
353                start = Command;
354                do {
355                    next = strchr(start, ';');
356                    while (*start == ' ' || *start == '\t')
357                        start++;
358                    if (next)
359                        *next = '\0';
360                    strcpy(Buffer, start);
361                    Buffer[sizeof(Buffer)-2] = '\0';
362                    strcat(Buffer, "\n");
363                    if (verbose)
364                        write(1, Buffer, strlen(Buffer));
365                    write(fd, Buffer, strlen(Buffer));
366                    if (Receive(fd, verbose | REC_SHOW) != 0) {
367                        fprintf(stderr, "Connection closed\n");
368                        break;
369                    }
370                    if (next)
371                        start = ++next;
372                } while (next && *next);
373                if (verbose)
374                    puts("");
375            }
376            break;
377
378        default:
379            fprintf(stderr, "ppp is not responding\n");
380            break;
381    }
382
383    close(fd);
384
385    return 0;
386}
387