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