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.17 1999/01/31 12:24:29 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 49 static char Buffer[LINELEN], Command[LINELEN]; 50 51 static int 52 Usage() 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 64 static int TimedOut = 0; 65 static void 66 Timeout(int Sig) 67 { 68 TimedOut = 1; 69 } 70 71 #define REC_PASSWD (1) 72 #define REC_SHOW (2) 73 #define REC_VERBOSE (4) 74 75 static char *passwd; 76 static char *prompt; 77 78 static char * 79 GetPrompt(EditLine *e) 80 { 81 if (prompt == NULL) 82 prompt = ""; 83 return prompt; 84 } 85 86 static int 87 Receive(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 152 static int data = -1; 153 static jmp_buf pppdead; 154 155 static void 156 check_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 177 static const char * 178 smartgets(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 193 int 194 main(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, err; 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 err = errno; 318 if (TimeoutVal) { 319 alarm(0); 320 sigaction(SIGALRM, &oact, 0); 321 } 322 if (TimedOut) { 323 fputs("Timeout: ", stderr); 324 err = 0; 325 } 326 fprintf(stderr, "Cannot connect to socket %s", argv[arg]); 327 if (err) 328 fprintf(stderr, ": %s", strerror(err)); 329 fputc('\n', stderr); 330 close(fd); 331 return 3; 332 } 333 334 if (TimeoutVal) { 335 alarm(0); 336 sigaction(SIGALRM, &oact, 0); 337 } 338 339 len = 0; 340 Command[sizeof(Command)-1] = '\0'; 341 for (arg++; arg < argc; arg++) { 342 if (len && len < sizeof(Command)-1) 343 strcpy(Command+len++, " "); 344 strncpy(Command+len, argv[arg], sizeof(Command)-len-1); 345 len += strlen(Command+len); 346 } 347 348 switch (Receive(fd, verbose | REC_PASSWD)) 349 { 350 case 1: 351 fprintf(stderr, "Password incorrect\n"); 352 break; 353 354 case 0: 355 if (len == 0) { 356 EditLine *edit; 357 History *hist; 358 const char *l, *env; 359 int size; 360 361 hist = history_init(); 362 if ((env = getenv("EL_SIZE"))) { 363 size = atoi(env); 364 if (size < 0) 365 size = 20; 366 } else 367 size = 20; 368 #ifdef __NetBSD__ 369 history(hist, NULL, H_SETSIZE, size); 370 #else 371 history(hist, H_EVENT, size); 372 #endif 373 edit = el_init("pppctl", stdin, stdout); 374 el_source(edit, NULL); 375 el_set(edit, EL_PROMPT, GetPrompt); 376 if ((env = getenv("EL_EDITOR"))) { 377 if (!strcmp(env, "vi")) 378 el_set(edit, EL_EDITOR, "vi"); 379 else if (!strcmp(env, "emacs")) 380 el_set(edit, EL_EDITOR, "emacs"); 381 } 382 el_set(edit, EL_SIGNAL, 1); 383 el_set(edit, EL_HIST, history, (const char *)hist); 384 while ((l = smartgets(edit, &len, fd))) { 385 if (len > 1) 386 #ifdef __NetBSD__ 387 history(hist, NULL, H_ENTER, l); 388 #else 389 history(hist, H_ENTER, l); 390 #endif 391 write(fd, l, len); 392 if (Receive(fd, REC_SHOW) != 0) 393 break; 394 } 395 fprintf(stderr, "Connection closed\n"); 396 el_end(edit); 397 history_end(hist); 398 } else { 399 start = Command; 400 do { 401 next = strchr(start, ';'); 402 while (*start == ' ' || *start == '\t') 403 start++; 404 if (next) 405 *next = '\0'; 406 strcpy(Buffer, start); 407 Buffer[sizeof(Buffer)-2] = '\0'; 408 strcat(Buffer, "\n"); 409 if (verbose) 410 write(1, Buffer, strlen(Buffer)); 411 write(fd, Buffer, strlen(Buffer)); 412 if (Receive(fd, verbose | REC_SHOW) != 0) { 413 fprintf(stderr, "Connection closed\n"); 414 break; 415 } 416 if (next) 417 start = ++next; 418 } while (next && *next); 419 if (verbose) 420 puts(""); 421 } 422 break; 423 424 default: 425 fprintf(stderr, "ppp is not responding\n"); 426 break; 427 } 428 429 close(fd); 430 431 return 0; 432 } 433