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