command.c revision 26551
1/* 2 * PPP User command processing module 3 * 4 * Written by Toshiharu OHNO (tony-o@iij.ad.jp) 5 * 6 * Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by the Internet Initiative Japan, Inc. The name of the 14 * IIJ may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: command.c,v 1.54 1997/06/09 03:27:16 brian Exp $ 21 * 22 */ 23#include <sys/types.h> 24#include <ctype.h> 25#include <termios.h> 26#include <sys/wait.h> 27#include <time.h> 28#include <netdb.h> 29#include <sys/socket.h> 30#include <netinet/in.h> 31#include <arpa/inet.h> 32#include <net/route.h> 33#include <paths.h> 34#include <alias.h> 35#include <fcntl.h> 36#include <errno.h> 37#include "fsm.h" 38#include "phase.h" 39#include "lcp.h" 40#include "ipcp.h" 41#include "modem.h" 42#include "filter.h" 43#include "command.h" 44#include "alias_cmd.h" 45#include "hdlc.h" 46#include "loadalias.h" 47#include "vars.h" 48#include "systems.h" 49#include "chat.h" 50#include "os.h" 51#include "timeout.h" 52 53extern void Cleanup(), TtyTermMode(), PacketMode(); 54extern int EnableCommand(), DisableCommand(), DisplayCommand(); 55extern int AcceptCommand(), DenyCommand(); 56static int AliasCommand(); 57extern int LocalAuthCommand(); 58extern int LoadCommand(), SaveCommand(); 59extern int ChangeParity(char *); 60extern int SelectSystem(); 61extern int ShowRoute(); 62extern void TtyOldMode(), TtyCommandMode(); 63extern struct pppvars pppVars; 64extern struct cmdtab const SetCommands[]; 65 66extern char *IfDevName; 67 68struct in_addr ifnetmask; 69int randinit; 70 71static int ShowCommand(), TerminalCommand(), QuitCommand(); 72static int CloseCommand(), DialCommand(), DownCommand(); 73static int SetCommand(), AddCommand(), DeleteCommand(); 74static int ShellCommand(); 75 76static int 77HelpCommand(list, argc, argv, plist) 78struct cmdtab *list; 79int argc; 80char **argv; 81struct cmdtab *plist; 82{ 83 struct cmdtab *cmd; 84 int n; 85 86 if (!VarTerm) 87 return 0; 88 89 if (argc > 0) { 90 for (cmd = plist; cmd->name; cmd++) 91 if (strcasecmp(cmd->name, *argv) == 0 && (cmd->lauth & VarLocalAuth)) { 92 if (plist == SetCommands) 93 fprintf(VarTerm, "set "); 94 fprintf(VarTerm, "%s\n", cmd->syntax); 95 return 0; 96 } 97 98 return -1; 99 } 100 101 n = 0; 102 for (cmd = plist; cmd->func; cmd++) 103 if (cmd->name && (cmd->lauth & VarLocalAuth)) { 104 fprintf(VarTerm, " %-8s: %-20s\n", cmd->name, cmd->helpmes); 105 n++; 106 } 107 108 if (n & 1) 109 fprintf(VarTerm, "\n"); 110 111 return 0; 112} 113 114int 115IsInteractive() 116{ 117 char *mes = NULL; 118 119 if (mode & MODE_DDIAL) 120 mes = "Working in dedicated dial mode."; 121 else if (mode & MODE_BACKGROUND) 122 mes = "Working in background mode."; 123 else if (mode & MODE_AUTO) 124 mes = "Working in auto mode."; 125 else if (mode & MODE_DIRECT) 126 mes = "Working in direct mode."; 127 else if (mode & MODE_DEDICATED) 128 mes = "Working in dedicated mode."; 129 if (mes) { 130 if (VarTerm) 131 fprintf(VarTerm, "%s\n", mes); 132 return 0; 133 } 134 return 1; 135} 136 137static int 138DialCommand(cmdlist, argc, argv) 139struct cmdtab *cmdlist; 140int argc; 141char **argv; 142{ 143 int tries; 144 145 if (LcpFsm.state > ST_CLOSED) { 146 if (VarTerm) 147 fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]); 148 return 0; 149 } 150 151 if (!IsInteractive()) 152 return(1); 153 154 if (argc > 0) { 155 if (SelectSystem(*argv, CONFFILE) < 0) { 156 if (VarTerm) 157 fprintf(VarTerm, "%s: not found.\n", *argv); 158 return -1; 159 } 160 } 161 162 tries = 0; 163 do { 164 if (VarTerm) 165 fprintf(VarTerm, "Dial attempt %u of %d\n", ++tries, VarDialTries); 166 modem = OpenModem(mode); 167 if (modem < 0) { 168 if (VarTerm) 169 fprintf(VarTerm, "Failed to open modem.\n"); 170 break; 171 } 172 if (DialModem() == EX_DONE) { 173 sleep(1); 174 ModemTimeout(); 175 PacketMode(); 176 break; 177 } 178 } while (VarDialTries == 0 || tries < VarDialTries); 179 180 return 0; 181} 182 183static int 184ShellCommand(cmdlist, argc, argv) 185struct cmdtab *cmdlist; 186int argc; 187char **argv; 188{ 189 const char *shell; 190 pid_t shpid; 191 FILE *oVarTerm; 192 193#ifdef SHELL_ONLY_INTERACTIVELY 194 if (mode != MODE_INTER) { 195 LogPrintf(LogWARN, "Can only start a shell in interactive mode\n"); 196 return 1; 197 } 198#else 199 if ((mode & (MODE_AUTO|MODE_INTER)) == (MODE_AUTO|MODE_INTER)) { 200 LogPrintf(LogWARN, "Shell is not allowed interactively in auto mode\n"); 201 return 1; 202 } 203#endif 204 205 if(argc == 0 && !(mode & MODE_INTER)) { 206 LogPrintf(LogWARN, "Can only start an interactive shell in" 207 " interactive mode\n"); 208 return 1; 209 } 210 211 if((shell = getenv("SHELL")) == 0) 212 shell = _PATH_BSHELL; 213 214 if((shpid = fork()) == 0) { 215 int dtablesize, i, fd; 216 217 if (VarTerm) 218 fd = fileno(VarTerm); 219 else if ((fd = open("/dev/null", O_RDWR)) == -1) { 220 LogPrintf(LogALERT, "Failed to open /dev/null: %s\n", strerror(errno)); 221 exit(1); 222 } 223 224 for (i = 0; i < 3; i++) 225 dup2(fd, i); 226 227 if (fd > 2) 228 if (VarTerm) { 229 oVarTerm = VarTerm; 230 VarTerm = 0; 231 if (oVarTerm && oVarTerm != stdout) 232 fclose(oVarTerm); 233 } else 234 close(fd); 235 236 for (dtablesize = getdtablesize(), i = 3; i < dtablesize; i++) 237 (void)close(i); 238 239 /* 240 * We are running setuid, we should change to 241 * real user for avoiding security problems. 242 */ 243 if (setgid(getgid()) < 0) { 244 LogPrintf(LogERROR, "setgid: %s\n", strerror(errno)); 245 exit(1); 246 } 247 if (setuid(getuid()) < 0) { 248 LogPrintf(LogERROR, "setuid: %s\n", strerror(errno)); 249 exit(1); 250 } 251 TtyOldMode(); 252 if(argc > 0) { 253 /* substitute pseudo args */ 254 for (i=1; i<argc; i++) { 255 if (strcasecmp(argv[i], "HISADDR") == 0) { 256 argv[i] = strdup(inet_ntoa(IpcpInfo.his_ipaddr)); 257 } 258 if (strcasecmp(argv[i], "INTERFACE") == 0) { 259 argv[i] = strdup(IfDevName); 260 } 261 if (strcasecmp(argv[i], "MYADDR") == 0) { 262 argv[i] = strdup(inet_ntoa(IpcpInfo.want_ipaddr)); 263 } 264 } 265 (void)execvp(argv[0], argv); 266 } 267 else 268 (void)execl(shell, shell, NULL); 269 270 LogPrintf(LogWARN, "exec() of %s failed\n", argc > 0 ? argv[0] : shell); 271 exit(255); 272 } 273 274 if( shpid == (pid_t)-1 ) { 275 LogPrintf(LogERROR, "Fork failed: %s\n", strerror(errno)); 276 } else { 277 int status; 278 (void)waitpid(shpid, &status, 0); 279 } 280 281 TtyCommandMode(1); 282 283 return(0); 284} 285 286struct cmdtab const Commands[] = { 287 { "accept", NULL, AcceptCommand, LOCAL_AUTH, 288 "accept option request", "accept option .."}, 289 { "add", NULL, AddCommand, LOCAL_AUTH, 290 "add route", "add dest mask gateway"}, 291 { "close", NULL, CloseCommand, LOCAL_AUTH, 292 "Close connection", "close"}, 293 { "delete", NULL, DeleteCommand, LOCAL_AUTH, 294 "delete route", "delete ALL | dest gateway [mask]"}, 295 { "deny", NULL, DenyCommand, LOCAL_AUTH, 296 "Deny option request", "deny option .."}, 297 { "dial", "call", DialCommand, LOCAL_AUTH, 298 "Dial and login", "dial|call [remote]"}, 299 { "disable", NULL, DisableCommand, LOCAL_AUTH, 300 "Disable option", "disable option .."}, 301 { "display", NULL, DisplayCommand, LOCAL_AUTH, 302 "Display option configs", "display"}, 303 { "enable", NULL, EnableCommand, LOCAL_AUTH, 304 "Enable option", "enable option .."}, 305 { "passwd", NULL, LocalAuthCommand,LOCAL_NO_AUTH, 306 "Password for manipulation", "passwd option .."}, 307 { "load", NULL, LoadCommand, LOCAL_AUTH, 308 "Load settings", "load [remote]"}, 309 { "save", NULL, SaveCommand, LOCAL_AUTH, 310 "Save settings", "save"}, 311 { "set", "setup", SetCommand, LOCAL_AUTH, 312 "Set parameters", "set[up] var value"}, 313 { "shell", "!", ShellCommand, LOCAL_AUTH, 314 "Run a subshell", "shell|! [sh command]"}, 315 { "show", NULL, ShowCommand, LOCAL_AUTH, 316 "Show status and statictics", "show var"}, 317 { "term", NULL, TerminalCommand,LOCAL_AUTH, 318 "Enter to terminal mode", "term"}, 319 { "alias", NULL, AliasCommand, LOCAL_AUTH, 320 "alias control", "alias option [yes|no]"}, 321 { "quit", "bye", QuitCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 322 "Quit PPP program", "quit|bye [all]"}, 323 { "help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 324 "Display this message", "help|? [command]", (void *)Commands }, 325 { NULL, "down", DownCommand, LOCAL_AUTH, 326 "Generate down event", "down"}, 327 { NULL, NULL, NULL }, 328}; 329 330extern int ReportCcpStatus(); 331extern int ReportLcpStatus(); 332extern int ReportIpcpStatus(); 333extern int ReportProtStatus(); 334extern int ReportCompress(); 335extern int ShowModemStatus(); 336extern int ReportHdlcStatus(); 337extern int ShowMemMap(); 338 339static int ShowLogLevel() 340{ 341 int i; 342 343 if (!VarTerm) 344 return 0; 345 fprintf(VarTerm, "Log:"); 346 for (i = LogMIN; i < LogMAXCONF; i++) { 347 if (LogIsKept(i)) 348 fprintf(VarTerm, " %s", LogName(i)); 349 } 350 fprintf(VarTerm, "\n"); 351 352 return 0; 353} 354 355static int ShowEscape() 356{ 357 int code, bit; 358 359 if (!VarTerm) 360 return 0; 361 if (EscMap[32]) { 362 for (code = 0; code < 32; code++) 363 if (EscMap[code]) 364 for (bit = 0; bit < 8; bit++) 365 if (EscMap[code] & (1<<bit)) 366 fprintf(VarTerm, " 0x%02x", (code << 3) + bit); 367 fprintf(VarTerm, "\n"); 368 } 369 return 1; 370} 371 372static int ShowTimeout() 373{ 374 if (!VarTerm) 375 return 0; 376 fprintf(VarTerm, " Idle Timer: %d secs LQR Timer: %d secs" 377 " Retry Timer: %d secs\n", VarIdleTimeout, VarLqrTimeout, 378 VarRetryTimeout); 379 return 1; 380} 381 382static int ShowAuthKey() 383{ 384 if (!VarTerm) 385 return 0; 386 fprintf(VarTerm, "AuthName = %s\n", VarAuthName); 387 fprintf(VarTerm, "AuthKey = %s\n", VarAuthKey); 388 return 1; 389} 390 391static int ShowVersion() 392{ 393 extern char VarVersion[]; 394 extern char VarLocalVersion[]; 395 396 if (!VarTerm) 397 return 0; 398 fprintf(VarTerm, "%s - %s \n", VarVersion, VarLocalVersion); 399 return 1; 400} 401 402static int ShowInitialMRU() 403{ 404 if (!VarTerm) 405 return 0; 406 fprintf(VarTerm, " Initial MRU: %ld\n", VarMRU); 407 return 1; 408} 409 410static int ShowPreferredMTU() 411{ 412 if (!VarTerm) 413 return 0; 414 if (VarPrefMTU) 415 fprintf(VarTerm, " Preferred MTU: %ld\n", VarPrefMTU); 416 else 417 fprintf(VarTerm, " Preferred MTU: unspecified\n"); 418 return 1; 419} 420 421static int ShowReconnect() 422{ 423 if (!VarTerm) 424 return 0; 425 fprintf(VarTerm, " Reconnect Timer: %d, %d tries\n", 426 VarReconnectTimer, VarReconnectTries); 427 return 1; 428} 429 430static int ShowRedial() 431{ 432 if (!VarTerm) 433 return 0; 434 fprintf(VarTerm, " Redial Timer: "); 435 436 if (VarRedialTimeout >= 0) { 437 fprintf(VarTerm, " %d seconds, ", VarRedialTimeout); 438 } 439 else { 440 fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD); 441 } 442 443 fprintf(VarTerm, " Redial Next Timer: "); 444 445 if (VarRedialNextTimeout >= 0) { 446 fprintf(VarTerm, " %d seconds, ", VarRedialNextTimeout); 447 } 448 else { 449 fprintf(VarTerm, " Random 0 - %d seconds, ", REDIAL_PERIOD); 450 } 451 452 if (VarDialTries) 453 fprintf(VarTerm, "%d dial tries", VarDialTries); 454 455 fprintf(VarTerm, "\n"); 456 457 return 1; 458} 459 460#ifndef NOMSEXT 461static int ShowMSExt() 462{ 463 if (!VarTerm) 464 return 0; 465 fprintf(VarTerm, " MS PPP extention values \n" ); 466 fprintf(VarTerm, " Primary NS : %s\n", inet_ntoa( ns_entries[0] )); 467 fprintf(VarTerm, " Secondary NS : %s\n", inet_ntoa( ns_entries[1] )); 468 fprintf(VarTerm, " Primary NBNS : %s\n", inet_ntoa( nbns_entries[0] )); 469 fprintf(VarTerm, " Secondary NBNS : %s\n", inet_ntoa( nbns_entries[1] )); 470 return 1; 471} 472#endif 473 474extern int ShowIfilter(), ShowOfilter(), ShowDfilter(), ShowAfilter(); 475 476struct cmdtab const ShowCommands[] = { 477 { "afilter", NULL, ShowAfilter, LOCAL_AUTH, 478 "Show keep Alive filters", "show afilter option .."}, 479 { "auth", NULL, ShowAuthKey, LOCAL_AUTH, 480 "Show auth name/key", "show auth"}, 481 { "ccp", NULL, ReportCcpStatus, LOCAL_AUTH, 482 "Show CCP status", "show cpp"}, 483 { "compress", NULL, ReportCompress, LOCAL_AUTH, 484 "Show compression statictics", "show compress"}, 485 { "dfilter", NULL, ShowDfilter, LOCAL_AUTH, 486 "Show Demand filters", "show dfilteroption .."}, 487 { "escape", NULL, ShowEscape, LOCAL_AUTH, 488 "Show escape characters", "show escape"}, 489 { "hdlc", NULL, ReportHdlcStatus, LOCAL_AUTH, 490 "Show HDLC error summary", "show hdlc"}, 491 { "ifilter", NULL, ShowIfilter, LOCAL_AUTH, 492 "Show Input filters", "show ifilter option .."}, 493 { "ipcp", NULL, ReportIpcpStatus, LOCAL_AUTH, 494 "Show IPCP status", "show ipcp"}, 495 { "lcp", NULL, ReportLcpStatus, LOCAL_AUTH, 496 "Show LCP status", "show lcp"}, 497 { "log", NULL, ShowLogLevel, LOCAL_AUTH, 498 "Show current log level", "show log"}, 499 { "mem", NULL, ShowMemMap, LOCAL_AUTH, 500 "Show memory map", "show mem"}, 501 { "modem", NULL, ShowModemStatus, LOCAL_AUTH, 502 "Show modem setups", "show modem"}, 503 { "mru", NULL, ShowInitialMRU, LOCAL_AUTH, 504 "Show Initial MRU", "show mru"}, 505 { "mtu", NULL, ShowPreferredMTU, LOCAL_AUTH, 506 "Show Preferred MTU", "show mtu"}, 507 { "ofilter", NULL, ShowOfilter, LOCAL_AUTH, 508 "Show Output filters", "show ofilter option .."}, 509 { "proto", NULL, ReportProtStatus, LOCAL_AUTH, 510 "Show protocol summary", "show proto"}, 511 { "reconnect",NULL, ShowReconnect, LOCAL_AUTH, 512 "Show Reconnect timer,tries", "show reconnect"}, 513 { "redial", NULL, ShowRedial, LOCAL_AUTH, 514 "Show Redial timeout value", "show redial"}, 515 { "route", NULL, ShowRoute, LOCAL_AUTH, 516 "Show routing table", "show route"}, 517 { "timeout", NULL, ShowTimeout, LOCAL_AUTH, 518 "Show Idle timeout value", "show timeout"}, 519#ifndef NOMSEXT 520 { "msext", NULL, ShowMSExt, LOCAL_AUTH, 521 "Show MS PPP extentions", "show msext"}, 522#endif 523 { "version", NULL, ShowVersion, LOCAL_NO_AUTH | LOCAL_AUTH, 524 "Show version string", "show version"}, 525 { "help", "?", HelpCommand, LOCAL_NO_AUTH | LOCAL_AUTH, 526 "Display this message", "show help|?", (void *)ShowCommands}, 527 { NULL, NULL, NULL }, 528}; 529 530struct cmdtab * 531FindCommand(cmds, str, pmatch) 532struct cmdtab *cmds; 533char *str; 534int *pmatch; 535{ 536 int nmatch; 537 int len; 538 struct cmdtab *found; 539 540 found = NULL; 541 len = strlen(str); 542 nmatch = 0; 543 while (cmds->func) { 544 if (cmds->name && strncasecmp(str, cmds->name, len) == 0) { 545 if (cmds->name[len] == '\0') { 546 *pmatch = 1; 547 return cmds; 548 } 549 nmatch++; 550 found = cmds; 551 } else if(cmds->alias && strncasecmp(str, cmds->alias, len) == 0) { 552 if (cmds->alias[len] == '\0') { 553 *pmatch = 1; 554 return cmds; 555 } 556 nmatch++; 557 found = cmds; 558 } 559 cmds++; 560 } 561 *pmatch = nmatch; 562 return found; 563} 564 565int 566FindExec(cmdlist, argc, argv) 567struct cmdtab *cmdlist; 568int argc; 569char **argv; 570{ 571 struct cmdtab *cmd; 572 int val = 1; 573 int nmatch; 574 575 cmd = FindCommand(cmdlist, *argv, &nmatch); 576 if (nmatch > 1) 577 LogPrintf(LogWARN, "%s: Ambiguous command\n", *argv); 578 else if (cmd && ( cmd->lauth & VarLocalAuth ) ) 579 val = (cmd->func)(cmd, --argc, ++argv, cmd->args); 580 else 581 LogPrintf(LogWARN, "%s: Invalid command\n", *argv); 582 583 if (val == -1) 584 LogPrintf(LogWARN, "Usage: %s\n", cmd->syntax); 585 else if(val) 586 LogPrintf(LogCOMMAND, "%s: Failed %d\n", *argv, val); 587 588 return val; 589} 590 591int aft_cmd = 1; 592extern int TermMode; 593 594void 595Prompt() 596{ 597 char *pconnect, *pauth; 598 599 if (!(mode & MODE_INTER) || !VarTerm || TermMode) 600 return; 601 602 if (!aft_cmd) 603 fprintf(VarTerm, "\n"); 604 else 605 aft_cmd = 0; 606 607 if ( VarLocalAuth == LOCAL_AUTH ) 608 pauth = " ON "; 609 else 610 pauth = " on "; 611 if (IpcpFsm.state == ST_OPENED && phase == PHASE_NETWORK) 612 pconnect = "PPP"; 613 else 614 pconnect = "ppp"; 615 fprintf(VarTerm, "%s%s%s> ", pconnect, pauth, VarShortHost); 616 fflush(VarTerm); 617} 618 619void 620DecodeCommand(buff, nb, prompt) 621char *buff; 622int nb; 623int prompt; 624{ 625 char *vector[20]; 626 char **argv; 627 int argc; 628 char *cp; 629 630 if (nb > 0) { 631 cp = buff + strcspn(buff, "\r\n"); 632 if (cp) 633 *cp = '\0'; 634 argc = MakeArgs(buff, vector, VECSIZE(vector)); 635 argv = vector; 636 637 if (argc > 0) 638 FindExec(Commands, argc, argv); 639 } 640 if (prompt) 641 Prompt(); 642} 643 644static int 645ShowCommand(list, argc, argv) 646struct cmdtab *list; 647int argc; 648char **argv; 649{ 650 if (argc > 0) 651 FindExec(ShowCommands, argc, argv); 652 else if (VarTerm) 653 fprintf(VarTerm, "Use ``show ?'' to get a list.\n"); 654 else 655 LogPrintf(LogWARN, "show command must have arguments\n"); 656 657 return 0; 658} 659 660static int 661TerminalCommand() 662{ 663 if (LcpFsm.state > ST_CLOSED) { 664 if (VarTerm) 665 fprintf(VarTerm, "LCP state is [%s]\n", StateNames[LcpFsm.state]); 666 return 1; 667 } 668 if (!IsInteractive()) 669 return(1); 670 modem = OpenModem(mode); 671 if (modem < 0) { 672 if (VarTerm) 673 fprintf(VarTerm, "Failed to open modem.\n"); 674 return(1); 675 } 676 if (VarTerm) { 677 fprintf(VarTerm, "Enter to terminal mode.\n"); 678 fprintf(VarTerm, "Type `~?' for help.\n"); 679 } 680 TtyTermMode(); 681 return(0); 682} 683 684static int 685QuitCommand(list, argc, argv) 686struct cmdtab *list; 687int argc; 688char **argv; 689{ 690 FILE *oVarTerm; 691 692 if (mode & (MODE_DIRECT|MODE_DEDICATED|MODE_AUTO)) { 693 if (argc > 0 && (VarLocalAuth & LOCAL_AUTH)) { 694 Cleanup(EX_NORMAL); 695 mode &= ~MODE_INTER; 696 oVarTerm = VarTerm; 697 VarTerm = 0; 698 if (oVarTerm && oVarTerm != stdout) 699 fclose(oVarTerm); 700 } else { 701 LogPrintf(LogPHASE, "Client connection closed.\n"); 702 VarLocalAuth = LOCAL_NO_AUTH; 703 mode &= ~MODE_INTER; 704 oVarTerm = VarTerm; 705 VarTerm = 0; 706 if (oVarTerm && oVarTerm != stdout) 707 fclose(oVarTerm); 708 close(netfd); 709 netfd = -1; 710 } 711 } else 712 Cleanup(EX_NORMAL); 713 714 return 0; 715} 716 717static int 718CloseCommand() 719{ 720 reconnect(RECON_FALSE); 721 LcpClose(); 722 if (mode & MODE_BACKGROUND) 723 Cleanup(EX_NORMAL); 724 return 0; 725} 726 727static int 728DownCommand() 729{ 730 LcpDown(); 731 return 0; 732} 733 734static int 735SetModemSpeed(list, argc, argv) 736struct cmdtab *list; 737int argc; 738char **argv; 739{ 740 int speed; 741 742 if (argc > 0) { 743 if (strcmp(*argv, "sync") == 0) { 744 VarSpeed = 0; 745 return 0; 746 } 747 speed = atoi(*argv); 748 if (IntToSpeed(speed) != B0) { 749 VarSpeed = speed; 750 return 0; 751 } 752 LogPrintf(LogWARN, "%s: Invalid speed\n", *argv); 753 } 754 return -1; 755} 756 757static int 758SetReconnect(list, argc, argv) 759struct cmdtab *list; 760int argc; 761char **argv; 762{ 763 if (argc == 2) { 764 VarReconnectTimer = atoi(argv[0]); 765 VarReconnectTries = atoi(argv[1]); 766 return 0; 767 } 768 769 return -1; 770} 771 772static int 773SetRedialTimeout(list, argc, argv) 774struct cmdtab *list; 775int argc; 776char **argv; 777{ 778 int timeout; 779 int tries; 780 char *dot; 781 782 if (argc == 1 || argc == 2 ) { 783 if (strncasecmp(argv[0], "random", 6) == 0 && 784 (argv[0][6] == '\0' || argv[0][6] == '.')) { 785 VarRedialTimeout = -1; 786 if (!randinit) { 787 randinit = 1; 788 if (srandomdev() < 0) 789 srandom((unsigned long)(time(NULL) ^ getpid())); 790 } 791 } else { 792 timeout = atoi(argv[0]); 793 794 if (timeout >= 0) 795 VarRedialTimeout = timeout; 796 else { 797 LogPrintf(LogWARN, "Invalid redial timeout\n"); 798 return -1; 799 } 800 } 801 802 dot = index(argv[0],'.'); 803 if (dot) { 804 if (strcasecmp(++dot, "random") == 0) { 805 VarRedialNextTimeout = -1; 806 if (!randinit) { 807 randinit = 1; 808 if (srandomdev() < 0) 809 srandom((unsigned long)(time(NULL) ^ getpid())); 810 } 811 } 812 else { 813 timeout = atoi(dot); 814 if (timeout >= 0) 815 VarRedialNextTimeout = timeout; 816 else { 817 LogPrintf(LogWARN, "Invalid next redial timeout\n"); 818 return -1; 819 } 820 } 821 } 822 else 823 VarRedialNextTimeout = NEXT_REDIAL_PERIOD; /* Default next timeout */ 824 825 if (argc == 2) { 826 tries = atoi(argv[1]); 827 828 if (tries >= 0) { 829 VarDialTries = tries; 830 } else { 831 LogPrintf(LogWARN, "Invalid retry value\n"); 832 return 1; 833 } 834 } 835 return 0; 836 } 837 838 return -1; 839} 840 841static int 842SetModemParity(list, argc, argv) 843struct cmdtab *list; 844int argc; 845char **argv; 846{ 847 int parity; 848 849 if (argc > 0) { 850 parity = ChangeParity(*argv); 851 if (parity < 0) 852 LogPrintf(LogWARN, "Invalid parity.\n"); 853 else { 854 VarParity = parity; 855 return 0; 856 } 857 } 858 859 return -1; 860} 861 862static int 863SetLogLevel(list, argc, argv) 864struct cmdtab *list; 865int argc; 866char **argv; 867{ 868 int i; 869 int res; 870 char *arg; 871 872 res = 0; 873 if (argc == 0 || (argv[0][0] != '+' && argv[0][0] != '-')) 874 LogDiscardAll(); 875 while (argc--) { 876 arg = **argv == '+' || **argv == '-' ? *argv + 1 : *argv; 877 for (i = LogMIN; i <= LogMAX; i++) 878 if (strcasecmp(arg, LogName(i)) == 0) { 879 if (**argv == '-') 880 LogDiscard(i); 881 else 882 LogKeep(i); 883 break; 884 } 885 if (i > LogMAX) { 886 LogPrintf(LogWARN, "%s: Invalid log value\n", arg); 887 res = -1; 888 } 889 argv++; 890 } 891 return res; 892} 893 894static int 895SetEscape(list, argc, argv) 896struct cmdtab *list; 897int argc; 898char **argv; 899{ 900 int code; 901 902 for (code = 0; code < 33; code++) 903 EscMap[code] = 0; 904 while (argc-- > 0) { 905 sscanf(*argv++, "%x", &code); 906 code &= 0xff; 907 EscMap[code >> 3] |= (1 << (code&7)); 908 EscMap[32] = 1; 909 } 910 return 0; 911} 912 913static int 914SetInitialMRU(list, argc, argv) 915struct cmdtab *list; 916int argc; 917char **argv; 918{ 919 long mru; 920 char *err; 921 922 if (argc > 0) { 923 mru = atol(*argv); 924 if (mru < MIN_MRU) 925 err = "Given MRU value (%ld) is too small.\n"; 926 else if (mru > MAX_MRU) 927 err = "Given MRU value (%ld) is too big.\n"; 928 else { 929 VarMRU = mru; 930 return 0; 931 } 932 LogPrintf(LogWARN, err, mru); 933 } 934 935 return -1; 936} 937 938static int 939SetPreferredMTU(list, argc, argv) 940struct cmdtab *list; 941int argc; 942char **argv; 943{ 944 long mtu; 945 char *err; 946 947 if (argc > 0) { 948 mtu = atol(*argv); 949 if (mtu == 0) { 950 VarPrefMTU = 0; 951 return 0; 952 } else if (mtu < MIN_MTU) 953 err = "Given MTU value (%ld) is too small.\n"; 954 else if (mtu > MAX_MTU) 955 err = "Given MTU value (%ld) is too big.\n"; 956 else { 957 VarPrefMTU = mtu; 958 return 0; 959 } 960 LogPrintf(LogWARN, err, mtu); 961 } 962 963 return -1; 964} 965 966static int 967SetIdleTimeout(list, argc, argv) 968struct cmdtab *list; 969int argc; 970char **argv; 971{ 972 if (argc-- > 0) { 973 VarIdleTimeout = atoi(*argv++); 974 UpdateIdleTimer(); /* If we're connected, restart the idle timer */ 975 if (argc-- > 0) { 976 VarLqrTimeout = atoi(*argv++); 977 if (VarLqrTimeout < 1) 978 VarLqrTimeout = 30; 979 if (argc > 0) { 980 VarRetryTimeout = atoi(*argv); 981 if (VarRetryTimeout < 1 || VarRetryTimeout > 10) 982 VarRetryTimeout = 3; 983 } 984 } 985 return 0; 986 } 987 988 return -1; 989} 990 991struct in_addr 992GetIpAddr(cp) 993char *cp; 994{ 995 struct hostent *hp; 996 struct in_addr ipaddr; 997 998 hp = gethostbyname(cp); 999 if (hp && hp->h_addrtype == AF_INET) 1000 bcopy(hp->h_addr, &ipaddr, hp->h_length); 1001 else if (inet_aton(cp, &ipaddr) == 0) 1002 ipaddr.s_addr = 0; 1003 return(ipaddr); 1004} 1005 1006static int 1007SetInterfaceAddr(list, argc, argv) 1008struct cmdtab *list; 1009int argc; 1010char **argv; 1011{ 1012 1013 DefMyAddress.ipaddr.s_addr = DefHisAddress.ipaddr.s_addr = 0L; 1014 if (argc > 4) 1015 return -1; 1016 1017 if (argc > 0) { 1018 if (ParseAddr(argc, argv++, 1019 &DefMyAddress.ipaddr, 1020 &DefMyAddress.mask, 1021 &DefMyAddress.width) == 0) 1022 return 1; 1023 if (--argc > 0) { 1024 if (ParseAddr(argc, argv++, 1025 &DefHisAddress.ipaddr, 1026 &DefHisAddress.mask, 1027 &DefHisAddress.width) == 0) 1028 return 2; 1029 if (--argc > 0) { 1030 ifnetmask = GetIpAddr(*argv); 1031 if (--argc > 0) { 1032 if (ParseAddr(argc, argv++, 1033 &DefTriggerAddress.ipaddr, 1034 &DefTriggerAddress.mask, 1035 &DefTriggerAddress.width) == 0) 1036 return 3; 1037 } 1038 } 1039 } 1040 } 1041 /* 1042 * For backwards compatibility, 0.0.0.0 means any address. 1043 */ 1044 if (DefMyAddress.ipaddr.s_addr == 0) { 1045 DefMyAddress.mask.s_addr = 0; 1046 DefMyAddress.width = 0; 1047 } 1048 if (DefHisAddress.ipaddr.s_addr == 0) { 1049 DefHisAddress.mask.s_addr = 0; 1050 DefHisAddress.width = 0; 1051 } 1052 1053 if ((mode & MODE_AUTO) || 1054 ((mode & MODE_DEDICATED) && dstsystem)) { 1055 if (OsSetIpaddress(DefMyAddress.ipaddr, DefHisAddress.ipaddr, ifnetmask) < 0) 1056 return 4; 1057 } 1058 return 0; 1059} 1060 1061#ifndef NOMSEXT 1062 1063void 1064SetMSEXT(pri_addr, sec_addr, argc, argv) 1065struct in_addr *pri_addr; 1066struct in_addr *sec_addr; 1067int argc; 1068char **argv; 1069{ 1070 int dummyint; 1071 struct in_addr dummyaddr; 1072 1073 pri_addr->s_addr = sec_addr->s_addr = 0L; 1074 1075 if( argc > 0 ) { 1076 ParseAddr(argc, argv++, pri_addr, &dummyaddr, &dummyint); 1077 if( --argc > 0 ) 1078 ParseAddr(argc, argv++, sec_addr, &dummyaddr, &dummyint); 1079 else 1080 sec_addr->s_addr = pri_addr->s_addr; 1081 } 1082 1083 /* 1084 * if the primary/secondary ns entries are 0.0.0.0 we should 1085 * set them to either the localhost's ip, or the values in 1086 * /etc/resolv.conf ?? 1087 * 1088 * up to you if you want to implement this... 1089 */ 1090 1091} 1092 1093static int 1094SetNS(list, argc, argv) 1095struct cmdtab *list; 1096int argc; 1097char **argv; 1098{ 1099 SetMSEXT(&ns_entries[0], &ns_entries[1], argc, argv); 1100 return 0; 1101} 1102 1103static int 1104SetNBNS(list, argc, argv) 1105struct cmdtab *list; 1106int argc; 1107char **argv; 1108{ 1109 SetMSEXT(&nbns_entries[0], &nbns_entries[1], argc, argv); 1110 return 0; 1111} 1112 1113#endif /* MS_EXT */ 1114 1115#define VAR_AUTHKEY 0 1116#define VAR_DIAL 1 1117#define VAR_LOGIN 2 1118#define VAR_AUTHNAME 3 1119#define VAR_DEVICE 4 1120#define VAR_ACCMAP 5 1121#define VAR_PHONE 6 1122 1123static int 1124SetVariable(list, argc, argv, param) 1125struct cmdtab *list; 1126int argc; 1127char **argv; 1128int param; 1129{ 1130 u_long map; 1131 char *arg; 1132 1133 if (argc > 0) 1134 arg = *argv; 1135 else 1136 arg = ""; 1137 1138 switch (param) { 1139 case VAR_AUTHKEY: 1140 strncpy(VarAuthKey, arg, sizeof(VarAuthKey)-1); 1141 VarAuthKey[sizeof(VarAuthKey)-1] = '\0'; 1142 break; 1143 case VAR_AUTHNAME: 1144 strncpy(VarAuthName, arg, sizeof(VarAuthName)-1); 1145 VarAuthName[sizeof(VarAuthName)-1] = '\0'; 1146 break; 1147 case VAR_DIAL: 1148 strncpy(VarDialScript, arg, sizeof(VarDialScript)-1); 1149 VarDialScript[sizeof(VarDialScript)-1] = '\0'; 1150 break; 1151 case VAR_LOGIN: 1152 strncpy(VarLoginScript, arg, sizeof(VarLoginScript)-1); 1153 VarLoginScript[sizeof(VarLoginScript)-1] = '\0'; 1154 break; 1155 case VAR_DEVICE: 1156 CloseModem(); 1157 strncpy(VarDevice, arg, sizeof(VarDevice)-1); 1158 VarDevice[sizeof(VarDevice)-1] = '\0'; 1159 VarBaseDevice = rindex(VarDevice, '/'); 1160 VarBaseDevice = VarBaseDevice ? VarBaseDevice + 1 : ""; 1161 break; 1162 case VAR_ACCMAP: 1163 sscanf(arg, "%lx", &map); 1164 VarAccmap = map; 1165 break; 1166 case VAR_PHONE: 1167 strncpy(VarPhoneList, arg, sizeof(VarPhoneList)-1); 1168 VarPhoneList[sizeof(VarPhoneList)-1] = '\0'; 1169 strcpy(VarPhoneCopy, VarPhoneList); 1170 VarNextPhone = VarPhoneCopy; 1171 break; 1172 } 1173 return 0; 1174} 1175 1176static int SetCtsRts(list, argc, argv) 1177struct cmdtab *list; 1178int argc; 1179char **argv; 1180{ 1181 if (argc > 0) { 1182 if (strcmp(*argv, "on") == 0) 1183 VarCtsRts = TRUE; 1184 else if (strcmp(*argv, "off") == 0) 1185 VarCtsRts = FALSE; 1186 else 1187 return -1; 1188 return 0; 1189 } 1190 return -1; 1191} 1192 1193 1194static int SetOpenMode(list, argc, argv) 1195struct cmdtab *list; 1196int argc; 1197char **argv; 1198{ 1199 if (argc > 0) { 1200 if (strcmp(*argv, "active") == 0) 1201 VarOpenMode = OPEN_ACTIVE; 1202 else if (strcmp(*argv, "passive") == 0) 1203 VarOpenMode = OPEN_PASSIVE; 1204 else 1205 return -1; 1206 return 0; 1207 } 1208 return -1; 1209} 1210 1211extern int SetIfilter(), SetOfilter(), SetDfilter(), SetAfilter(); 1212 1213struct cmdtab const SetCommands[] = { 1214 { "accmap", NULL, SetVariable, LOCAL_AUTH, 1215 "Set accmap value", "set accmap hex-value", (void *)VAR_ACCMAP}, 1216 { "afilter", NULL, SetAfilter, LOCAL_AUTH, 1217 "Set keep Alive filter", "set afilter ..."}, 1218 { "authkey", "key", SetVariable, LOCAL_AUTH, 1219 "Set authentication key", "set authkey|key key", (void *)VAR_AUTHKEY}, 1220 { "authname", NULL, SetVariable, LOCAL_AUTH, 1221 "Set authentication name", "set authname name", (void *)VAR_AUTHNAME}, 1222 { "ctsrts", NULL, SetCtsRts, LOCAL_AUTH, 1223 "Use CTS/RTS modem signalling", "set ctsrts [on|off]"}, 1224 { "device", "line", SetVariable, LOCAL_AUTH, 1225 "Set modem device name", "set device|line device-name", (void *)VAR_DEVICE}, 1226 { "dfilter", NULL, SetDfilter, LOCAL_AUTH, 1227 "Set demand filter", "set dfilter ..."}, 1228 { "dial", NULL, SetVariable, LOCAL_AUTH, 1229 "Set dialing script", "set dial chat-script", (void *)VAR_DIAL}, 1230 { "escape", NULL, SetEscape, LOCAL_AUTH, 1231 "Set escape characters", "set escape hex-digit ..."}, 1232 { "ifaddr", NULL, SetInterfaceAddr, LOCAL_AUTH, 1233 "Set destination address", "set ifaddr [src-addr [dst-addr [netmask [trg-addr]]]]"}, 1234 { "ifilter", NULL, SetIfilter, LOCAL_AUTH, 1235 "Set input filter", "set ifilter ..."}, 1236 { "log", NULL, SetLogLevel, LOCAL_AUTH, 1237 "Set log level", "set log [+|-]value..."}, 1238 { "login", NULL, SetVariable, LOCAL_AUTH, 1239 "Set login script", "set login chat-script", (void *)VAR_LOGIN }, 1240 { "mru", NULL, SetInitialMRU, LOCAL_AUTH, 1241 "Set Initial MRU value", "set mru value" }, 1242 { "mtu", NULL, SetPreferredMTU, LOCAL_AUTH, 1243 "Set Preferred MTU value", "set mtu value" }, 1244 { "ofilter", NULL, SetOfilter, LOCAL_AUTH, 1245 "Set output filter", "set ofilter ..." }, 1246 { "openmode", NULL, SetOpenMode, LOCAL_AUTH, 1247 "Set open mode", "set openmode [active|passive]"}, 1248 { "parity", NULL, SetModemParity, LOCAL_AUTH, 1249 "Set modem parity", "set parity [odd|even|none]"}, 1250 { "phone", NULL, SetVariable, LOCAL_AUTH, 1251 "Set telephone number(s)", "set phone phone1[:phone2[...]]", (void *)VAR_PHONE }, 1252 { "reconnect",NULL, SetReconnect, LOCAL_AUTH, 1253 "Set Reconnect timeout", "set reconnect value ntries"}, 1254 { "redial", NULL, SetRedialTimeout, LOCAL_AUTH, 1255 "Set Redial timeout", "set redial value|random[.value|random] [dial_attempts]"}, 1256 { "speed", NULL, SetModemSpeed, LOCAL_AUTH, 1257 "Set modem speed", "set speed value"}, 1258 { "timeout", NULL, SetIdleTimeout, LOCAL_AUTH, 1259 "Set Idle timeout", "set timeout value"}, 1260#ifndef NOMSEXT 1261 { "ns", NULL, SetNS, LOCAL_AUTH, 1262 "Set NameServer", "set ns pri-addr [sec-addr]"}, 1263 { "nbns", NULL, SetNBNS, LOCAL_AUTH, 1264 "Set NetBIOS NameServer", "set nbns pri-addr [sec-addr]"}, 1265#endif 1266 { "help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 1267 "Display this message", "set help|?", (void *)SetCommands}, 1268 { NULL, NULL, NULL }, 1269}; 1270 1271static int 1272SetCommand(list, argc, argv) 1273struct cmdtab *list; 1274int argc; 1275char **argv; 1276{ 1277 if (argc > 0) 1278 FindExec(SetCommands, argc, argv); 1279 else if (VarTerm) 1280 fprintf(VarTerm, "Use `set ?' to get a list or `set ? <var>' for" 1281 " syntax help.\n"); 1282 else 1283 LogPrintf(LogWARN, "set command must have arguments\n"); 1284 1285 return 0; 1286} 1287 1288 1289static int 1290AddCommand(list, argc, argv) 1291struct cmdtab *list; 1292int argc; 1293char **argv; 1294{ 1295 struct in_addr dest, gateway, netmask; 1296 1297 if (argc == 3) { 1298 dest = GetIpAddr(argv[0]); 1299 netmask = GetIpAddr(argv[1]); 1300 if (strcasecmp(argv[2], "HISADDR") == 0) 1301 gateway = IpcpInfo.his_ipaddr; 1302 else 1303 gateway = GetIpAddr(argv[2]); 1304 OsSetRoute(RTM_ADD, dest, gateway, netmask); 1305 return 0; 1306 } 1307 1308 return -1; 1309} 1310 1311static int 1312DeleteCommand(list, argc, argv) 1313struct cmdtab *list; 1314int argc; 1315char **argv; 1316{ 1317 struct in_addr dest, gateway, netmask; 1318 1319 if (argc >= 2) { 1320 dest = GetIpAddr(argv[0]); 1321 if (strcasecmp(argv[1], "HISADDR") == 0) 1322 gateway = IpcpInfo.his_ipaddr; 1323 else 1324 gateway = GetIpAddr(argv[1]); 1325 netmask.s_addr = 0; 1326 if (argc == 3) { 1327 if (inet_aton(argv[2], &netmask) == 0) { 1328 LogPrintf(LogWARN, "Bad netmask value.\n"); 1329 return -1; 1330 } 1331 } 1332 OsSetRoute(RTM_DELETE, dest, gateway, netmask); 1333 } else if (argc == 1 && strcasecmp(argv[0], "all") == 0) { 1334 DeleteIfRoutes(0); 1335 } else 1336 return -1; 1337 1338 return 0; 1339} 1340 1341static int AliasEnable(); 1342static int AliasOption(); 1343 1344static struct cmdtab const AliasCommands[] = 1345{ 1346 { "enable", NULL, AliasEnable, LOCAL_AUTH, 1347 "enable IP aliasing", "alias enable [yes|no]"}, 1348 { "port", NULL, AliasRedirectPort, LOCAL_AUTH, 1349 "port redirection", "alias port [proto addr_local:port_local port_alias]"}, 1350 { "addr", NULL, AliasRedirectAddr, LOCAL_AUTH, 1351 "static address translation", "alias addr [addr_local addr_alias]"}, 1352 { "deny_incoming", NULL, AliasOption, LOCAL_AUTH, 1353 "stop incoming connections", "alias deny_incoming [yes|no]", 1354 (void*)PKT_ALIAS_DENY_INCOMING}, 1355 { "log", NULL, AliasOption, LOCAL_AUTH, 1356 "log aliasing link creation", "alias log [yes|no]", 1357 (void*)PKT_ALIAS_LOG}, 1358 { "same_ports", NULL, AliasOption, LOCAL_AUTH, 1359 "try to leave port numbers unchanged", "alias same_ports [yes|no]", 1360 (void*)PKT_ALIAS_SAME_PORTS}, 1361 { "use_sockets", NULL, AliasOption, LOCAL_AUTH, 1362 "allocate host sockets", "alias use_sockets [yes|no]", 1363 (void*)PKT_ALIAS_USE_SOCKETS }, 1364 { "unregistered_only", NULL, AliasOption, LOCAL_AUTH, 1365 "alias unregistered (private) IP address space only", 1366 "alias unregistered_only [yes|no]", 1367 (void*)PKT_ALIAS_UNREGISTERED_ONLY}, 1368 { "help", "?", HelpCommand, LOCAL_AUTH | LOCAL_NO_AUTH, 1369 "Display this message", "alias help|?", 1370 (void *)AliasCommands}, 1371 { NULL, NULL, NULL }, 1372}; 1373 1374 1375static int 1376AliasCommand(list, argc, argv) 1377struct cmdtab *list; 1378int argc; 1379char **argv; 1380{ 1381 if (argc > 0) 1382 FindExec(AliasCommands, argc, argv); 1383 else if (VarTerm) 1384 fprintf(VarTerm, "Use `alias help' to get a list or `alias help <option>'" 1385 " for syntax help.\n"); 1386 else 1387 LogPrintf(LogWARN, "alias command must have arguments\n"); 1388 1389 return 0; 1390} 1391 1392static int 1393AliasEnable(list, argc, argv) 1394struct cmdtab *list; 1395int argc; 1396char **argv; 1397{ 1398 if (argc == 1) 1399 if (strcasecmp(argv[0], "yes") == 0) { 1400 if (!(mode & MODE_ALIAS)) { 1401 if (loadAliasHandlers(&VarAliasHandlers) == 0) { 1402 mode |= MODE_ALIAS; 1403 return 0; 1404 } 1405 LogPrintf(LogWARN, "Cannot load alias library\n"); 1406 return 1; 1407 } 1408 return 0; 1409 } else if (strcasecmp(argv[0], "no") == 0) { 1410 if (mode & MODE_ALIAS) { 1411 unloadAliasHandlers(); 1412 mode &= ~MODE_ALIAS; 1413 } 1414 return 0; 1415 } 1416 1417 return -1; 1418} 1419 1420 1421static int 1422AliasOption(list, argc, argv, param) 1423struct cmdtab *list; 1424int argc; 1425char **argv; 1426void* param; 1427{ 1428 if (argc == 1) 1429 if (strcasecmp(argv[0], "yes") == 0) { 1430 if (mode & MODE_ALIAS) { 1431 VarSetPacketAliasMode((unsigned)param, (unsigned)param); 1432 return 0; 1433 } 1434 LogPrintf(LogWARN, "alias not enabled\n"); 1435 } else if (strcmp(argv[0], "no") == 0) { 1436 if (mode & MODE_ALIAS) { 1437 VarSetPacketAliasMode(0, (unsigned)param); 1438 return 0; 1439 } 1440 LogPrintf(LogWARN, "alias not enabled\n"); 1441 } 1442 1443 return -1; 1444} 1445