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