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