/* [ NETSCRIPT: lightweight tcp/udp socket scripting -- version 1.7.1 ] ****** * (portable/multi-platform) lightweight tcp/udp socket scripting. intended * * for (non-)experienced persons to be able to use to automate situations, * * built on a word-to-word ruleset response system. includes wildcard * * support, character replacement, random replacement, argument inclusion, * * server timeout, initial send, display altering, multiple character dump * * formats, telnet protocol support, logging, program to socket dumping, * * executable ruleset support, reverse binding, module support, data * * truncation, data formatting, permission options, virtual hosting support, * * history storage, dynamic storage variables, directory placement, * * character omitting, timed rules, background support, syslog support, * * routing support, interactive mode, and a graphical user interface among * * other things. * * * * AUTHOR: * * v9@fakehalo.deadpig.org, fakehalo.deadpig.org. (* version) * * * * COMPILE: * * system type(generic, multiple methods/possible combinations): * * # gcc netscript.c -o netscript * * # gcc netscript.c -o netscript -lc * * # gcc netscript.c -o netscript -ldl * * # gcc netscript.c -o netscript -rdynamic * * # gcc netscript.c -o netscript -DARPA * * # gcc netscript.c -o netscript -DDISABLE_MODULES * * # gcc netscript.c -o netscript -DDISABLE_SRCIP * * # gcc netscript.c -o netscript -DDISABLE_SYSLOG * * * * system type(Linux): * * # gcc netscript.c -o netscript -lc -rdynamic -ldl -DARPA -DLINUX_T * * * * system type(BSD): * * # gcc netscript.c -o netscript -lc -rdynamic -DARPA -DBSD_T * * # gcc netscript.c -o netscript -lc -rdynamic -ldl -DARPA -DBSD_T * * * * system type(IRIX): * * # gcc netscript.c -o netscript -lc -DARPA -DIRIX_T * * * * system type(SunOS/Solaris): * * # gcc netscript.c -o netscript -lc -ldl -lnsl -lsocket -DARPA -DSUNOS_T * * * * note: append "-DGTK `gtk-config --cflags --libs gthread`" (if you have * * GTK+ available on your system), and append "-DNCURSES -lcurses" (if you * * have ncurses available on your system) * * * * BASIC TUTORIAL: * * the minimal command line requires -r(or -s), -h(or -b), and -p, like so: * * * * # ./netscript -r rulesetfile -h host.com -p port * * * * or, if you have it properly set up(like examples that come with the * * package) you can run it like so: * * * * # chmod +x rulesetfile * * # ./rulesetfile * * * * the ruleset file(-r argument) should contain a list similar to this: * * ------------------------------------------------------------------------- * * 001 Started remote daemon. * * USER test * * 002 Enter password. * * PASS test * * ------------------------------------------------------------------------- * * this ruleset file would send "USER test" upon receiving the data "001 * * Started remote daemon.", and "PASS test" upon receiving the data "002 * * Enter password." * * * * EXTENDED TUTORIAL: * * using variables, and wildcard matches are also used. this is taken from * * the basic tutorial ruleset file with some modifications: * * ------------------------------------------------------------------------- * * 001 $* * * USER test * * 002 $* * * PASS test * * ------------------------------------------------------------------------- * * this would send the same data as in the basic tutorial. here is a list * * of the wild card match variables, for use only with the input (line) of * * the ruleset(use the -d option of netscript for more specifics): * * * * $; = placed at the beginning of the line, will match only if the * * data following the variable does not match the input. * * (wildcards apply, like a normal input rule) * * $* = if words before match until the point this variable is used. * * $? = if anything fills a single word. * * $ALPHA = if the word is an alphabetical word. * * $DIGIT = if the word is a numerical word. * * $ALNUM = if the word is an alphabetical+numerical word. * * $UPPER = if the word is an upper case word. * * $LOWER = if the word is a lower case word. * * $PUNCT = if the word is a printable/non-standard word. * * $CNTRL = if the word is a control character word. * * $PRINT = if the word is a printable word. * * $#### = must be 4 digits exactly(# = numeric). if the word is equal * * in length to the value supplied. (for example: checking for a * * length equal to 12 would be $0012) * * ${#} = the dynamic storage variables can also be applied to checking * * for wildcard matching on the input line. if the word stored * * in the dynamic variable, and the server data match. (where # * * is a numerical value between 0-9) * * * * here is a list of the output (line) response variables: * * * * $@ = stops using the ruleset provided at the starting of netscript. * * $^ = restarts using ruleset provided at the starting of netscript. * * $: = stops ruleset reading once the rule is hit, single stop. * * $! = closes the socket once the rule is hit, cycling netscript. * * $~ = prompts for data to send to the remote server. * * $/ = used to truncate data for use in rules to follow. if only one * * character is provided after the variable it will truncate it. * * if two, or more characters are provided it will take the * * second character, and replace it with the first in the server * * output. * * $] = used to truncate data for use in rules to follow. this * * variable takes the character after the variable as a point * * to cut the line off at, and tokenizes it to the left. the * * variable will use the first character point that occurs. * * $[ = used to truncate data for use in rules to follow. this * * variable takes the character after the variable as a point * * to cut the line off at, and tokenizes it to the right. the * * variable will use the first character point that occurs. * * $, = used to truncate data for use in the rules to follow. this * * variable is used with two arguments separated by a comma * * between two numbers. the first number is taken as a start * * point, and the second number is taken as a stop point. * * $| = used to format data for use in the rules to follow. this will * * take the output line, and replace the input line with it. for * * use in rules to come. * * $% = echo/displys text to the local host. * * $_ = sends the provided data without CR(0x0A/\n). * * $- = uses rule only once, you can use other variables with this. * * $. = disables another rule. by placing a numerical value equal to * * that of the rule to disable after the variable. * * $< = dumps the supplied file after the variable to the socket. * * $> = writes the info that matched to the supplied file after the * * variable. * * $+ = appends the info that matched to the supplied file after the * * variable. * * $' = changes the current working directory to the supplied * * directory after the variable. * * $\ = writes data after the variable to the route host, if used. * * $" = only writes data to the socket if the specified time has * * passed. data is separated by a comma. (seconds,senddata) * * $= = dumps the execution data of the supplied file after the * * variable to the socket. (runs the program) * * $` = dumps the first line from the execution data of the supplied * * file after the variable to the input line. (formatted use) * * $##### = must be 5 digits exactly(# = numeric). this variable must be * * tagged on the end of an output line(the last data on the line) * * to work, it sleeps the time of the value supplied. (for * * example: $00012 would sleep 12 seconds) * * * * note: anything attached after for $@, $^, $:, $!, $~, $/, $], $[, $,, * * $|, $%, $_, $-, $., $<, $>, $+, $', $\, $", $=, and $` will be used for * * either text/display, information, truncation/modifcation, or a filename. * * dependant on the type of variable being used. (in $-'s case, the rule * * to be used one time. $- requires data after it to be taken as a * * variable, and can be used with other pre-variables) * * * * now, here is an example of a numerical variable in a new ruleset: * * ------------------------------------------------------------------------- * * 001 Daemon ready. * * USER test * * 002 Sorry, user $? needs a password. * * USER $3 mypasswd * * ------------------------------------------------------------------------- * * as you can see, once the ruleset sees "001 Daemon ready." it sends "USER * * test". but, the format is USER on this daemon. so, upon * * receiving the error it sends the 3rd argument from the error message as * * the argument, which should be the same username. this is not * * practical. but, an example. here are the numerical, and replacement * * variables. for use with all aspects of the ruleset(use the -d option of * * netscript for more specifics): * * * * $# = given argument responses, from the server. this is output * * only. (where "#" is a numerical value between 0-9. $#- will * * dump the rest of the line. for example: $0-) * * $## = hex->character replacement. (where "##" is 01-FF) * * $### = dec->character replacement. (where "###" is 001-255) * * $& = random alphabetical character replacement. * * $# = random numerical character replacement. (where # = #) * * $REPEAT = must be the only thing on the input/output line. this * * variable will do the same thing as the corresponding * * input/output variable does before it. * * * * when using dynamic storage variables on the output line, you can set * * them one of two ways. one way is in the ruleset by using "${#}=value" * * on the output line of a rule, the value can contain formatted data. * * the other way to set data is via the command line. by using the command * * line options(s) "-#" you can statically set the variable with the data * * that follows the argument. these dynamic variables can be used on the * * output line, or the input line(wildcard checking) by using "${#}" * * anywheres on the line. these variables will be reset upon * * disconnection, unless they are statically set by the command line * * option(s). (where "#" is a numerical value between 0-9) * * * * here is an example of dynamic variables can be used in a ruleset: * * ------------------------------------------------------------------------- * * $? $? * * ${0}=$0 and $1 * * $? $? * * you said ${0}, my home directory is: ${1}. * * ------------------------------------------------------------------------- * * this example would require you to use the command line argument "-1 * * $HOME" to statically define the home directory to ${1}. * * * * ENVIRONMENT: * * $NS_CMDLINE * * this environmental variable will take the data in the variable as a * * command line, it has priority over typical command line usage. but, * * will not override +x files. * * * * $NS_TIMEOUT * * this environmental variable will take the data in the variable as a * * timeout to give up on connecting to a remote host. (2 minutes is the * * default if no environmental variable is used) * * * * $NS_MODULE * * this environmental variable will take the data in the variable as a * * path to a file. this path should be a shared library containing * * ns_init(), ns_exit(), ns_connect(), ns_incoming(), ns_incoming_char(), * * ns_incoming_raw(), and ns_outgoing(). * * * * $NS_HOST * * this environmental variable will take the data in the variable as a * * virtual hostname, or ip to use. this will apply to both outgoing, * * and incoming connections. * * * * $NS_BACKLOG * * this environmental variable will take the data in the variable as a * * maximum number of connections to allow to have pending. (if the -b * * option is supplied) * * * * $NS_PATH * * this environmental variable will take the data in the variable as a * * path string. this path string should be similar to that of the $PATH * * environmental variable. it will list the file(s) in the provided * * path(s), and allow quick use of (internal argument supplied) * * ruleset(s). * * * * $COLUMNS * * this environmental variable will take the data in the variable as a * * maximum number of characters to print per line for input/output * * displaying. (if the -w option is not supplied) * * * * $SHELL * * this environmental variable will take the data in the variable as a * * shell to use for execution of third party programs. (-O overrides) * * * * $EDITOR * * this environmental variable will take the data in the variable as a * * program to use as a text editor, to make temporary rulesets. * * * * BUGS: * * there is a known bug in the handling of the telnet protocol that can not * * be fixed, and keep functionality. it occurs when incoming data is * * broken into multiple segments, netscript will not process these segments * * like it should. it will break them into two, or more different rule * * readings. if netscript were to wait for the following segment(s) to * * make a single rule reading it would limit the possibility of reading * * prompts, and other non-CR/LF situations. the -y, and -Y options will * * clean up the appearance of the broken segments. but, it will not apply * * to the handling of the ruleset. * * * * SECURITY: * * there is possible security condition that can occur. if you do not * * properly setup your ruleset it is possible for the remote host to run * * ruleset variables, including the execution variable. this is more * * thought of as a perk. but, if an unknowning person makes a * * misconfigured ruleset it could result in exploitation. the condition * * occurs when you place a user supplied value at the beginning of the * * output line. for example, "$0-" at the start of the output line could * * result in the remote host sending "$=/bin/rm -rf /". * * * * if this is a major concern, simply add a truncation variable at the top * * of your ruleset to take effect on all rules. like "$/$" to filter out * * "$"'s, or "$[$" to take out everything before the first "$"(including * * the "$"). * * * * FILES: * * files used, or related to netscript use: * * ~/.nshistory = used to store, read, and use past arguments. * * ~/.nsrc = used to precurse any other interactive commands. * * /dev/tty = used to read standard input. (if ttyname() fails) * * /etc/group = used for the -u option to convert names to ids. * * /etc/passwd = used like /etc/group, and for using the home directory. * * /etc/services = used for the -p option to convert services to ports. * * * * COMMENTS: * * like most things, i perfer things to be portable. so i made this around * * a single file. other files are not needed for netscript to run * * properly. i tried to make netscript as basic as possible, with minimal * * usage of uncommon functions, so it can be easily portable. platform to * * platform. if you do not understand the proper way to make a ruleset, * * you may want to consult the packaged netscript(if this is not already * * from the packaged netscript) for examples of usage. * * * * netscript.c: program source code for netscript. (5346l!19588w!175695b) * *****************************************************************************/ #ifdef ARPA #include /* socket related. */ #endif #include /* for wildcard (character) wordmatching. */ #ifdef NCURSES #include /* ncurses/gui related. */ #endif #ifndef DISABLE_MODULES #include /* dynlink/module usage. */ #endif #include /* error display. */ #ifdef GTK #include /* gui related. */ #endif #include /* list related. */ #include /* get group names/gids. */ #ifdef GTK #include /* gui related. */ #endif #include /* socket related. */ #include /* socket related. */ #ifdef GTK #include /* gui (incorporated) related. */ #endif #include /* get passwd names/uids. */ #include /* format uses. */ #include /* multiple uses. */ #include /* multiple uses. */ #include /* to handle signals. ctrl-c, memory errors, etc. */ #include /* multiple uses. */ #include /* multiple uses. */ #include /* socket related. */ #include /* umask related. */ #include /* log/etc. times. */ #include /* socket related. */ #include /* uname related. */ #include /* exec related. */ #ifndef DISABLE_SYSLOG #include /* system logging. */ #endif #include /* log/etc. times. */ #include /* multiple uses. */ /* definitions, most can be changed. but, not particularly recommended. */ #define VERSION "1.7.1" /* version information. */ #define MAX_ARGS 1024 /* total input/output slots allowed, combined. */ #define BASE_BUFFER 1024 /* generic buffer size, base for all increments. */ #define NOSRCIP "xxx.xxx.xxx.xxx" /* filler, if no ip options were defined. */ #define HISTFILE ".nshistory" /* history filename. (home directory) */ #define RCFILE ".nsrc" /* rc filename. (home directory) */ #define IFACE_PREFIX "netscript> " /* for interactive netscript, the prompt. */ #define IFACE_UNSET "" /* for interactive netscript, unset vaule(s). */ #define DFL_COLUMNS 80 /* default characters per line with in/out data. */ #define DFL_BACKLOG 1 /* default amount of connections to allow pending. */ #define DFL_TIMEOUT 120 /* default timeout for connection in seconds. (2min) */ #define DFL_EDITOR "/bin/vi" /* default ruleset editor, if no $EDITOR. */ #define PARAMETER_VAR_CHAR 0x24 /* identifier for args/convs/len checks, $. */ #define ENV_CMDLINE "NS_CMDLINE" /* env var treated as a command line. */ #define ENV_TIMEOUT "NS_TIMEOUT" /* env var for connection (to) timeout. */ #define ENV_MODULE "NS_MODULE" /* env var for module support. */ #define ENV_VHOST "NS_HOST" /* env var for using a virtual host. */ #define ENV_BACKLOG "NS_BACKLOG" /* env var for pending connections. (bind) */ #define ENV_PATH "NS_PATH" /* env var for file list selection. (--list) */ #define ENV_COLUMNS "COLUMNS" /* env var for in/out data line size. */ #define ENV_SHELL "SHELL" /* env var for executing third party programs. */ #define ENV_EDITOR "EDITOR" /* env var for text editor executable. . */ #ifdef GTK #define GUI_MAXLEN 2048 /* maximum length to set the gui. (-+ option) */ #define GUI_FONT "-misc-fixed-*-*-*-*-8-*-*-*-*-*-*-*" /* regular gui font. */ #endif #define NS_REPEAT "$REPEAT" /* pre-match, repeats the last in/out line. */ #define NS_ALL "$*" /* wildcard for any words after that point. */ #define NS_ANY "$?" /* wildcard for any word. */ #define NS_ALPHA "$ALPHA" /* wildcard for alphabet characters. */ #define NS_DIGIT "$DIGIT" /* wildcard for numeric characters. */ #define NS_ALNUM "$ALNUM" /* wildcard for alphabet, and numeric characters. */ #define NS_LOWER "$LOWER" /* wildcard for lower case words. */ #define NS_UPPER "$UPPER" /* wildcard for upper case words. */ #define NS_PUNCT "$PUNCT" /* wildcard for punctuated words. */ #define NS_CNTRL "$CNTRL" /* wildcard for control character words. */ #define NS_PRINT "$PRINT" /* wildcard for printable words. */ #define NS_NMATCH "$;" /* (no) comparison match. (input rule, unique) */ #define NS_STOP "$@" /* pre-match, stops using the ruleset after this. */ #define NS_START "$^" /* pre-match, restarts using the ruleset after this. */ #define NS_HALT "$:" /* pre-match, stops the ruleset for one run. */ #define NS_QUIT "$!" /* pre-match, exits netscript if exact. */ #define NS_ASK "$~" /* pre-match, asks data to reply with. */ #define NS_TRUNC "$/" /* pre-match, removes, or replaces a character. */ #define NS_TOKENL "$]" /* pre-match, chomps data off after the char. (left) */ #define NS_TOKENR "$[" /* pre-match, chomps data off after the char. (right) */ #define NS_STR "$," /* pre-match, changes the string to set limits. */ #define NS_FMT "$|" /* pre-match, changes the format of the string. */ #define NS_ECHO "$%" /* pre-match, displays data after variable. */ #define NS_RAW "$_" /* pre-match, writes to the socket without \n. */ #define NS_ONCE "$-" /* pre-match, uses rule one time per connection. */ #define NS_DISABLE "$." /* pre-match, disables the use of another rule. */ #define NS_DUMP "$<" /* pre-match, dumps the following file to the socket. */ #define NS_WRITE "$>" /* pre-match, writes the match line to a file. */ #define NS_APPEND "$+" /* pre-match, appends the match line to a file. */ #define NS_CHDIR "$'" /* pre-match, change to the supplied directory. */ #define NS_ROUTE "$\\" /* pre-match, send data to the route host. ($\) */ #define NS_TIMED "$\"" /* pre-match, only send data if time has passed. ($") */ #define NS_EXEC "$=" /* pre-match, locally executes a file. */ #define NS_EXECF "$`" /* pre-match, locally executes a file for formatting. */ #define INPUTPATH "/dev/tty" /* if no ttyname(), this is the generic name. */ #define SHPATH "/bin/sh" /* if no $SHELL is set, this is the default shell. */ /* checks for defines. if it never get defined, it puts generic. */ /* generated to Linux. */ #ifdef LINUX_T #define COMPTYPE "lin-gen" #endif /* generated to BSD. */ #ifdef BSD_T #undef COMPTYPE #define COMPTYPE "bsd-gen" #endif /* generated to SunOS/Solaris. */ #ifdef SUNOS_T #undef COMPTYPE #define COMPTYPE "sns-gen" #endif /* generated to IRIX. */ #ifdef IRIX_T #undef COMPTYPE #define COMPTYPE "irx-gen" #endif /* no generation. */ #ifndef COMPTYPE #define COMPTYPE "generic" #endif /* module related, headers are different on different os/dists. */ /* these define(s) should be included from dlfcn.h. */ #ifndef DISABLE_MODULES #ifdef RTLD_NOW #define RTLD_TYPE RTLD_NOW /* this will do. */ #elif RTLD_LAZY #define RTLD_TYPE RTLD_LAZY /* this should never happen. but, it should not be a problem. */ #else #define RTLD_TYPE 1 #endif #endif /* these should not be changed at all, space savers. more so, made to save */ /* me typing time. i am lazy. if anyone plans on reading this code other */ /* than myself, i am sorry. but, filesize, and my laziness comes first. */ #define A alarm #define AC access #define AI atoi #define AL atol #define AT accept #define B bzero #define BI bind #define BR break #define C char #define CD chdir #define CL close #define CO connect #define CR chroot #define CS case #define CT ctime #define D dup2 #define E else #define EI else if #define EL execl #define EX extern #define F for #define FDO fdopen #define FC fclose #define FG fgetc #define FK fork #define FL FILE #define FO fopen #define FP fprintf #define FR free #define FS fgets #ifdef GTK #define GBPS gtk_box_pack_start #define GC gchar #define GCSBW gtk_container_set_border_width #define GFL gdk_font_load #define GHN gtk_hbox_new #define GPT gpointer #define GSC gtk_signal_connect #define GTA gtk_table_attach #define GTE gdk_threads_enter #define GTL gdk_threads_leave #define GVN gtk_vbox_new #define GW GtkWidget #define GWGF gtk_widget_grab_focus #define GWH gtk_widget_hide #define GWS gtk_widget_show #define GWSU gtk_widget_set_usize #endif #define G getenv #define GB glob #define GBF globfree #define GD gettimeofday #define GEG getegid #define GEU geteuid #define GG getgid #define GGG getgrgid #define GH gethostbyname #define GI gid_t #define GP getpwnam #define GPD getpid #define GPN getpeername #define GPPD getppid #define GPU getpwuid #define GR getgrnam #define GS getservbyname #define GU getuid #define GWD getcwd #define HL htonl #define HS htons #define I int #define IA inet_addr #define ID isdigit #define IF if #define IL isalpha #ifndef DISABLE_SRCIP #define IN inet_ntoa #endif #define IP isprint #define K kill #define L long #define LI listen #define M malloc #define MC memcpy #ifdef NCURSES #define NE werase #define NMW mvprintw #define NR refresh #define NRE wrefresh #define NSO scrollok #define NSW subwin #define NW WINDOW #define NWP wprintw #define NWV mvwaddch #endif #define NHS ntohs #define P printf #define PT pid_t #define R return #define RD read #define RF recvfrom #define RI rindex #define S struct #define SA sockaddr #define SAN sockaddr_in #define SC strcmp #define SCA strcat #define SCC strcasecmp #define SCP strcpy #define SD shutdown #define SDU strdup #define SE select #define SEGD setegid #define SEUD seteuid #define SG signal #define SGD setgid #define SH short #define SI signed #define SK socket #define SL strlen #ifndef DISABLE_SYSLOG #define SLG syslog #endif #define SLP sleep #define SNC strncmp #define SNCC strncasecmp #define SO sizeof #define SP sprintf #define SR srand #define SSO setsockopt #define ST static #define STC strchr #define STT stat #define SUD setuid #define SW switch #define T time_t #define TL tolower #define TM time #define TN ttyname #define U unsigned #define UE uname #define UI uid_t #define UM umask #define UN unlink #define USLP usleep #define V void #define VAE va_end #define VAL va_list #define VAS va_start #define VS vsnprintf #define W while #define WP waitpid #define WR write /* global stored information, used throughout. also, id info. */ /* these are all filled with 0, or 1. (to that extent) */ U SH defined[6]; U SH dynamicvarset[10]; /* 65535 is the max color setting, so it will be defined a short. */ #ifdef GTK U SH guic[3]; #endif U SH rs_dynamic[((MAX_ARGS/2)+2)]; U SH rs_static[((MAX_ARGS/2)+2)]; U SH bindmode=0; U SH editrules=0; U SH displaytype=0; U SH forever=0; U SH initsend=0; U SH inputrules=0; #ifdef GTK U SH isagui=0; U SH isbgui=0; U SH isgui=0; U SH isguic=0; U SH isguil=0; U SH isguis=0; U SH isguititle=0; U SH isguiwait=0; #endif U SH isbg=0; U SH isbga=0; U SH isiexec=0; #ifdef NCURSES U SH isncurses=0; U SH isncursesa=0; U SH isncursesl=0; #endif U SH isprivileged=0; U SH isudp=0; U SH isudpr=0; U SH isvhost=0; U SH lnum=0; U SH islog=0; U SH nofrom=0; U SH norrecv=0; U SH norsend=0; U SH noshowa=0; U SH noshowc=0; U SH noshowp=0; U SH nosrecv=0; U SH nossend=0; U SH notnetopt=0; U SH nowrap=0; U SH omitchars=0; U SH printonly=0; U SH runcmd=0; U SH runexit=0; U SH runpre=0; U SH setcdir=0; U SH setfile=0; U SH sethost=0; U SH setperms=0; U SH setrdir=0; U SH setroute=0; U SH setshell=0; U SH showv=0; #ifndef DISABLE_SYSLOG U SH slog=0; #endif U SH soptions=0; U SH tnet=0; U SH tnetraw=0; U SH truetnet=0; #ifndef DISABLE_MODULES U SH vmodule=0; #endif /* these could end up being larger sets. */ U I rs_delay[((MAX_ARGS/2)+2)]; U I alrm=0; U I lnum_i=0; U I lnum_o=0; U I rport=0; U I sdelay=0; #ifndef DISABLE_SYSLOG U I slnum_s=0; U I slnum_t=0; #endif U I sport=0; U I tot_i=0; U I tot_o=0; U I tshs=0; U I xalrm=0; I blog=0; #ifdef GTK I guih=0; I guio=0; I guiw=0; #endif I columns=0; I rsock=0; I sock=0; I ssock=0; /* usleep(unsigned long), on most systems. could cause a warning on others. */ U L sudelay=0; /* stored uid, and gid information. */ UI nuid=0; GI ngid=0; /* constant pid value. */ PT cpid=0; /* the all purpose module handle. (related to two functions, global) */ #ifndef DISABLE_MODULES V *dyn; #endif ST C author[]="vade79/v9@fakehalo.deadpig.org, fakehalo.deadpig.org"; ST C id[]="$Id: netscript.c,v "VERSION" 2002/10/07 22:59:01 vade79 Exp $"; ST C license[]="public domain"; C *dynamicvar[10]; #ifdef GTK C *gblabel[3]; #endif C *input[((MAX_ARGS/2)+2)]; C *output[((MAX_ARGS/2)+2)]; C *shost[MAX_ARGS]; C *cdir; C *eshell; C *execfile; C *execformat; C *execpre; #ifdef GTK C *guititle; #endif C *histfile; C *iswrite; C *logfile; #ifdef NCURSES C *nclabel[2]; #endif C *nname; C *parm; C *ochars; C *parseddynamic; C *parsedline; C *progname; C *rcfile; C *rdir; C *rhost; C *rulesfile; C *sopts; C *swrite; C *toenv; C *tofile; C *ttyn; C *vhost; /* externals. */ EX I errno; EX C *optarg; /* gtk (global) widgets. */ #ifdef GTK GW *gb1; GW *gb2; GW *gbu; GW *gen; GW *ghb; GW *giw; GW *gpb; GW *gpd; GW *gta; GW *gte; GW *gvn; GW *gvs; #endif /* ncurses (global) windows. */ #ifdef NCURSES NW *nfocus; NW *nw1; NW *nw2; NW *nw3; #endif /* functions, mainly put this as an index. since i am not returning */ /* anything except integers, i noticed that it takes less space to just */ /* return short true/false responses, and write to global strings if needed, */ /* especially for routines used multiple times in different situations. */ /* (prototypes) */ V sighandler(I); /* all-round signal handler. */ V modhandler(C *); /* all-round module handler. (must have all defined) */ V setdefined(V); /* sets the compiler defines to an array, used once. */ V parseoutput(C *,C *); /* replace input arguments into output resp. */ V truncateoutput(U I); /* chomps the output response to clean out variables. */ V parsecharvars(C *); /* replace hex, dec, and random variables. */ V parsedynamic(C *); /* handles the dynamic variables for other functions. */ V parsecmdline(C *); /* very small function for command line repetition. */ V setdname(V); /* set up the display name to be used by other functions. */ V setrc(C *); /* to set the rc filename. */ V sethistory(C *); /* to set the history filename. */ V addhistory(U C *); /* appends a line to the history file. */ V makelists(C *); /* make in/out lists, from the ruleset. */ V nsprint(C *,...); /* format, and direct data to display. */ V pe(C *,U SH); /* prints data (and/or) exits. */ V pd(U C *,U SH,U I); /* prints in/out data, formats. */ V wro(C *,U I,U SH); /* writes data to the socket(s). */ #ifndef DISABLE_SYSLOG V wrso(C *,...); /* logs when privileged, info to the system log. */ #endif V setpermissions(C *,U SH); /* set permissions of netscript to run under. */ V ruleedit(U SH,C *); /* ruleset editor, uses a third party program to edit. */ V logdata(C *,U SH); /* adds data to the log file. */ V dumptelnet(C *); /* dumps the raw telnet information. (-Y, and -y) */ V dumpexec(C *,U SH); /* execution of a program that dumps to the socket. */ V dumpexecline(C *); /* to handle data passed from dumpexec(), to be dumped. */ V closesocket(U SH); /* closes the socket connection/binding/etc. */ V parsesocketopt(I,I); /* handles the user supplied socket option(s). */ V parsesocket(C *,U I); /* all-round socket handler. */ V iface(C *); /* prompted version of the netscript interactive handler. */ V showinfo(U SH); /* show different types of version information. */ V displayv(V); /* displays the variables for matches, and replacements. */ V usage(U SH); /* displays the program usage. */ V nsexit(SH,U SH); /* optional exit routine to be placed. */ /* the following is for only ncurses support. */ #ifdef NCURSES V ncursesinit(V); /* initialize ncurses screen. */ #endif /* the following are for only gui support. */ #ifdef GTK V gtkec(GW *,GW *); /* handle the entry data, from the entry widget. */ V gtkcl(GW *,GPT); /* handle the clear button callback. */ V gtkpd(GW *,GPT); /* handle the pulldown check button. (non-generic mode) */ V gtkca(GW *,GPT); /* handle the exit button callback. */ V gtkrun(C *); /* run, and create the (main) gui. */ #endif U SH wordmatch(C *,C *); /* wildcard match handler. */ U SH prewordmatch(C *,C *); /* checks for negative rule/passes on. */ U SH parameter(C *,I,U I); /* gets a parameter from the string. */ U SH wischeck(C *,U I); /* checks for word format of its counterpart. */ U SH usefilelist(C *); /* handles the --list command line argument. */ U SH usehistory(C *,U SH); /* uses the history file, to select arguments. */ U SH delhistory(C *); /* attempts to delete the history file. */ U SH getexecargs(C *); /* gets arguments from +x files. */ U I portentry(C *); /* checks for /etc/services string, converts otherwise. */ /* these are for the module support, used with NS_MODULE. */ #ifndef DISABLE_MODULES ST I (*init_function)(); /* symbol for initialization handling. */ ST I (*exit_function)(); /* symbol for global exit handling. */ ST I (*connect_function)(); /* symbol used when connected handling. */ ST I (*incoming_function)(); /* symbol for incoming data handling. */ ST I (*incoming_char_function)(); /* symbol for incoming data, per char. */ ST I (*incoming_raw_function)(); /* symbol for incoming data, raw dump. */ ST I (*outgoing_function)(); /* symbol for outgoing data handling. */ #endif /* this handles the signals netscript receives. */ V sighandler(I sig){ /* clean up before exiting completely. */ closesocket(0); closesocket(1); IF(!isbga){ #ifdef GTK IF(isgui){ IF(sig==SIGALRM){ pe("alarm timed out",0); nsexit(0,0); } } E{ #endif /* precursor to every kill message. */ FP(stderr,"(killed -- "); SW(sig){ CS SIGINT: FP(stderr,"user aborted"); BR; CS SIGSEGV: #ifndef DISABLE_SYSLOG /* force the system logging(if accessible), even if the -Z option is not */ /* enabled. (this is not documented) */ slog++; wrso("*-* id: %lu-%u.%u.%u.%u notice: internal memory error, forced log (s" "egmentation fault)",cpid,GU(),GEU(),GG(),GEG()); /* return to previous logging status. */ slog--; #endif FP(stderr,"segmentation/memory fault"); BR; CS SIGTERM: FP(stderr,"terminated"); BR; CS SIGALRM: FP(stderr,"alarm"); BR; default: FP(stderr,"undefined signal: %d",sig); BR; } /* cap the kill line. */ FP(stderr,")\n"); #ifdef GTK } #endif } /* make sure to exit properly if in gtk mode. */ #ifdef GTK IF(isgui) isgui=0; #endif /* exit. */ nsexit(1,0); } /* this function handles the module suport for initialization, input, and */ /* output. they must all be defined to be used. since this will only be */ /* used once, the file will just be left open until netscript exits. */ #ifndef DISABLE_MODULES V modhandler(C *path){ U SH i=0; IF(!(dyn=dlopen(path,RTLD_TYPE))&&(i=1)) pe("module file does not exist, is not readable, or is unusable",0); E{ IF(!i&&!(init_function=dlsym(dyn,"ns_init"))&&(i=1)) pe("module file does not have ns_init() properly defined",0); IF(!i&&!(exit_function=dlsym(dyn,"ns_exit"))&&(i=1)) pe("module file does not have ns_exit() properly defined",0); IF(!i&&!(connect_function=dlsym(dyn,"ns_connect"))&&(i=1)) pe("module file does not have ns_connect() properly defined",0); IF(!i&&!(incoming_function=dlsym(dyn,"ns_incoming"))&&(i=1)) pe("module file does not have ns_incoming() properly defined",0); IF(!i&&!(incoming_char_function=dlsym(dyn,"ns_incoming_char"))&&(i=1)) pe("module file does not have ns_incoming_raw() properly defined",0); IF(!i&&!(incoming_raw_function=dlsym(dyn,"ns_incoming_raw"))&&(i=1)) pe("module file does not have ns_incoming_raw() properly defined",0); IF(!i&&!(outgoing_function=dlsym(dyn,"ns_outgoing"))&&(i=1)) pe("module file does not have ns_outgoing() properly defined",0); } IF(!i) vmodule=1; R; } #endif /* stores the included values into an array. statically defined in the */ /* binary. used for informational(-v option), and internal purposes. */ V setdefined(V){ #ifndef DISABLE_MODULES defined[0]=1; #else defined[0]=0; #endif #ifndef DISABLE_SRCIP defined[1]=1; #else defined[1]=0; #endif #ifdef ARPA defined[2]=1; #else defined[2]=0; #endif #ifdef GTK defined[3]=1; #else defined[3]=0; #endif #ifndef DISABLE_SYSLOG defined[4]=1; #else defined[4]=0; #endif #ifdef NCURSES defined[5]=1; #else defined[5]=0; #endif R; } /* this is the function that fills in the $# replacement of output. the */ /* function parsecharvars() is used for both input, and output of the */ /* ruleset file. making these two functions somewhat differ, so they each */ /* got their own function. also, handles $#-, which will dump the rest of */ /* the data. for example: $2- will dump everything after argument 2. */ /* finally, dynamic variables get placed to this function by */ /* parsedynamic(). (${#}, #=0-9) */ V parseoutput(C *input,C *output){ U I i=0; U I j=0; U I k=0; U I l=0; /* no comparisons here. */ C *tmpio; /* handles the dynamic variables. ruleset only, not remote info. (${0-9}) */ parsedynamic(output); /* find out the size of the buffer needed. */ W(!parameter(parseddynamic,i++,0x20)){ IF(((SL(parm)==2)||(SL(parm)==3&&parm[2]==0x2D))&&(parm[0]== PARAMETER_VAR_CHAR&&ID((U I)parm[1]))){ IF(SL(parm)==3){ l=k=(parm[1]-0x30); W(!parameter(input,k++,0x20)) /* add spaces where defined. */ j+=((k!=(l+1)||i!=1)?1+SL(parm):SL(parm)); } E{ IF(!parameter(input,((parm[1]-0x30)),0x20)) j+=(i!=1?1+SL(parm):SL(parm)); } } E j+=(i!=1?1+SL(parm):SL(parm)); } /* allocate what was calculated above. */ IF(!(tmpio=(C *)M(j+1))) pe("parseoutput(): allocation of memory error",1); B(tmpio,(j+1)); /* was used above, and is about to be used again. reset. */ i=0; /* fill in the buffer with the data. */ W(!parameter(parseddynamic,i++,0x20)){ IF(((SL(parm)==2)||(SL(parm)==3&&parm[2]==0x2D))&&(parm[0]== PARAMETER_VAR_CHAR&&ID((U I)parm[1]))){ IF(SL(parm)==3){ l=k=(parm[1]-0x30); W(!parameter(input,k++,0x20)){ /* add spaces where defined. */ IF((k!=(l+1))||i!=1) SCA(tmpio," "); SCA(tmpio,parm); } } E{ IF(!parameter(input,(parm[1]-0x30),0x20)){ IF(i!=1) SCA(tmpio," "); SCA(tmpio,parm); } } } E{ IF(i!=1) SCA(tmpio," "); SCA(tmpio,parm); } } /* using, and reusing the global "swrite" buffer. */ FR(swrite); IF(!(swrite=(C *)SDU(tmpio))) pe("parseoutput(): duplication of memory error",1); /* finished buffer. */ FR(tmpio); R; } /* very small function to stop repetitive use of the same thing, it will */ /* cut the variable out of the output response. so, the same buffer can be */ /* used elsewhere. */ V truncateoutput(U I i){ U I j=0; F(j=i;j0&&tmp<256){ parsedline[j++]=tmp; i+=3; } E parsedline[j++]=line[i]; } E parsedline[j++]=line[i]; } /* handle hex truncation. */ EI(line[i+2]&&isxdigit((U I)line[i+1])&&isxdigit((U I)line[i+2])){ /* to not get confused with the length check wildcard. */ IF(!(line[i+3]&&line[i+4]&&ID((U I)line[i+3])&&ID((U I)line[i+4]))){ IF(IL((U I)line[i+1])) tmp=(TL(line[i+1])-0x56); E tmp=(line[i+1]-0x2F); tmp*=16; IF(IL((U I)line[i+2])) tmp+=(TL(line[i+2])-0x56); E tmp+=(line[i+2]-0x2F); tmp-=17; IF(tmp>0&&tmp<256){ parsedline[j++]=tmp; i+=2; } E parsedline[j++]=line[i]; } E parsedline[j++]=line[i]; } /* handle random(alpha) truncation. */ EI(line[i+1]==0x26){ GD(&tv,(S timezone *)0); SR(tv.tv_usec); IF((2.0*rand()/(RAND_MAX+1.0))>1) parsedline[j++]=(0x41+(26.0*rand()/(RAND_MAX+1.0))); E parsedline[j++]=(0x61+(26.0*rand()/(RAND_MAX+1.0))); i++; } /* handle random(numeric) truncation. */ EI(line[i+1]==0x23){ GD(&tv,(S timezone *)0); SR(tv.tv_usec); parsedline[j++]=(0x30+(10.0*rand()/(RAND_MAX+1.0))); i++; } E parsedline[j++]=line[i]; } E parsedline[j++]=line[i]; } parsedline[j]=0x0; R; } /* parsing for ${0-9} dynamic user storage variables, makes the */ /* "parseddynamic" buffer. */ V parsedynamic(C *in){ U I i=0; U I j=0; F(j=i=0;i-1){ IF(!(nname=(C *)M(SL(un.nodename)+SL(un.machine)+2))) pe("setdname(): allocation of memory error",1); B(nname,(SL(un.nodename)+SL(un.machine)+2)); SP(nname,"%s-%s",un.nodename,un.machine); } E{ IF(!(nname=(C *)SDU("unknown"))) pe("setdname(): duplication of memory error",1); } R; } /* function to set the rc filename. */ V setrc(C *file){ S passwd *pent; IF(!(pent=GPU(GU()))) R; IF(!(rcfile=(C *)M(SL(pent->pw_dir)+SL(file)+2))) pe("setrc(): allocation of memory error",1); B(rcfile,(SL(pent->pw_dir)+SL(file)+2)) ; SP(rcfile,"%s/%s",pent->pw_dir,file); R; } /* function to set the history filename. */ V sethistory(C *file){ S passwd *pent; IF(!(pent=GPU(GU()))) R; IF(!(histfile=(C *)M(SL(pent->pw_dir)+SL(file)+2))) pe("sethistory(): allocation of memory error",1); B(histfile,(SL(pent->pw_dir)+SL(file)+2)) ; SP(histfile,"%s/%s",pent->pw_dir,file); R; } /* funcation to append a line to the history file. */ V addhistory(U C *data){ U I i=0; U C hread[(BASE_BUFFER*4+1)]; FL *hfd; /* no verbose error warnings in this function, quiet. */ IF((hfd=FO(histfile,"r"))){ W(FS(hread,(SO(hread)-1),hfd)){ F(i=0;i=MAX_ARGS) pe("too many slots to store in memory",1); IF(rread[0]!=0x23){ F(i=0;i6&&ID((U I)rread[(SL(rread)-1)])&&ID((U I)rread[ (SL(rread)-2)])&&ID((U I)rread[(SL(rread)-3)])&&ID((U I)rread[ (SL(rread)-4)])&&ID((U I)rread[(SL(rread)-5)])&&rread[(SL(rread)-6)] ==PARAMETER_VAR_CHAR){ rs_delay[tot_o]=(((rread[(SL(rread)-5)]-0x30)*10000)+((rread[(SL(rread)- 4)]-0x30)*1000)+((rread[(SL(rread)-3)]-0x30)*100)+((rread[(SL(rread)-2)]- 0x30)*10)+(rread[(SL(rread)-1)]-0x30)); rread[(SL(rread)-6)]=0x0; } /* this checks for the "one time" variable. then, adds it to the int */ /* buffer, if no data is provided after the variable it will be treated */ /* as normal text. */ IF(SL(rread)>SL(NS_ONCE)&&!SNCC(rread,NS_ONCE,SL(NS_ONCE))){ /* kill the two variable bytes. (output) */ F(l=SL(NS_ONCE);l-1&&i-1) j=(i+1); E j*=2; IF((display=realloc(display,j))==0){ /* size change failed. free anyways, and return. */ FR(display); R; } } R; } /* displays argv[0], the supplied text, and exits if non-zero. */ V pe(C *err,U SH quit){ /* simple enough handling on this option. */ IF(!noshowa) nsprint("%s: %s.\n",progname,err); IF(quit) nsexit(quit,0); R; } /* displays hex, dec, or regular with the from/to prompt option. */ /* 0 = output, 1 = input, 2 = other. */ V pd(U C *in,U SH io,U I size){ U I i=0; U I j=0; U I k=0; /* will be used for hex, or dec (or duplication of the original). */ U C *chrdump; U C *line; C prompt[4]; /* columns gets set before pd() is ever ran, in main(). */ IF(!(line=(C *)M(size+1))) pe("pd(): allocation of memory error",1); B(line,(size+1)); IF(displaytype){ /* size multiplied four times because every byte in the original */ /* buffer is going to be equal to four in the new buffer. */ IF(!(chrdump=(C *)M((SL(in)*4)+1))) pe("pd(): allocation of memory error",1); B(chrdump,((SL(in)*4)+1)); F(i=0;i "); EI(io&&!nosrecv) SP(prompt,"<- "); IF(!nowrap){ B(line,(size+1)); F(i=0;i=size));j++) line[SL(line)]=0x20; /* do not want a screwed up wordwrap, just slap a linefeed there instead. */ EI(chrdump[i]==0x0A) line[SL(line)]=0x0D; E line[SL(line)]=chrdump[i]; IF(SL(line)>=size){ #ifdef NCURSES nfocus=(io?nw1:nw2); #endif nsprint("%s\n",line); B(line,(size+1)); } } IF(SL(line)){ #ifdef NCURSES nfocus=(io?nw1:nw2); #endif nsprint("%s\n",line); } } /* for disabled wordwrap, which also includes th -L option. (-w option) */ EI(SL(chrdump)){ /* precurse with number of lines. */ IF(lnum){ #ifdef NCURSES nfocus=(io?nw1:nw2); #endif nsprint("(%.4d) ",(!io?(lnum_o++):(lnum_i++))); /* restart it to zero. */ IF(lnum_o>=10000) lnum_o=1; IF(lnum_i>=10000) lnum_i=1; } #ifdef NCURSES nfocus=(io?nw1:nw2); #endif nsprint("%s%s\n",!nofrom?prompt:"",chrdump); } FR(chrdump); FR(line); R; } /* writes data to the socket, and handles the ns_outgoing() module. also, */ /* handles the telnet dump for outgoing. (-y, and -Y options) */ V wro(C *output,U I size,U SH io){ U SH s=0; fd_set cfd; fd_set crfd; S timeval tv; /* check, and use the ns_outgoing() symbol, it passes the output to be */ /* wrote to the socket, the amount that will be wrote, the actual size of */ /* the data, and the socket value. (char *, int, int, int) */ #ifndef DISABLE_MODULES IF(vmodule&&SL(output)&&size&&!io) (*outgoing_function)(output,size,SL(output),sock); #endif IF(sock!=-1&&!io){ FD_ZERO(&cfd); FD_SET(sock,&cfd); /* handle outgoing telnet dumping. (-y, and -Y options) */ dumptelnet(output); /* no time needed. */ tv.tv_sec=0; tv.tv_usec=0; /* make sure the socket is really there. */ IF(SE((sock+1),0,&cfd,0,&tv)>0) WR(sock,output,size); IF(islog&&tnetraw) logdata(output,3); } IF(setroute){ /* to still check for activity with select(). */ IF(((norrecv&&io)||(norsend&&!io))&&io!=2) s=1; IF(rsock!=-1){ FD_ZERO(&crfd); FD_SET(rsock,&crfd); tv.tv_sec=0; tv.tv_usec=0; IF(SE((rsock+1),0,&crfd,0,&tv)>0){ IF(!s) WR(rsock,output,size); } /* silent. */ E{ SD(rsock,2); CL(rsock); rsock=-1; setroute=0; } } } R; } /* this function will write the supplied arguments to the system log. it */ /* has a similar usage to nsprint(). (-Z option) */ #ifndef DISABLE_SYSLOG V wrso(C *format,...){ SI I i=0; /* max size. */ U I j=(BASE_BUFFER*8); C *wlog; VAL ap; /* only do if enabled. (-Z option) */ IF(!slog) R; /* return if backgrounded or malloc() failed. */ IF(!(wlog=(C *)M(j))) R; W(1){ VAS(ap,format); i=VS(wlog,j,format,ap); VAE(ap); IF(i>-1&&i-1) j=(i+1); E j*=2; IF((wlog=realloc(wlog,j))==0){ /* size change failed. free anyways, and return. */ FR(wlog); R; } } R; } #endif /* function to set the permissions of netscript to run under. set after */ /* connected. but, set before taking any input, or sending any output. */ V setpermissions(C *string,U SH type){ S passwd *pent; S group *gent; /* read the string. */ IF(!type){ /* set them up default. in case no data is provided, it will just reset. */ ngid=GEG(); nuid=GEU(); /* if a "." exists. take the first token as uid, and then second as gid. */ IF(!parameter(string,1,0x2E)){ IF(!(gent=GR(parm))) ngid=AI(parm); E ngid=gent->gr_gid; parameter(string,0,0x2E); IF(!(pent=GP(parm))) nuid=AI(parm); E nuid=pent->pw_uid; } E{ IF(!(pent=GP(string))) nuid=AI(string); /* gid should be defaulted, already. */ E{ nuid=pent->pw_uid; ngid=pent->pw_gid; } /* apply the gid of the user, since no other gid was specified. */ } } /* do what setpermissions() said to when called earlier. */ E{ /* note the new id information. to potentially, clarify the discontinue */ /* of logging.*/ #ifndef DISABLE_SYSLOG wrso("%d-%d id: %lu-%u.%u.%u.%u new: %lu-%u.%u.%u.%u",slnum_t,(slnum_s++), cpid,GU(),GEU(),GG(),GEG(),cpid,nuid,nuid,ngid,ngid); #endif /* set the groups up, to follow. */ IF((pent=GPU(nuid))) initgroups(pent->pw_name,ngid); /* setre*id() is not on some systems. virtually the same thing. keeps */ /* the groups. also, no need for setfs*id(), sete*id() will do it. */ /* setfs*id() is not supported everywheres either. */ SGD(ngid); SEGD(ngid); SUD(nuid); SEUD(nuid); } R; } /* ruleset editor, uses a third party text editor on a file. */ V ruleedit(U SH type,C *path){ C *editor; C *tmpfile; PT fp; T tm; S stat mod; IF(isprivileged) pe("a third party editor can not be executed with privileged access",0); E{ IF(G(ENV_EDITOR)){ IF(!(editor=(C *)SDU((C *)G(ENV_EDITOR)))) pe("ruleedit(): duplication of memory error",1); } E{ IF(!(editor=(C *)SDU(DFL_EDITOR))) pe("ruleedit(): duplication of memory error",1); } IF(!type){ IF(!(tmpfile=(C *)M(5+10+5+10+1))) pe("ruleedit(): allocation of memory error",1); B(tmpfile,(5+10+5+10+1)); TM(&tm); SP(tmpfile,"/tmp/netscript.%.5lu%.10lu",(U L)cpid,(U L)tm); } E{ IF(!(tmpfile=(C *)SDU(path))) pe("ruleedit(): duplication of memory error",1); } SW(fp=FK()){ CS -1: pe("failed forking for the third party text editor",0); BR; CS 0: SG(SIGINT,SIG_DFL); EL(editor,editor,tmpfile,0); pe("failed execution of (ruleset) file editor",0); _exit(1); BR; default: /* wait till finished. */ WP(fp,0,0); BR; } IF(STT(tmpfile,&mod)) pe("could not access the temporary/ruleset file passed to the editor",1); EI(!setfile){ /* this should never happen. but, just incase. */ IF(mod.st_uid!=GEU()||mod.st_gid!=GEG()) pe("the temporary file has a different owner/group than the current proces" "s",1); EI(!setfile){ IF(!(rulesfile=(C *)SDU(tmpfile))) pe("ruleedit(): duplication of memory error",1); setfile=1; } } FR(editor); FR(tmpfile); } R; } /* this function does the logging. (-l option) */ /* 0 = output, 1 = input, 2 = other, else = raw. */ V logdata(C *data,U SH io){ /* will be used to hold the ctime data. */ C *timebuf; C prompt[3]; T tm; FL *fd; /* opens, and allows appending to the log file. */ IF(!(fd=FO(logfile,"a"))) pe("log file can not be created, or is not writable",1); E{ TM(&tm); IF(!(timebuf=(C *)SDU(CT(&tm)))) pe("logdata(): duplication of memory error",1); IF(timebuf[(SL(timebuf)-1)]==0x0A) timebuf[(SL(timebuf)-1)]=0x0; B(prompt,3); IF(!io) SP(prompt,"->"); EI(io==1) SP(prompt,"<-"); EI(io==2) SP(prompt,"!!"); IF(SL(data)){ /* raw data write. (-y, and -Y options) */ IF(!SL(prompt)) FP(fd,"%s",data); E /* regular data write. */ FP(fd,"%s: %s %s\n",timebuf,prompt,data); } FR(timebuf); FC(fd); } R; } /* the fixed dumping of information with the telnet option. has */ /* comparisons. (-y, and -Y in conjunction with -T option) */ V dumptelnet(C *dump){ U I i=0; U I j=0; U C *tmpdump; IF(!(tmpdump=(C *)M(SL(dump)+1))) pe("dumptelnet(): allocation of memory error",1); IF(tnetraw){ /* 1 = stderr, 2 = stdout(regular). */ IF(tnetraw==1){ /* do not show if backgrounded. */ IF(!isbga) FP(stderr,"%s",dump); } E{ /* mainly did it this way for debug purposes. */ B(tmpdump,(SL(dump)+1)); F(i=j=0;jsocket. */ /* if desired. */ IF(isiexec) D(sock,0); /* output. */ D(fd[1],1); D(fd[1],2); /* better than a raw execution. */ EL(eshell,eshell,"-c",path,0); /* make sure the handler is still defined, should be anyways. */ SG(SIGINT,sighandler); /* should never make it here. if it does, since its duplicated, it will */ /* send any output to the socket. so, looks better just to be silent. */ _exit(1); BR; default: /* ignore temporarily to send the signal only to the forked pid. */ SG(SIGINT,SIG_IGN); FD_ZERO(&ffd); FD_SET(fd[0],&ffd); W(!k){ /* defined amount of delay time, 3 seconds by default. (-x option) */ tv.tv_sec=(xalrm?xalrm:3); /* no need to be so precise. */ tv.tv_usec=0; IF((s=SE((fd[0]+1),&ffd,0,0,&tv))>0){ B(eread,(BASE_BUFFER*8+1)); IF(RD(fd[0],eread,(BASE_BUFFER*8))){ F(i=0;(s>0&&i=(BASE_BUFFER*8)){ /* count back for the missed byte. */ IF(j>=(BASE_BUFFER*8)) i--; ereadl[j]=0x0; IF(type&&!r){ /* free the pre-placed "null". */ FR(execformat); IF(!(execformat=(C *)SDU(ereadl))) pe("dumpexec(): duplication of memory error",1); /* let other positions know the buffer is set. */ r=1; /* can only use one line. so, (fool) exit after one exists. */ s=0; } E dumpexecline(ereadl); B(ereadl,(BASE_BUFFER*8+1)); /* reset counter. */ j=0; } E ereadl[j++]=eread[i]; } B(eread,(BASE_BUFFER*8+1)); } } /* if statement, and not else. because, of the fool exit possibility. */ IF(s<=0){ /* cap it off, for the next function. */ ereadl[j]=0x0; IF(type&&!r&&SL(ereadl)){ /* free the pre-placed "null". */ FR(execformat); IF(!(execformat=(C *)SDU(ereadl))) pe("dumpexec(): duplication of memory error",1); /* no need to set short r, to notify, it is never used again. */ } /* will dump any leftovers, as if there was a CR. */ E dumpexecline(ereadl); B(ereadl,(BASE_BUFFER*8+1)); /* force it, incase it timed out. */ K(fp,SIGKILL); /* wait up, do not want defunctness. */ WP(fp,0,0); /* bye bye. */ CL(fd[0]); CL(fd[1]); /* unignore ctrl-c aborts. */ SG(SIGINT,sighandler); k=1; } } BR; } } /* it would never make it to this point two times with variable usage. */ /* so, no need to support such an event. required information. */ IF(runexit&&!type) pe("completed execution dump, exiting netscript",1); EI(!noshowp&&!type) pe("completed execution dump, incoming data resumed",0); R; } /* to actually handle the line passed from dumpexec(). */ V dumpexecline(C *line){ U C *dump; IF(SL(line)){ IF(!(dump=(C *)M(SL(line)+(runpre?SL(execpre):0)+1))) pe("dumpexecline(): allocation of memory error",1); B(dump,(SL(line)+(runpre?SL(execpre):0)+1)); IF(runpre) SCA(dump,execpre); SCA(dump,line); /* last use of eread for this run. */ IF(!nossend) pd(dump,0,columns); wro(dump,SL(dump),0); wro("\n",1,0); /* add the output to the log, if enabled. (-l option) */ IF(islog&&!tnetraw) logdata(dump,0); /* last use of dump for this run. */ FR(dump); } R; } /* small function to close sockets. related to connecting, and binding. */ V closesocket(U SH type){ /* server connection/connected. (and routed along with it) */ IF(!type){ IF(sock>=0){ SD(sock,2); CL(sock); sock=-1; } IF(setroute&&rsock>=0){ SD(rsock,2); CL(rsock); rsock=-1; } } /* server bind socket. */ E{ IF(ssock>=0){ SD(ssock,2); CL(ssock); ssock=-1; } } R; } /* this function handles the user supplied socket option(s). */ V parsesocketopt(I type,I sockv){ U I i=0; I j=0; I soargs[2]; C *curopt; /* even if no options are set, set this automatically. (bind socket only) */ IF(type==1){ j=1; SSO(sockv,SOL_SOCKET,SO_REUSEADDR,(V *)&j,SO(j)); /* was not defined on one of the supported platforms, check to be safe. */ #ifdef SO_REUSEPORT SSO(sockv,SOL_SOCKET,SO_REUSEPORT,(V *)&j,SO(j)); #endif } IF(soptions){ parsedynamic(sopts); /* find out the size of the buffer needed. */ W(!parameter(parseddynamic,i++,0x3A)){ IF(!(curopt=(C *)SDU(parm))) pe("parsesocketopt(): duplication of memory error",1); parameter(curopt,0,0x2C); /* int->int comparison. */ IF(AI(curopt)==type){ B((V *)soargs,SO(soargs)); IF(!parameter(curopt,1,0x2C)){ soargs[0]=AI(parm); IF(!parameter(curopt,2,0x2C)){ soargs[1]=AI(parm); IF(SSO(sockv,SOL_SOCKET,soargs[0],(V *)&soargs[1],SO(soargs[1]))) pe("internal setting of socket option failed",0); } } } FR(curopt); } } R; } /* the socket connection, and line parser. takes the data from the remote */ /* host, and puts it in a per line format, then passes it along to the match */ /* function(s). also includes some specific variable handling. */ V parsesocket(C *host,U I port){ /* this is only used in this function. */ U SH stoprules=0; /* many loop ints used to help keep track of what is what. still re-used */ /* some i knew would never cross paths. */ U I i=0; U I j=0; U I k=0; U I l=0; U I m=0; U I n=0; U I o=0; U I p=0; U I q=0; U I r=0; U I s=0; /* for the $, truncation variable. */ SI I left=0; SI I right=0; /* socket (size) related. */ SI I salen=0; /* file dump read buffer. (variable $<) */ U C dread[(BASE_BUFFER*4+1)]; /* special read buffer for initial data. */ U C iread[(BASE_BUFFER*4+1)]; /* initial write buffer. */ U C iwrite[(BASE_BUFFER*4+1)]; /* read buffer for socket data. needs comparisons. */ U C sread[(BASE_BUFFER*4+1)]; /* buffer for data built up till a completed line, otherwise gets cleared. */ /* allowance of large lines. */ U C sreadl[(BASE_BUFFER*16+1)]; /* three byte response buffer, for telnet protocol responses. */ U C telnet[3]; /* single byte, multiple uses. no comparisons. */ C sb[1]; S hostent *he; /* connect to socket / bind client socket. */ S SAN ns; /* bind server socket. */ S SAN sns; /* route client socket. */ S SAN rns; /* for the $"(time passed) rule. */ T ctm; T rtm; FL *dfd; FL *ifd; /* reset the line values to one. (-L option) */ IF(lnum) lnum_i=lnum_o=1; IF(!noshowc) /* could have used tot_i, or tot_o for the second argument, i used tot_i. */ nsprint("[%lu@%s] * Session started with %d rule(s) defined.\n",cpid,nname, tot_i); /* handling for socket binding. */ IF(bindmode){ /* only happens on the first binding. (for forever mode) */ /* unless udp mode is active, then will rebind. */ IF(bindmode!=2||isudp){ /* main server sockaddr structure. */ if(isudp) sock=SK(AF_INET,SOCK_DGRAM,IPPROTO_UDP); else ssock=SK(AF_INET,SOCK_STREAM,IPPROTO_TCP); parsesocketopt(1,(isudp?sock:ssock)); B((V *)&sns,SO(sns)); sns.sin_family=AF_INET; sns.sin_port=HS(port); IF(isvhost){ /* resolve/set the host. */ IF((sns.sin_addr.s_addr=IA(vhost))){ IF(!(he=GH(vhost))){ IF(!noshowc) nsprint("[%lu@%s] * Could not resolve the provided virtual host, using " "any...\n",cpid,nname); sns.sin_addr.s_addr=HL(INADDR_ANY); } E MC((C *)&sns.sin_addr,(C *)he->h_addr,SO(sns.sin_addr)); } E sns.sin_addr.s_addr=HL(INADDR_ANY); } /* bind to the ip/port. (-b option) */ IF(BI((isudp?sock:ssock),(S SA *)&sns,SO(sns))<0){ IF(!noshowc) nsprint("[%lu@%s] * Bind failed: %s.\n",cpid,nname,strerror(errno)); /* yet again. better safe than sorry, do not want fds to fill up. */ closesocket(0); closesocket(1); R; } /* so it does not re-bind, again. */ bindmode=2; } IF(!noshowc) nsprint("[%lu@%s] * Awaiting incoming connection...\n",cpid,nname); /* one time connection(per listen), should not need more than one. */ IF(isudp){ i=SO(S SA); IF(RF(sock,sread,(BASE_BUFFER*4),MSG_PEEK,(S SA *)&sns,&i)<0){ nsprint("[%lu@%s] * Bind failed: recvfrom()\n",cpid,nname); /* close up shop. */ closesocket(0); closesocket(1); R; } IF(CO(sock,(S SA *)&sns,SO(sns))){ IF(!noshowc) nsprint("[%lu@%s] * Connection failed: %s.\n",cpid,nname,strerror(errno)); R; } } E{ IF(LI(ssock,blog)<0){ pe("could not listen on supplied port",0); R; } salen=SO(ns); IF((sock=AT(ssock,(S SA *)&ns,&salen))<0){ pe("could not accept remote connection",0); R; } parsesocketopt(0,sock); } /* close it, if its just one time. (bind) */ IF(!forever) closesocket(1); IF(isudp){ i=SO(ns); /* if fails, doesnt really matter. (hopefully) */ GPN(sock,(S SA *)&ns,&i); } IF(!noshowc){ nsprint("[%lu@%s] * Accepted connection from: %s:%d.\n",cpid,nname, /* since these ips do not really exist, other than in an error */ /* situation. blank out the confusion of an error. */ #ifndef DISABLE_SRCIP ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0")) ?NOSRCIP:IN(ns.sin_addr)) #else NOSRCIP #endif ,port); } } /* handling for socket connection. */ E{ sock=SK(AF_INET,(isudp?SOCK_DGRAM:SOCK_STREAM),(isudp?IPPROTO_UDP: IPPROTO_TCP)); parsesocketopt(0,sock); B((V *)&ns,SO(ns)); ns.sin_family=AF_INET; IF(isvhost){ /* resolve/set the host. */ IF((ns.sin_addr.s_addr=IA(vhost))){ IF(!(he=GH(vhost))){ IF(!noshowc) nsprint("[%lu@%s] * Could not resolve the provided virtual host, using a" "ny...\n",cpid,nname); ns.sin_addr.s_addr=HL(INADDR_ANY); } E MC((C *)&ns.sin_addr,(C *)he->h_addr,SO(ns.sin_addr)); } IF(BI(sock,(S SA *)&ns,SO(ns))<0){ /* clean up, and use any. */ pe("error binding name to socket, using any",0); B((V *)&ns,SO(ns)); ns.sin_family=AF_INET; ns.sin_addr.s_addr=HL(INADDR_ANY); IF(BI(sock,(S SA *)&ns,SO(ns))<0) pe("could not bind name properly",0); } } B((V *)&ns,SO(ns)); ns.sin_family=AF_INET; ns.sin_port=HS(port); IF(!noshowc) nsprint("[%lu@%s] * Checking the provided host...\n",cpid,nname); IF((ns.sin_addr.s_addr=IA(host))){ /* if not valid, attempts to resolve as a host. */ IF(!(he=GH(host))){ /* nothing left to try. */ IF(!noshowc) nsprint("[%lu@%s] * Could not resolve the provided host.\n",cpid,nname); R; } E /* successfully resolved. */ MC((C *)&ns.sin_addr,(C *)he->h_addr,SO(ns.sin_addr)); } IF(!noshowc) nsprint("[%lu@%s] * Attempting to connect to the provided host...\n",cpid, nname); /* if you can not connect to the server the first time might as well kill */ /* the program, same problem would continue infinitely. so, if it times */ /* out after ??(2 minutes by default) seconds it will just exit. */ IF(G(ENV_TIMEOUT)&&AI((C *)G(ENV_TIMEOUT))>0) A(AI((C *)G(ENV_TIMEOUT))); E A(DFL_TIMEOUT); /* like it looks, attempts to connect to the remote server. */ IF(CO(sock,(S SA *)&ns,SO(ns))){ A(0); IF(!noshowc) nsprint("[%lu@%s] * Connection failed: %s.\n",cpid,nname,strerror(errno)); R; } E{ A(0); IF(!noshowc) nsprint("[%lu@%s] * %s: %s:%d.\n",cpid,nname,(isudp?"Created connection": "Connected successfully"), /* since these ips do not really exist, other than in an error */ /* situation. blank out the confusion of an error. */ #ifndef DISABLE_SRCIP ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))? NOSRCIP:IN(ns.sin_addr)) #else NOSRCIP #endif ,port); } } /* only do the following if outside GTK+. (changing id levels would make */ /* for display problems) */ #ifdef GTK IF(!isgui){ #endif /* set the permissions before taking any input, or sending any output. */ /* only done once. since binding would have occured already. */ IF(setperms){ setpermissions(0,1); setperms=0; } #ifdef GTK } #endif #ifndef DISABLE_SYSLOG wrso("%d-%d id: %lu-%u.%u.%u.%u remote: %s-%u type: %s",slnum_t,(slnum_s++), cpid,GU(),GEU(),GG(),GEG(), #ifndef DISABLE_SRCIP ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))? NOSRCIP:IN(ns.sin_addr)) #else NOSRCIP #endif ,port,(bindmode?"incoming":"outgoing")); #endif IF(setroute){ rsock=SK(AF_INET,(isudpr?SOCK_DGRAM:SOCK_STREAM),(isudpr?IPPROTO_UDP: IPPROTO_TCP)); parsesocketopt(2,rsock); B((V *)&rns,SO(rns)); rns.sin_family=AF_INET; IF(isvhost){ IF((rns.sin_addr.s_addr=IA(vhost))){ IF(!(he=GH(vhost))){ IF(!noshowc) nsprint("[%lu@%s] * Could not resolve the provided virtual host, using a" "ny...\n",cpid,nname); rns.sin_addr.s_addr=HL(INADDR_ANY); } E MC((C *)&rns.sin_addr,(C *)he->h_addr,SO(rns.sin_addr)); } IF(BI(rsock,(S SA *)&rns,SO(rns))<0){ /* clean up, and use any. */ pe("error binding name to socket, using any",0); B((V *)&rns,SO(rns)); rns.sin_family=AF_INET; rns.sin_addr.s_addr=HL(INADDR_ANY); IF(BI(rsock,(S SA *)&rns,SO(rns))<0){ pe("could not bind name properly, proceeding anyways",0); rsock=-1; } } } IF(rsock!=-1){ B((V *)&rns,SO(rns)); rns.sin_family=AF_INET; rns.sin_port=HS(rport); IF(!noshowc) nsprint("[%lu@%s] * Checking the provided (route) host...\n",cpid,nname); IF((rns.sin_addr.s_addr=IA(rhost))){ /* if not valid, attempts to resolve as a host. */ IF(!(he=GH(rhost))){ /* nothing left to do. */ IF(!noshowc) nsprint("[%lu@%s] * Could not resolve the provided host, proceeding anyw" "ays...\n",cpid,nname); rsock=-1; } E /* successfully resolved. */ MC((C *)&rns.sin_addr,(C *)he->h_addr,SO(rns.sin_addr)); } IF(!noshowc&&rsock!=-1) nsprint("[%lu@%s] * Attempting to connect to the provided (route) host..." "\n",cpid,nname); IF(G(ENV_TIMEOUT)&&AI((C *)G(ENV_TIMEOUT))>0) A(AI((C *)G(ENV_TIMEOUT))); E A(DFL_TIMEOUT); IF(rsock==-1||CO(rsock,(S SA *)&rns,SO(rns))){ A(0); IF(rsock!=-1&&!noshowc) nsprint("[%lu@%s] * Route connection failed: %s. (proceeding)\n",cpid, nname,strerror(errno)); /* ensure the error is known. */ rsock=-1; } E{ A(0); IF(!noshowc) nsprint("[%lu@%s] * Connected (route) successfully: %s:%d.\n",cpid,nname, #ifndef DISABLE_SRCIP ((!SC(IN(rns.sin_addr),"255.255.255.255")||!SC(IN(rns.sin_addr),"0.0.0.0") )?NOSRCIP:IN(rns.sin_addr)) #else NOSRCIP #endif ,rport); } } } /* states log start time, and ip that was used. if enabled. (-l option) */ IF(islog&&!tnetraw){ logdata("NEW NETSCRIPT SESSION STARTED.",2); /* logging of the ip used. */ logdata( /* since these ips do not really exist, other than in an error situation. */ /* blank out the confusion of an error. */ #ifndef DISABLE_SRCIP ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))? NOSRCIP:IN(ns.sin_addr)) #else NOSRCIP #endif ,2); } /* check, and use the ns_connect() symbol, it passes the connection type, */ /* ip value, and port. (short, unsigned long int, int) */ #ifndef DISABLE_MODULES IF(vmodule) (*connect_function)(bindmode,ns.sin_addr,port); #endif /* for the $" rule, will set the time of the connection to be compared to. */ TM(&rtm); /* cleans out the dynamic (int)buffer for the "one time" variable. */ B((V *)rs_dynamic,SO(rs_dynamic)); /* this is for the "$." variable, it makes it not truely static. resets */ /* every connection if the value is two. (or back to one) */ F(i=0;i1) rs_static[i]-=2; } /* cleans out the dynamic (int)buffer for variable data. (usable) */ /* little more involved than a bzero() for the static vars set by the */ /* command line. */ F(i=0;i<10;i++){ IF(dynamicvarset[i]==1){ FR(dynamicvar[i]); dynamicvarset[i]=0; } } IF(initsend){ /* handle the unique initial input data. if it is a "?" it will prompt */ /* for input. make sure not to allow if backgrounded. */ IF(!SC(iswrite,"?")&&!isbga){ /* gui version of the request. */ #ifdef GTK IF(isgui){ IF(isguiwait) R; E{ nsprint("input request: enter dynamic initial data to send.\n"); /* only if non-generic. */ IF(!isbgui){ GTE(); /* make sure focus is on the entry box. */ GWGF(gen); /* show the entry box. */ GWS(gen); GTL(); } isguiwait=1; W(isguiwait) USLP(250000); } } /* typical version of the request. */ E{ #endif IF(!(ifd=FO(ttyn,"r"))) pe("could not open standard input for read",0); E{ /* none of this will work anyways if backgrounded. will close the fd. */ IF(!isbga){ IF(!noshowp) pe("initial send defined user input, incoming data suspended",0); /* show default, or reason prompt, if not in raw mode. */ IF(!tnetraw) nsprint("enter initial data to send: "); B(iread,(BASE_BUFFER*4+1)); /* truncated for pd(). */ IF(FS(iread,(SO(iread)-1),ifd)) F(o=0;o 0x%.2x 0x%.2x " "0x%.2x)\n",!nofrom?"-> ":"",sread[i],sread[i+1],sread[i+2],telnet[0], telnet[1],telnet[2]); } } /* telnet mode will not wait for a \r, or \n, must get one or more telnet */ /* option before automatically allowed. so, not to create problems with */ /* bad syntax. */ IF(sread[i]==0x0A||sread[i]==0x0D||(tnet&&truetnet&&!sread[i+1])){ /* check where to place the null byte, and make sure byte exists for the */ /* extended null byte. it will not add the last byte if its the last */ /* byte. */ IF(tnet&&truetnet&&!sread[i+1]&&(BASE_BUFFER*16+1)>(j+1)){ /* check, and use the ns_incoming_char() symbol, it passes the byte to */ /* be added to the buffer. (int) */ #ifndef DISABLE_MODULES IF(vmodule) (*incoming_char_function)(sread[i]); #endif /* append the byte that is usually a \r, or \n. but, for telent */ /* support a non-static character. */ sreadl[j]=sread[i]; sreadl[(j+1)]=0x0; } E sreadl[j]=0x0; /* handle the -S, and -U command line arguments for delaying. */ IF(sdelay) SLP(sdelay); IF(sudelay) USLP(sudelay); /* pass to the routed host, if enabled. (-R option) */ IF(setroute){ wro(sreadl,SL(sreadl),1); IF(SL(sreadl)) wro("\n",1,1); } /* check, and use the ns_incoming() symbol, it passes the incoming */ /* string of data, the size of that data, and the socket value. */ /* (char *, int, int) */ #ifndef DISABLE_MODULES IF(vmodule&&SL(sreadl)) (*incoming_function)(sreadl,SL(sreadl),sock); #endif IF(!nosrecv) pd(sreadl,1,columns); /* add the output to the log, if enabled. (-l option) */ IF(islog&&!tnetraw) logdata(sreadl,1); /* reset the temporary variable. */ IF(stoprules==2) stoprules=0; F(k=0;koutput, $1 $2 $3, makes swrite buf. */ /* rules will redo this for possible skipped arguments in this run. */ /* it will be done when the buffer gets chomped down using a rule. */ parseoutput(sreadl,output[k]); /* check, and handle the direct stop variable. */ IF(!SNCC(swrite,NS_STOP,SL(NS_STOP))){ /* changes buffer to dump the variable. for later display. */ truncateoutput(SL(NS_STOP)); /* update the new clean buffer. */ parseoutput(sreadl,swrite); /* no possibility of format bug, pe() handles like text. */ IF(!noshowp) pe(SL(swrite)?swrite:"ruleset defined ruleset stop",0); stoprules=1; } /* check, and handle the direct restart variable, even without stop. */ EI(!SNCC(swrite,NS_START,SL(NS_START))){ /* changes buffer to dump the variable. for later display. */ truncateoutput(SL(NS_START)); /* update the new clean buffer. */ parseoutput(sreadl,swrite); /* no possibility of format bug, pe() handles like text. */ IF(!noshowp) pe(SL(swrite)?swrite:"ruleset defined ruleset start",0); stoprules=0; } /* check, and handle for the direct halt variable. */ EI(!SNCC(swrite,NS_HALT,SL(NS_HALT))){ /* changes buffer to dump the variable. for later display. */ truncateoutput(SL(NS_HALT)); /* update the new clean buffer. */ parseoutput(sreadl,swrite); /* no possibility of format bug, pe() handles like text. */ IF(!noshowp) pe(SL(swrite)?swrite:"ruleset defined halt from continuing",0); stoprules=2; } /* check, and handle for the direct quit variable. */ EI(!SNCC(swrite,NS_QUIT,SL(NS_QUIT))){ /* changes buffer to dump the variable. for later display. */ truncateoutput(SL(NS_QUIT)); /* update the new clean buffer. */ parseoutput(sreadl,swrite); /* no possibility of format bug, pe() handles like text. */ IF(!noshowp) pe(SL(swrite)?swrite:"ruleset defined socket kill",0); closesocket(0); R; } /* check, and handle the direct ask variable. */ EI(!SNCC(swrite,NS_ASK,SL(NS_ASK))){ /* can not exactly do this if it is backgrounded. */ IF(isbga) R; /* changes buffer to dump the variable. for later display. */ truncateoutput(SL(NS_ASK)); /* update the new clean buffer. */ parseoutput(sreadl,swrite); /* gui version of the request. */ #ifdef GTK IF(isgui){ IF(isguiwait) R; E{ nsprint("input request: %s.\n",SL(swrite)?swrite:"enter response"); /* only if non-generic. */ IF(!isbgui){ GTE(); /* make sure focus is on the entry box. */ GWGF(gen); /* show the entry box. */ GWS(gen); GTL(); } isguiwait=1; W(isguiwait) USLP(250000); } } /* typical version of the request. */ E{ #endif IF(!(ifd=FO(ttyn,"r"))) pe("could not open standard input for read",0); E{ IF(!noshowp) pe("ruleset defined user input, incoming data suspended",0); /* show default, or reason prompt, if not in raw mode. */ IF(!tnetraw) nsprint("%s: ",SL(swrite)?swrite:"enter response"); B(iwrite,(BASE_BUFFER*4+1)); #ifdef NCURSES IF(isncurses) wgetnstr(nw3,iwrite,(SO(iwrite)-1)); E #endif IF(FS(iwrite,(SO(iwrite)-1),ifd)) F(o=0;o1) F(l=0;l0) /* using the int again here. */ F(l=0;l0){ /* using the int(s) again here. */ F(m=l=0;lSL(sreadl)) right=SL(sreadl); F(r=q=0;q=left&&q(SL(parm)+1)){ truncateoutput(SL(parm)+1); IF(!nossend) pd(swrite,0,columns); wro(swrite,SL(swrite),0); wro("\n",1,0); } } } /* check, and handle the execution dump/formatting variables. */ EI(!SNCC(swrite,NS_EXEC,SL(NS_EXEC))||!SNCC(swrite,NS_EXECF,SL(NS_EXECF)) ){ /* will reuse this int again, and again. */ p=(!SNCC(swrite,NS_EXEC,SL(NS_EXEC))?0:1); /* changes buffer to dump the variable. for later display. */ truncateoutput(p?SL(NS_EXECF):SL(NS_EXEC)); /* update the new clean buffer. */ parseoutput(sreadl,swrite); IF(!noshowp&&!p) pe("ruleset requested a local program execution",0); /* privileged checking occurs with this function, since its used */ /* elsewhere. */ dumpexec(swrite,p); IF(p&&SL(execformat)){ /* byte-by-byte transfer/check. (reused int p) */ F(p=0;((p<(SO(sreadl)-1))&&(p<(SL(execformat))));p++) sreadl[p]=execformat[p]; sreadl[p]=0x0; } } /* not required to check every slot for a byte. but, i do. */ EI(swrite[0]&&swrite[1]&&swrite[2]&&swrite[3]&&swrite[4]&&swrite[0]== PARAMETER_VAR_CHAR&&swrite[1]==0x7B&&ID((U I)swrite[2])&&swrite[3]==0x7D &&swrite[4]==0x3D){ /* store the number before chomping it down. */ s=(swrite[2]-0x30); /* do not overwrite the statically set variables. */ IF(dynamicvarset[s]!=2){ /* changes buffer to dump the variable. for later display. */ truncateoutput(5); /* update the new clean buffer. */ parseoutput(sreadl,swrite); IF(dynamicvarset[s]==1) FR(dynamicvar[s]); IF(!(dynamicvar[s]=(C *)SDU(swrite))) pe("parsesocket(): duplication of memory error",1); dynamicvarset[s]=1; } } E{ IF(!nossend) pd(swrite,0,columns); wro(swrite,SL(swrite),0); wro("\n",1,0); /* add the input to the log, if enabled. (-l option) */ IF(islog&&!tnetraw) logdata(swrite,0); } } } B(sreadl,(BASE_BUFFER*16+1)); j=0; } E /* do not print the telnet options, no one wants to see that. */ IF(tnet&&truetnet&&sread[i]==0xFF&&(sread[i+1]==0xFE||sread[i+1]==0xFD|| sread[i+1]==0xFC||sread[i+1]==0xFB)) i+=2; /* for reading of printable characters only. meaning non-printable */ /* characters will not make it to ruleset processing. but, the telnet */ /* protocol handling is processed before this point. so, it will not be */ /* effected. (-P option). also, omits defined characters from them -o */ /* option. */ EI((!printonly||IP((U I)sread[i]))&&(!omitchars||!STC(ochars,sread[i]))){ /* check the buffer that is filling until a completed line, making sure */ /* not to exceed bounds. if it does the buffer is cleared. */ IF(j>=SO(sreadl)){ B(sreadl,(BASE_BUFFER*16+1)); j=0; } /* write the byte if nothing before this option wanted to stop it. */ E{ /* check, and use the ns_incoming_char() symbol, it passes the byte to */ /* be added to the buffer. (int) */ #ifndef DISABLE_MODULES IF(vmodule) (*incoming_char_function)(sread[i]); #endif sreadl[j++]=sread[i]; } } } } /* once more. better safe than sorry, do not want fds to fill up. */ closesocket(0); R; } /* for display types of version information. */ V showinfo(U SH type){ C *timebuf; T tm; IF(type==1){ /* left without uname (verbose display) information. */ nsprint("[%lu] * Version: netscript/v%s!%s. -- License: %s.\n" "[%lu] * Id data: %s\n" "[%lu] * Mod: %s -- Src: %s -- Arp: %s -- Gui: %s -- Slg: %s -- Ncr: %s.\n" "[%lu] * Author: %s.%s\n",cpid,VERSION,COMPTYPE,license,cpid,id,cpid, (defined[0]?"on":"off"),(defined[1]?"on":"off"),(defined[2]?"on":"off"), (defined[3]?"on":"off"),(defined[4]?"on":"off"),(defined[5]?"on":"off"), cpid,author,isprivileged?" (privileged)":""); } EI(type==2){ TM(&tm); IF(!(timebuf=(C *)SDU(CT(&tm)))) pe("showinfo(): duplication of memory error",1); IF(timebuf[(SL(timebuf)-1)]==0x0A) timebuf[(SL(timebuf)-1)]=0x0; nsprint("[ netscript: (version: v%s!%s - launchtime: %s) ]\n",VERSION, COMPTYPE,timebuf); FR(timebuf); } R; } /* this function will handle the prompted version of netscript. */ V iface(C *base){ U SH r=0; U SH s=0; U I i=0; U I j=0; U I k=0; C **tmpname; C *tmptime; U C icwd[(BASE_BUFFER*4+1)]; U C iread[(BASE_BUFFER*4+1)]; FL *ifd; PT fp; T tm; S group *gent; S passwd *pent; /* no user aborts in this mode, will reset at the end of the function. */ SG(SIGINT,SIG_IGN); /* no reading of (non-ruleset) files when privileged. this is silent. */ IF(!isprivileged){ IF(!(ifd=FO(rcfile,"r"))) s=0; E s=1; } W(!r){ IF(!s) nsprint("%s",base); IF(!s&&!(ifd=FO(ttyn,"r"))) pe("could not open standard input for read",1); E{ B(iread,(BASE_BUFFER*4+1)); IF(FS(iread,(SO(iread)-1),ifd)){ F(i=0;i1) displaytype=0; nsprint("disptype: %s\n",(!displaytype?"disabled":(displaytype==1?"hex": "dec"))); } EI(!SNCC(iread,"execexit",8)){ runexit=(runexit?0:1); nsprint("execexit: %sabled\n",(runexit?"en":"dis")); } EI(!SNCC(iread,"execfile",8)){ IF(isprivileged) nsprint("execfile: can not log data to a file with privileged access.\n"); E{ IF(!parameter(iread,1,0x20)){ IF(runcmd) FR(execfile); parsecmdline(parm); IF(!(execfile=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); runcmd=1; } nsprint("execfile: %s\n",(runcmd?execfile:IFACE_UNSET)); } } EI(!SNCC(iread,"execinteractive",15)){ isiexec=(isiexec?0:1); nsprint("execinteractive: %sabled\n",(isiexec?"en":"dis")); } EI(!SNCC(iread,"execpre",7)){ IF(!parameter(iread,1,0x20)){ IF(runpre) FR(execpre); parsecmdline(parm); IF(!(execpre=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); runpre=1; } nsprint("execpre: %s\n",(runpre?execpre:IFACE_UNSET)); } EI(!SNCC(iread,"execshell",9)){ IF(!parameter(iread,1,0x20)){ parsecmdline(parm); IF(AC(parsedline,X_OK)) nsprint("execshell: argument1 is not a valid file, or is not executable." "\n"); E{ IF(setshell) FR(eshell); IF(!(eshell=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); setshell=1; } } nsprint("execshell: %s\n",(setshell?eshell:IFACE_UNSET)); } EI(!SNCC(iread,"execwait",8)){ IF(!parameter(iread,1,0x20)){ IF(AI(parm)<0) nsprint("execwait: argument1 must be a positive integer, can not define." "\n"); E xalrm=AI(parm); } nsprint("execwait: %d\n",xalrm); } EI(!SNCC(iread,"forever",7)){ forever=(forever?0:1); nsprint("forever: %sabled\n",(forever?"en":"dis")); } #ifdef GTK EI(!SNCC(iread,"guicolor",8)){ IF(!parameter(iread,1,0x20)){ parsecmdline(parm); IF(SL(parsedline)==6){ B((V *)guic,SO(guic)); F(isguic=i=0;i<6;i+=2){ IF(IL((U I)parsedline[i])) j=(TL(parsedline[i])-0x56); E j=(parsedline[i]-0x2F); j*=16; IF(IL((U I)parsedline[i+1])) j+=(TL(parsedline[i+1])-0x56); E j+=(parsedline[i+1]-0x2F); j-=17; IF(j>=0&&j<256) guic[isguic]=(j*257); isguic++; } } } nsprint("guicolor: %.2x%.2x%.2x\n",(guic[0]/257),(guic[1]/257),(guic[2]/257) ); } EI(!SNCC(iread,"guilabel",8)){ IF(!parameter(iread,1,0x20)){ IF(isguil){ F(k=0;k1? " <...>":"")); } EI(!SNCC(iread,"guipdlen",8)){ IF(!parameter(iread,1,0x20)){ IF(AI(parm)<0) nsprint("guipdlen: argument1 must be a positive integer, can not define." "\n"); E guio=(AI(parm)>GUI_MAXLEN?GUI_MAXLEN:AI(parm)); } nsprint("guipdlen: %d\n",guio); } EI(!SNCC(iread,"guipd",5)){ isguis=(isguis?0:1); nsprint("guipd: %sabled\n",(isguis?"en":"dis")); } EI(!SNCC(iread,"guititle",8)){ IF(!parameter(iread,1,0x20)){ IF(isguititle) FR(guititle); parsecmdline(parm); IF(!(guititle=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); isguititle=1; } nsprint("guititle: %s\n",(isguititle?guititle:IFACE_UNSET)); } EI(!SNCC(iread,"gui",3)){ IF(isprivileged) nsprint("gui: the gui frontend can not be used when netscript is privilege" "d.\n"); E{ IF(isgui){ IF(isbgui) isbgui=isgui=0; E isbgui=1; } E isgui=1; nsprint("gui: %s\n",(!isgui?"disabled":(isbgui==1?"generic":"normal"))); } } #endif EI(!SNCC(iread,"host",4)){ IF(bindmode) nsprint("host: bind mode is already defined, can not define.\n"); E{ IF(!parameter(iread,1,0x20)){ IF(sethost){ F(k=0;k=MAX_ARGS) pe("too many slots to store in memory",1); } sethost=1; } nsprint("host: %s%s\n",(sethost?shost[0]:IFACE_UNSET),(tshs>1?" <...>": "")); } } EI(!SNCC(iread,"initial",7)){ IF(!parameter(iread,1,0x20)){ IF(initsend) FR(iswrite); parsecmdline(parm); IF(!(iswrite=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); initsend=1; } nsprint("initial: %s\n",(initsend?iswrite:IFACE_UNSET)); } EI(!SNCC(iread,"logfile",7)){ IF(isprivileged) nsprint("logfile: can not log data to a file with privileged access.\n"); E{ IF(!parameter(iread,1,0x20)){ IF(islog) FR(logfile); parsecmdline(parm); IF(!(logfile=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); islog=1; } nsprint("logfile: %s\n",(islog?logfile:IFACE_UNSET)); } } #ifdef NCURSES EI(!SNCC(iread,"ncurseslabel",12)){ IF(!parameter(iread,1,0x20)){ IF(isncursesl){ F(k=0;k1?" <...>":"")); } EI(!SNCC(iread,"ncurses",7)){ isncursesa=(isncursesa?0:1); nsprint("ncurses: %sabled\n",(isncursesa?"en":"dis")); } #endif EI(!SNCC(iread,"nonprintables",13)){ printonly=(printonly?0:1); nsprint("nonprintables: %sabled\n",(printonly?"en":"dis")); } EI(!SNCC(iread,"notelnetshowopt",15)){ notnetopt=(notnetopt?0:1); nsprint("notelnetshowopt: %sabled\n",(notnetopt?"en":"dis")); } EI(!SNCC(iread,"nowordwrap",10)){ nowrap=(nowrap?0:1); nsprint("nowordwrap: %sabled\n",(nowrap?"en":"dis")); } EI(!SNCC(iread,"omit",4)){ IF(!parameter(iread,1,0x20)){ IF(omitchars) FR(ochars); parsecmdline(parm); IF(!(ochars=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); omitchars=1; } nsprint("omit: %s\n",(omitchars?ochars:IFACE_UNSET)); } EI(!SNCC(iread,"perm",4)){ IF(!parameter(iread,1,0x20)){ IF(!setperms){ parsecmdline(parm); setpermissions(parsedline,0); setperms=1; } E nsprint("perm: permissions are already defined, can not re-define.\n"); } nsprint("perm: %u.%u <%s>\n",nuid,ngid,(setperms?"set":"unset")); } EI(!SNCC(iread,"pnotify",7)){ noshowp=(noshowp?0:1); nsprint("pnotify: %sabled\n",(noshowp?"en":"dis")); } EI(!SNCC(iread,"port",4)){ IF(!parameter(iread,1,0x20)) sport=portentry(parm); nsprint("port: %d\n",sport); } EI(!SNCC(iread,"routehost",9)){ IF(!parameter(iread,1,0x20)){ IF(setroute) FR(rhost); parsecmdline(parm); IF(!(rhost=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); setroute=1; } nsprint("routehost: %s\n",(setroute?rhost:IFACE_UNSET)); } EI(!SNCC(iread,"routenoincoming",15)){ norrecv=(norrecv?0:1); nsprint("routenoincoming: %sabled\n",(norrecv?"en":"dis")); } EI(!SNCC(iread,"routenooutgoing",15)){ norsend=(norsend?0:1); nsprint("routenooutgoing: %sabled\n",(norsend?"en":"dis")); } EI(!SNCC(iread,"routeport",9)){ IF(!parameter(iread,1,0x20)){ IF(AI(parm)<0) nsprint("routeport: argument1 must be a positive integer, can not define." "\n"); E rport=AI(parm); } nsprint("routeport: %d\n",rport); } EI(!SNCC(iread,"routeudp",8)){ isudpr=(isudpr?0:1); nsprint("routeudp: %sabled\n",(isudpr?"en":"dis")); } EI(!SNCC(iread,"rulesetedit",11)){ editrules=(editrules?0:1); nsprint("rulesetedit: %sabled\n",(editrules?"en":"dis")); } EI(!SNCC(iread,"rulesetinput",12)){ IF(setfile) nsprint("rulesetinput: there is a ruleset file defined to use, can not def" "ine.\n"); E{ inputrules=(inputrules?0:1); nsprint("rulesetinput: %sabled\n",(inputrules?"en":"dis")); } } EI(!SNCC(iread,"ruleset",7)){ IF(inputrules) nsprint("ruleset: ruleset input is already defined, can not define.\n"); E{ IF(!parameter(iread,1,0x20)){ IF(setfile) FR(rulesfile); parsecmdline(parm); IF(!(rulesfile=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); setfile=1; } nsprint("ruleset: %s\n",(setfile?rulesfile:IFACE_UNSET)); } } EI(!SNCC(iread,"sdelay",5)){ IF(!parameter(iread,1,0x20)){ IF(AI(parm)<0) nsprint("sdelay: argument1 must be a positive integer, can not define." "\n"); E sdelay=AI(parm); } nsprint("sdelay: %d\n",sdelay); } EI(!SNCC(iread,"showlines",10)){ lnum=(lnum?0:1); IF(lnum) lnum=lnum_i=lnum_o=nowrap=1; nsprint("showlines: %sabled\n",(lnum?"en":"dis")); } EI(!SNCC(iread,"showversion",11)){ showv=(showv?0:2); nsprint("showversion: %sabled\n",(showv?"en":"dis")); } EI(!SNCC(iread,"socketopts",10)){ IF(!parameter(iread,1,0x20)){ IF(soptions) FR(sopts); parsecmdline(parm); IF(!(sopts=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); soptions=1; } nsprint("socketopts: %s\n",(soptions?sopts:IFACE_UNSET)); } #ifndef DISABLE_SYSLOG EI(!SNCC(iread,"syslog",6)){ slog=(slog?0:1); nsprint("syslog: %sabled\n",(slog?"en":"dis")); } #endif EI(!SNCC(iread,"telnettype",10)){ IF(tnetraw++>1) tnetraw=0; nsprint("telnettype: %s\n",(!tnetraw?"disabled":(tnetraw==1?"stderr": "stdout"))); } EI(!SNCC(iread,"telnet",6)){ tnet=(tnet?0:1); nsprint("telnet: %sabled\n",(tnet?"en":"dis")); } EI(!SNCC(iread,"timedexit",9)){ IF(!parameter(iread,1,0x20)){ IF(AI(parm)<0) nsprint("timedexit: argument1 must be a positive integer, can not define." "\n"); E alrm=AI(parm); } nsprint("timedexit: %d\n",alrm); } EI(!SNCC(iread,"udpmode",7)){ isudp=(isudp?0:1); nsprint("udpmode: %sabled\n",(isudp?"en":"dis")); } EI(!SNCC(iread,"udelay",5)){ IF(!parameter(iread,1,0x20)){ IF(AI(parm)<0) nsprint("udelay: argument1 must be a positive integer, can not define." "\n"); E sudelay=AI(parm); } nsprint("udelay: %d\n",sudelay); } EI(!SNCC(iread,"var",3)){ IF(!parameter(iread,1,0x20)){ IF(ID((U I)parm[0])){ j=(parm[0]-0x30); IF(dynamicvarset[j]!=2) FR(dynamicvar[j]); IF(!parameter(iread,2,0x20)){ parsecmdline(parm); IF(!(dynamicvar[j]=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); dynamicvarset[j]=2; } nsprint("var(%d): %s\n",j,(dynamicvarset[j]==2?dynamicvar[j]: IFACE_UNSET)); } E nsprint("var(*): parameter1 is not a value between 0 and 9.\n"); } E nsprint("var(syntax): var <0-9> \n"); } EI(!SNCC(iread,"vhost",5)){ IF(!parameter(iread,1,0x20)){ IF(isvhost) FR(vhost); parsecmdline(parm); IF(!(vhost=(C *)SDU(parsedline))) pe("iface(): duplication of memory error",1); isvhost=1; } nsprint("vhost: %s\n",(isvhost?vhost:IFACE_UNSET)); } EI(!SNCC(iread,"exit",4)||!SNCC(iread,"quit",4)) nsexit(0,0); EI(!SNCC(iread,"run",3)||!SNCC(iread,"launch",6)) r=1; EI(!SNCC(iread,"&cwd",4)){ IF(!parameter(iread,1,0x20)){ parsecmdline(parm); CD(parm); } B(icwd,(BASE_BUFFER*4+1)); GWD(icwd,(BASE_BUFFER*4+1)); nsprint("&cwd: %s\n",icwd); } EI(!SNCC(iread,"&id",3)){ IF(!(tmpname=(C **)M(5*(SO(C *))))) pe("iface(): allocation of memory error",1); B((V *)tmpname,SO(tmpname)); IF((pent=GPU(GU()))&&SL(pent->pw_name)){ IF(!(tmpname[0]=(C *)SDU(pent->pw_name))) pe("iface(): duplication of memory error",1); } E{ IF(!(tmpname[0]=(C *)SDU("unknown"))) pe("iface(): duplication of memory error",1); } IF((pent=GPU(GEU()))&&SL(pent->pw_name)){ IF(!(tmpname[1]=(C *)SDU(pent->pw_name))) pe("iface(): duplication of memory error",1); } E{ IF(!(tmpname[1]=(C *)SDU("unknown"))) pe("iface(): duplication of memory error",1); } IF((gent=GGG(GG()))&&SL(gent->gr_name)){ IF(!(tmpname[2]=(C *)SDU(gent->gr_name))) pe("iface(): duplication of memory error",1); } E{ IF(!(tmpname[2]=(C *)SDU("unknown"))) pe("iface(): duplication of memory error",1); } IF((gent=GGG(GEG()))&&SL(gent->gr_name)){ IF(!(tmpname[3]=(C *)SDU(gent->gr_name))) pe("iface(): duplication of memory error",1); } E{ IF(!(tmpname[3]=(C *)SDU("unknown"))) pe("iface(): duplication of memory error",1); } nsprint("&id: uid=%u(%s) euid=%u(%s) gid=%u(%s) egid=%u(%s)\n",GU(), tmpname[0],GEU(),tmpname[1],GG(),tmpname[2],GEG(),tmpname[3]); FR(tmpname); } EI(!SNCC(iread,"&pid",4)) nsprint("&pid: %lu (parent=%lu)\n",cpid,GPPD()); EI(!SNCC(iread,"&time",6)){ TM(&tm); IF(!(tmptime=(C *)SDU(CT(&tm)))) pe("iface(): duplication of memory error",1); IF(tmptime[(SL(tmptime)-1)]==0x0A) tmptime[(SL(tmptime)-1)]=0x0; nsprint("&time: %s (value=%d)\n",tmptime,tm); FR(tmptime); } EI(SL(iread)&&iread[0]==0x21){ IF(isprivileged) nsprint("!: can not execute third party programs with privileged access." "\n"); E{ F(i=1;i\t- changes the working directory of netscript.\n" "chroot\t\t\t- changes the root directory of netscript.\n" "cnotify\t\t\t\t- disables display of connection notifications.\n" "disparrows\t\t\t- disables display of arrow precursors.\n" "dispincoming\t\t\t- disables display of incoming data.\n" "dispoutgoing\t\t\t- disables display of outgoing data.\n" "disptype\t\t\t- displays hex/dec values.\n" "execexit\t\t\t- kills netscript after the first dump.\n" "execfile\t\t\t- dumps the program data to the socket.\n" "execinteractive\t\t\t- will allow interactive use of programs.\n" "execpre\t\t\t\t- precurse data to attach for each line dumped.\n" "execshell\t\t\t- will use an alternate shell for executions.\n" "execwait\t\t- kills the program if the program dump hangs.\n" "forever\t\t\t\t- when disconnected. reconnect, or rebind.\n" #ifdef GTK "gui\t\t\t\t- enables the gui frontend. (to normal/generic)\n" "guicolor\t\t- sets a text foreground color for the gui.\n" "guilabel\t\t- defines button labels for the gui.\n" "guipd\t\t\t\t- automatically start pulled down. (non-generic)\n" "guipdlen\t\t\t- increase the length of the gui. (non-generic)\n" "guititle\t\t\t- displays as the title for the gui.\n" #endif "host\t\t<host,host,...>\t- remote host (or ip) to connect to.\n" "initial\t\t<data>\t\t- send initial data once connected. (\"?\"=dyn)\n" "logfile\t\t<file>\t\t- turns input/output logging on.\n" #ifdef NCURSES "ncurses\t\t\t\t- switch console to ncurses visualization.\n" "ncurseslabel\t<l1:l2>\t\t- defines tab labels for the ncurses.\n" #endif "nonprintables\t\t\t- disables reading of non-printable characters.\n" "notelnetshowopt\t\t\t- disables display of verbose telnetd-opts.\n" "nowordwrap\t\t\t- disables wordwrap for in/out displaying.\n" "omit\t\t<charlist>\t- will omit socket reading of the charlist.\n" "perm\t\t<user[.group]>\t- changes netscript id permissions.\n" "pnotify\t\t\t\t- disables display of unimportant ruleset info.\n" "port\t\t<port>\t\t- remote port to connect to, or bind to.\n" "routehost\t<host>\t\t- will set a host, to route socket data to.\n" "routenoincoming\t\t\t- disable routed sending of incoming data.\n" "routenooutgoing\t\t\t- disable routed sending of outgoing data.\n" "routeport\t<port>\t\t- will set a port to connect on the route host.\n" "routeudp\t\t\t- switches the route host to the UDP protocol.\n" "ruleset\t\t<file>\t\t- input/output (ruleset) file.\n" "rulesetedit\t\t\t- edit the temporary/ruleset with an editor.\n" "rulesetinput\t\t\t- input/output ruleset, via input.\n" "sdelay\t\t<second(s)>\t- delay before processing incoming data. \n" "showlines\t\t\t- displays the value of each line.\n" "showversion\t\t\t- displays the version info of netscript.\n" "socketopts\t<#,#,#:...>\t- sets socket option(s) inside netscript.\n" #ifndef DISABLE_SYSLOG "syslog\t\t\t\t- enables system logging.\n" #endif "telnet\t\t\t\t- attempt to interpret the telnet protocol.\n" "telnettype\t\t\t- dump raw socket data. (to stderr/stdout)\n" "timedexit\t<second(s)>\t- closes the connection after alloted time.\n" "udpmode\t\t\t\t- switches netscript to the UDP protocol.\n" "udelay\t\t<usecond(s)>\t- delay before processing incoming data.\n" "var\t\t<0-9> <data>\t- will statically define the dynamic variable.\n" "vhost\t\t<host>\t\t- will define a virtual host to use, or bind to.\n" "&cwd AND &id AND &pid AND &time\t- local (only) interactive display comman" "ds.\n" "![command]\t\t\t- shell out of interactive netscript.\n" "run AND launch\t\t\t- execute the provided information.\n" "exit AND quit\t\t\t- exit netscript.\n" "help\t\t\t\t- this screen, displays interactive commands.\n"); } EI(SL(iread)&&iread[0]!=0x23) nsprint("unknown command: %s (try \'help\' for a command list)\n",iread); } SG(SIGINT,sighandler); R; } /* display of variable uses, the -d argument. finally went for \t's */ V displayv(V){ nsprint("Defined ruleset match, and replacement variables used by netscript:" "\n" "IN/OUT\tTYPE\t\tDOES/ACTION\t\t\t\tVARIABLE\n" "I/O\treplace\t\twill replace with the in/out used above\t\"%s\"\n" "O\tpre-data\tstops use of the ruleset\t\t\"%s\"\n" "O\tpre-data\trestarts use of the ruleset\t\t\"%s\"\n" "O\tpre-data\tstops the ruleset reading cycle\t\t\"%s\"\n" "O\tpre-data\tcloses the socket\t\t\t\"%s\"\n" "O\tpre-data\tasks for input response to send\t\t\"%s\"\n" "O\tpre-data\ttruncates characters from server data\t\"%s\"\n" "O\tpre-data\ttruncates tokens from server data (l)\t\"%s\"\n" "O\tpre-data\ttruncates tokens from server data (r)\t\"%s\"\n" "O\tpre-data\ttruncates strings from server data\t\"%s\"\n" "O\tpre-data\tformats the received input data\t\t\"%s\"\n" "O\tpre-data\tdisplays the supplied data\t\t\"%s\"\n" "O\tpre-data\twrites the supplied data without a CR\t\"%s\"\n" "O\tpre-data\tuses rule only one time (requires data)\t\"%s\"\n" "O\tpre-data\tdisables a rule from the ruleset\t\"%s\"\n" "O\tpre-data\tdumps the file used after variable\t\"%s\"\n" "O\tpre-data\twrites to the file used after variable\t\"%s\"\n" "O\tpre-data\tappends to the file used after variable\t\"%s\"\n" "O\tpre-data\tchange to the dir used after variable\t\"%s\"\n" "O\tpre-data\tsends supplied data to the route host\t\"%s\"\n" "O\tpre-data\tonly sends data if time has passed\t\"%s\"\n" "O\tpre-data\texecutes the file used after variable\t\"%s\"\n" "O\tpre-data\texecutes the file to be used in rules\t\"%s\"\n" "I\tpre-data\tcheck for a reverse/negative match\t\"%s\"\n" "I\twildcard\tanything after point\t\t\t\"%s\"\n" "I\twildcard\tanything that is a value\t\t\"%s\"\n" "I\twildcard\tanything that is alphabetical\t\t\"%s\"\n" "I\twildcard\tanything that is numerical\t\t\"%s\"\n" "I\twildcard\tanything that is alphabetical|numerical\t\"%s\"\n" "I\twildcard\tanything that is upper case\t\t\"%s\"\n" "I\twildcard\tanything that is lower case\t\t\"%s\"\n" "I\twildcard\tanything that is punctuated\t\t\"%s\"\n" "I\twildcard\tanything that is a control word\t\t\"%s\"\n" "I\twildcard\tanything that is a printable word\t\"%s\"\n" "I\twildcard\t<\"%c####\" anything that is equal to length, #=num>\n" "O\tend-data\t<\"%c#####\" delay in secs before processing rule, #=num>\n" "O\treplace\t\t<\"%c#\" will replace with the argument from input, #=num>\n" "I/O\treplace\t\t<\"%c{#}\" will replace with stored dynamic data, #=num>\n" "I/O\treplace\t\t<\"%c##\" will replace with hex->chr value, ##=01-FF>\n" "I/O\treplace\t\t<\"%c###\" will replace with dec->chr value, ###=001-255>\n" "I/O\treplace\t\t<\"%c&\" will replace with a random letter>\n" "I/O\treplace\t\t<\"%c#\" will replace with a random number, #=#>\n" "\nDefined environmental variables used by netscript:\n" "DOES/ACTION\t\t\t\t\t\t\tVARIABLE\n" "treated as a command line\t\t\t\t\t\"$%s\"\n" "treated as a connection timeout time\t\t\t\t\"$%s\"\n" #ifndef DISABLE_MODULES "treated as a file to use for module support\t\t\t\"$%s\"\n" #endif "treated as a virtual host to use\t\t\t\t\"$%s\"\n" "treated as a backlog used for binding\t\t\t\t\"$%s\"\n" "treated as a maximum limit of text per line\t\t\t\"$%s\"\n" "treated as a shell to execute third party programs\t\t\"$%s\"\n" "treated as a text editor to make/edit (temporary) rulesets\t\"$%s\"\n\n" "Note: variables surrounded by <>'s are static, and unchangeable variables.\n" " consult documentation for more definitions on variables.\n",NS_REPEAT, NS_STOP,NS_START,NS_HALT,NS_QUIT,NS_ASK,NS_TRUNC,NS_TOKENL,NS_TOKENR,NS_STR, NS_FMT,NS_ECHO,NS_RAW,NS_ONCE,NS_DISABLE,NS_DUMP,NS_WRITE,NS_APPEND,NS_CHDIR, NS_ROUTE,NS_TIMED,NS_EXEC,NS_EXECF,NS_NMATCH,NS_ALL,NS_ANY,NS_ALPHA,NS_DIGIT, NS_ALNUM,NS_UPPER,NS_LOWER,NS_PUNCT,NS_CNTRL,NS_PRINT,PARAMETER_VAR_CHAR, PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR, PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,ENV_CMDLINE, ENV_TIMEOUT, #ifndef DISABLE_MODULES ENV_MODULE, #endif ENV_VHOST,ENV_BACKLOG,ENV_COLUMNS,ENV_SHELL, ENV_EDITOR); nsexit(0,0); } /* stated in displayv(). also, finally went for the \t's here too. */ V usage(U SH extended){ nsprint("Usage: %s [extended options...] -s|-r file -b|-h host -p port\n" "Usage: %s file (must be a +rx internal argument supplied ruleset file)\n" "Usage: %s --list [path:path:...] (must be used by command line only)\n" "Usage: %s --hist [#]|[clear] (must be used by command line only)\n" "Usage: %s [--interactive] (will enter interactive prompted mode)\n", progname,progname,progname,progname,progname); IF(extended) nsprint("\n -r <file>\t\tinput/output (ruleset) file. (required, or -s)\n" " -h <host>\t\tremote host (or ip) to connect to. (required, or -b)\n" " -p <port>\t\tremote port to connect to, or bind to. (required)\n" " -# <data>\t\twill statically define the dynamic variable. (#=0-9)\n" " -i <data>\t\tsend initial data once connected. (\"?\" for dynamic)\n" " -m <path>\t\twill change the working directory of netscript.\n" " -M <path>\t\twill change the root directory of netscript. (superuser)\n" " -R <host>\t\twill set a host, to route socket data to.\n" " -k <port>\t\twill set a port to connect to on the route host. (-R)\n" " -u <data>\t\tchanges netscript id permissions. (\"user[.group]\" style)\n" " -q <host>\t\twill define a virtual host to use, or bind to.\n" " -o <data>\t\twill omit socket reading of the supplied character(s).\n" " -S <time>\t\tdelay before processing incoming data. (seconds)\n" " -U <time>\t\tdelay before processing incoming data. (useconds)\n" " -t <time>\t\tclose the connection after alloted time.\n" " -Q <data>\t\tsets local socket option(s). (\"#,#,#:#,#,#:...\" style)\n" " -l <file>\t\tturns input/output logging on, writes to the file.\n" #ifdef GTK " -G <name>\t\tdisplays the name as the title for the gui. (-g)\n" " -+ <size>\t\tchanges the length of the pulldown. (non-generic) (-g)\n" " -# <data>\t\tsets foreground color for the gui. (\"ffffff\" style) (-g)\n" " -K <data>\t\tsets button labels for the gui. (\"l1:l2:l3\" style) (-g)\n" #endif #ifdef NCURSES " -= <data>\t\tsets tab labels for ncurses. (\"l1:l2\" style) (-_)\n" #endif " -e <prog>\t\tdumps the program data to the socket.\n" " -E <data>\t\tprecurse data to attach for each line dumped. (-e)\n" " -O <prog>\t\twill use an alternate shell for executions. (-e)\n" " -x <time>\t\tkills the program if the program dump hangs. (-e)\n" " -X\t\t\tkills netscript after the program has been dumped. (-e)\n" " -a\t\t\twill allow interactive use of programs. (-e)\n" " -f\t\t\twill run a third party edtior to define the ruleset.\n" " -@\t\t\twill switch netscript to the UDP protocol.\n" " -^\t\t\twill switch the route host to the UDP protocol.\n" " -B\t\t\tsends netscript to the background.\n" " -n\t\t\tdisables display of outgoing data.\n" " -N\t\t\tdisables display of incoming data.\n" " -j\t\t\tdisable routed sending of outgoing data. (-R)\n" " -J\t\t\tdisable routed sending of incoming data. (-R)\n" " -F\t\t\tdisables display of arrow precursors.\n" " -I\t\t\twhen disconnected. reconnect, or rebind.\n" " -s\t\t\ttakes the ruleset from standard input instead of a file.\n" " -b\t\t\tbinds to the supplied port, instead of connecting out.\n" #ifdef GTK " -g\t\t\tuses the gui frontend. (use twice for generic version)\n" " -W\t\t\tautomatically starts pulled down. (non-generic) (-g)\n" #endif #ifdef NCURSES " -_\t\t\tswitch console display to ncurses visualization.\n" #endif #ifndef DISABLE_SYSLOG " -Z\t\t\tuses system logging. (if syslog is accessible)\n" #endif " -T\t\t\tattempts to interpret the telnet protocol.\n" " -y\t\t\twill dump raw socket data to standard error. (-T)\n" " -Y\t\t\twill dump raw socket data to standard output. (-T)\n" " -z\t\t\tdisables display of verbose telnetd-opt input/output.\n" " -L\t\t\tdisplays the value of each line as a precursor.\n" " -H\t\t\tdisplays hex values, instead of character values. (ff)\n" " -D\t\t\tdisplays dec values, instead of character values. (255)\n" " -w\t\t\tdisables wordwrap for in/out displaying.\n" " -P\t\t\tdisables reading of non-printable characters.\n" " -c\t\t\tdisables display of connection notifications.\n" " -C\t\t\tdisables display of ruleset info that is not required.\n" " -A\t\t\tdisables display of all prompted netscript comments.\n" " -d\t\t\tdisplays the variables used by the ruleset, and environ.\n" " -v\t\t\tdisplays the version info of netscript, and exits.\n" " -V\t\t\tdisplays the version info of netscript, and continues.\n" "\nAuthor: %s. [ihadnihn]\n",author); nsexit(0,0); } /* any global exit routines can be placed here, your choice. */ V nsexit(SH i,U SH type){ /* clear the screen for ncurses. */ #ifdef NCURSES IF(isncurses) endwin(); #endif /* just idle out until really closed. */ #ifdef GTK IF(isgui&&isgui!=3&&isagui){ pe("all processing finished, awaiting exit request",0); isgui=2; W(isgui!=3) USLP(250000); } #endif #ifndef DISABLE_SYSLOG /* only if something happened, note this one. */ IF(!(!slnum_s&&!slnum_t)) wrso("%d-%d id: %lu-%u.%u.%u.%u exit: %s (%s)",slnum_t,slnum_s,cpid,GU(), GEU(),GG(),GEG(),(i?"abnormal":"normal"),(cpid==GPD()?"main":"branch")); #endif /* check, and use the ns_exit() symbol, it passes the exit value, and exit */ /* type(main/branch). (short, unsigned short) */ #ifndef DISABLE_MODULES IF(vmodule){ (*exit_function)(i,type); /* added clean-up for the module file here, since it is going to exit. */ dlclose(dyn); } #endif /* clean up a possible build up with raw telnet on exit. */ IF(tnetraw&&truetnet){ nsprint("\n"); /* same goes for logging. */ IF(islog) logdata("\n",3); } closesocket(0); closesocket(1); IF(type) _exit(i); E exit(i); } /* the following function is only for the ncurses mode. */ #ifdef NCURSES V ncursesinit(V) { U I i=0; initscr(); cbreak(); nonl(); keypad(stdscr,TRUE); /* reset columns to ncurses information. */ columns=(COLS-1); /* no need for anything larger, unless you are trying to bother memory. */ IF(1024<columns){ pe("COLS is too large",0); columns=DFL_COLUMNS; } /* the prompt itself must be counted in the most minimal of cases. */ IF((1>columns&&nofrom)||(4>columns&&!nofrom)){ pe("COLS is too small",0); columns=DFL_COLUMNS; } /* setup tab labels. */ F(i=0;i<COLS;i++) NWV(stdscr,((LINES-3-1)/2),i,'-'); F(i=0;i<COLS;i++) NWV(stdscr,(LINES-3),i,'-'); NMW(((LINES-3-1)/2),0,"[-<"); NMW(((LINES-3-1)/2),3,(isncursesl?nclabel[0]:"Output stream")); NMW(((LINES-3-1)/2),(isncursesl?(SL(nclabel[0])+3):16),">"); NMW(((LINES-3-1)/2),(COLS-1),"]"); NMW((LINES-3),0,"[-<"); NMW((LINES-3),3,(isncursesl>1?nclabel[1]:"Input stream")); NMW((LINES-3),(isncursesl>1?(SL(nclabel[1])+3):15),">"); NMW((LINES-3),(COLS-1),"]"); move((LINES-3+1),0); NR(); /* make (ncurses) windows. */ nw1=NSW(stdscr,((LINES-3-1)/2),COLS,0,0); NSO(nw1,1); nw2=NSW(stdscr,((LINES-3-1)/2),COLS,((LINES-3-1)/2)+1,0); NSO(nw2,1); nw3=NSW(stdscr,(3-1),COLS,((LINES-3)+1),0); NSO(nw3,1); touchwin(stdscr); NR(); /* straighten up. */ NE(nw1); NRE(nw1); NE(nw2); NRE(nw2); NE(nw3); NRE(nw3); /* nsprint() defaultly goes to the main (ncurses) window. */ nfocus=nw3; /* ready to go. */ isncurses=1; R; } #endif /* the following functions are only for the gui mode. */ #ifdef GTK /* function triggered when return is pressed for an entry. (gui mode) */ V gtkec(GW *gw,GW *ge){ GC *et; et=gtk_entry_get_text(GTK_ENTRY(ge)); IF(SL(et)&&isgui==1){ IF(isguiwait){ /* write the response to the socket. */ wro(et,SL(et),0); wro("\n",1,0); /* log if requested. */ IF(islog) logdata(et,0); /* reset waiting loop. */ isguiwait=0; gtk_entry_set_text(GTK_ENTRY(ge),""); /* only for non-generic gui. */ IF(!isbgui){ /* away you go. */ GWH(gen); /* window refresh. */ GWSU(giw,guiw,guih); /* refocus on the last button made, which is the exit button. */ GWGF(gbu); } } } R; } /* function to clear the screen. (gui mode) */ V gtkcl(GW *gw,GPT gd){ IF(gtk_text_get_length(GTK_TEXT(gte))) gtk_text_backward_delete(GTK_TEXT(gte),gtk_text_get_length(GTK_TEXT(gte))); R; } /* function to pull down the gui, using 300 as a general/default value. */ /* (non-generic gui mode) */ V gtkpd(GW *gw,GPT gd){ IF(GTK_TOGGLE_BUTTON(gpd)->active==TRUE) guih+=(guio?guio:300); E guih-=(guio?guio:300); /* set the new position. */ GWSU(giw,guiw,guih); R; } /* function that is triggered to close the program. (gui mode) */ V gtkca(GW *gw,GPT gd){ gtk_main_quit(); /* finalize the close. */ isgui=3; /* just incase netscript is waiting anywheres else. */ nsexit(0,0); } /* create, and launch the display. (gui mode) */ V gtkrun(C *dispname){ C *disptitle; /* check for normal, non-generic font. */ IF(!isbgui&&!(GFL(GUI_FONT))) pe("error loading font, use the -g option twice for generic mode",1); /* set up the soon-to-be titlebar. */ IF(!(disptitle=(C *)M((isguititle?SL(guititle):SL(dispname))+SL(VERSION)+33+1) )) pe("gtkrun(): allocation of memory error",1); B(disptitle,((isguititle?SL(guititle):SL(dispname))+SL(VERSION)+33+1)); SP(disptitle,"Netscript/v%s(%.3s)-Xvisualization: %s",VERSION,COMPTYPE, (isguititle?guititle:dispname)); /* setup the window. */ giw=gtk_window_new(GTK_WINDOW_TOPLEVEL); GWSU(giw,(isbgui?520:(guiw=440)),(isbgui?200:(guih=150))); /* defined to not be allowed to make too small, does not look so hot. */ gtk_window_set_policy(GTK_WINDOW(giw),FALSE,(isbgui?TRUE:FALSE),FALSE); GSC(GTK_OBJECT(giw),"destroy",GTK_SIGNAL_FUNC(gtkca),0); gtk_window_set_title(GTK_WINDOW(giw),disptitle); /* done with title buffer. */ FR(disptitle); GCSBW(GTK_CONTAINER(giw),0); gb1=GVN(FALSE,0); gtk_container_add(GTK_CONTAINER(giw),gb1); GWS(gb1); gb2=GVN(FALSE,0); GCSBW(GTK_CONTAINER(gb2),5); GBPS(GTK_BOX(gb1),gb2,TRUE,TRUE,0); GWS(gb2); gta=gtk_table_new(2,2,FALSE); GBPS(GTK_BOX(gb2),gta,TRUE,TRUE,0); GWS(gta); /* text widget, vertical bar gets added on next. */ gte=gtk_text_new(0,0); gtk_text_set_editable(GTK_TEXT(gte),FALSE); gtk_text_set_word_wrap(GTK_TEXT(gte),FALSE); GTA(GTK_TABLE(gta),gte,0,1,0,1,GTK_EXPAND|GTK_SHRINK|GTK_FILL,GTK_EXPAND| GTK_SHRINK|GTK_FILL,0,0); GWS(gte); /* vertical scrollbar, for the text widget. */ gvs=gtk_vscrollbar_new(GTK_TEXT(gte)->vadj); GTA(GTK_TABLE(gta),gvs,1,2,0,1,GTK_FILL,GTK_EXPAND|GTK_SHRINK|GTK_FILL,0,0); GWS(gvs); gtk_widget_realize(gte); gtk_text_freeze(GTK_TEXT(gte)); gtk_text_thaw(GTK_TEXT(gte)); gvn=GVN(TRUE,0); GBPS(GTK_BOX(gb2),gvn,FALSE,FALSE,0); GWS(gvn); /* entry box. (do not show until needed, unless generic mode is on) */ gen=gtk_entry_new_with_max_length(BASE_BUFFER); GSC(GTK_OBJECT(gen),"activate",GTK_SIGNAL_FUNC(gtkec),gen); GBPS(GTK_BOX(gvn),gen,FALSE,FALSE,0); IF(isbgui) GWS(gen); /* pulldown/up button/box. (only in non-generic gui mode) */ IF(!isbgui){ /* button box. */ gpb=GHN(TRUE,0); GBPS(GTK_BOX(gvn),gpb,FALSE,FALSE,0); GWS(gpb); /* check button. */ gpd=gtk_check_button_new_with_label(isguil>2?gblabel[2]:"Pulldown"); GSC(GTK_OBJECT(gpd),"clicked",GTK_SIGNAL_FUNC(gtkpd),0); GBPS(GTK_BOX(gpb),gpd,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(gpd,GTK_CAN_DEFAULT); GWS(gpd); } /* button box. */ ghb=GHN(TRUE,0); GBPS((isbgui?GTK_BOX(gvn):GTK_BOX(gpb)),ghb,FALSE,TRUE,0); GWS(ghb); /* clear button. */ gbu=gtk_button_new_with_label(isguil>1?gblabel[1]:"Clear"); GSC(GTK_OBJECT(gbu),"clicked",GTK_SIGNAL_FUNC(gtkcl),0); GBPS(GTK_BOX(ghb),gbu,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(gbu,GTK_CAN_DEFAULT); GWS(gbu); /* exit button. */ gbu=gtk_button_new_with_label(isguil?gblabel[0]:"Exit"); GSC(GTK_OBJECT(gbu),"clicked",GTK_SIGNAL_FUNC(gtkca),0); GBPS(GTK_BOX(ghb),gbu,TRUE,TRUE,0); GTK_WIDGET_SET_FLAGS(gbu,GTK_CAN_DEFAULT); GWS(gbu); /* focus on the entry/exit button. (depending if generic mode is on) */ GWGF(isbgui?gen:gbu); /* pulldown on start. (-W option) */ IF(!isbgui&&isguis) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gpd),TRUE); /* show the window. */ GWS(giw); /* allow output/display use. */ isagui=1; /* update the gui. */ GTE(); gtk_main(); GTL(); /* netscript is done. */ pthread_exit(0); R; } #endif /* this function is to check for the reverse wildcard check. if it does */ /* not occur it gets passed normally along to wordmatch(). */ U SH prewordmatch(C *wildcard,C *in){ U SH r=0; U I i=0; C *tmpwildcard; IF(!(tmpwildcard=(C *)SDU(wildcard))) pe("prewordmatch(): duplication of memory error",1); /* check for the negative/reverse match rule. */ IF(SL(tmpwildcard)>SL(NS_NMATCH)&&!SNCC(tmpwildcard,NS_NMATCH,SL(NS_NMATCH))){ F(i=SL(NS_NMATCH);i<SL(tmpwildcard);i++) tmpwildcard[(i-SL(NS_NMATCH))]=tmpwildcard[i]; tmpwildcard[(i-SL(NS_NMATCH))]=0x0; r=wordmatch(tmpwildcard,in); /* done with that. */ FR(tmpwildcard); /* reverse it, the idea of this pre-function. */ R(r?0:1); } /* otherwise, just like normal. */ E R wordmatch(wildcard,in); } /* for the real wildcard match checking. */ U SH wordmatch(C *wildcard,C *in){ U I i=0; U I j=0; U I k=0; U I r=0; U I tmp=0; C *tmpbuf; /* handles the dynamic variables. (${0-9}) */ parsedynamic(wildcard); /* remove back-to-back spaces for parsing with the remote data. */ F(j=0;j<SL(in);j++){ IF(!(in[j+1]&&in[j]==0x20&&in[j+1]==0x20)) in[k++]=in[j]; } in[k]=0x0; /* remove back-to-back spaces for parsing with the ruleset. */ F(k=j=0;j<SL(parseddynamic);j++) IF(!(parseddynamic[j+1]&&parseddynamic[j]==0x20&&parseddynamic[j+1]==0x20)) parseddynamic[k++]=parseddynamic[j]; parseddynamic[k]=0x0; /* quick exact match check. */ IF(!SC(parseddynamic,in)) R(0); W(!parameter(parseddynamic,i,0x20)){ IF(!(tmpbuf=(C *)SDU(parm))) pe("wordmatch(): duplication of memory error",1); /* checks for a wildcard match for anything after that point. before */ /* checking the next parameter. */ IF(SC(tmpbuf,NS_ALL)){ /* gets the input parameter, to check for the rest of the wildcards, or */ /* possible perfect matches. if no more parameters, returns failure. */ /* also increases the word for the next loop run. */ IF(parameter(in,i++,0x20)){ FR(tmpbuf); R(1); } /* checking for all wildcard word matches. (length wildcard is next) */ IF(!SC(tmpbuf,parm)||!SCC(tmpbuf,NS_ANY)||(!SCC(tmpbuf,NS_ALPHA)&&wischeck( parm,0))||(!SCC(tmpbuf,NS_DIGIT)&&wischeck(parm,1))||(!SCC(tmpbuf,NS_ALNUM) &&wischeck(parm,2))||(!SCC(tmpbuf,NS_UPPER)&&wischeck(parm,3))||(!SCC( tmpbuf,NS_LOWER)&&wischeck(parm,4))||(!SCC(tmpbuf,NS_PUNCT)&&wischeck(parm, 5))||(!SCC(tmpbuf,NS_CNTRL)&&wischeck(parm,6))||(!SCC(tmpbuf,NS_PRINT)&& wischeck(parm,7))) r=0; /* the length wildcard, must be four digits long, and then will be */ /* processed accordingly. */ EI(SL(tmpbuf)==5&&tmpbuf[0]==PARAMETER_VAR_CHAR&&ID((U I)tmpbuf[1])&& ID((U I)tmpbuf[2])&&ID((U I)tmpbuf[3])&&ID((U I)tmpbuf[4])){ tmp=(((tmpbuf[1]-0x30)*1000)+((tmpbuf[2]-0x30)*100)+((tmpbuf[3]-0x30)*10)+ (tmpbuf[4]-0x30)); /* match. */ IF(SL(parm)==tmp) r=0; /* did not match. */ E r=1; } E r=1; IF(r){ FR(tmpbuf); R(r); } } E{ FR(tmpbuf); R(r); } FR(tmpbuf); } /* leftover data does not count as a match. just using int i again for the */ /* loop. checks to see if uneven arguments. 1 = failed, 0 = success. */ i=0; W(!parameter(parseddynamic,i,0x20)) i++; IF(!parameter(in,i,0x20)) /* un-even. */ r=1; E /* even. */ r=0; R(r); } /* this is meant to pluck a word out of a sentence, then duplicated it to */ /* the character string "parm". kind of like a strtok() without tokenizing. */ U SH parameter(C *string,I i,U I sep){ U I j=0; U I k=0; U I r=0; /* no comparison. */ C *buf; IF(!(buf=(C *)M(SL(string)+1))) pe("parameter(): allocation of memory error",1); B(buf,(SL(string)+1)); IF(i<0) r=1; E F(j=0;j<SL(string);j++){ IF(string[j]==sep) i--; EI(!i) buf[k++]=string[j]; IF(string[j]==0x0A||string[j]==0x0) j=(SL(string)+1); } IF(i>0) r=1; FR(parm); IF(!(parm=(C *)SDU(buf))) pe("parameter(): duplication of memory error",1); FR(buf); R(r); } /* this function checks word format of their counterpart, instead of a */ /* single character. for some reason i like using strlen() instead of *buf */ /* to check for use, old habit i suppose. */ U SH wischeck(C *word,U I type){ U I i=0; IF(!SL(word)) R(0); F(i=0;i<SL(word);i++) IF((!IL((U I)word[i])&&type==0)||(!ID((U I)word[i])&&type==1)||(!isalnum( (U I)word[i])&&type==2)||(!isupper((U I)word[i])&&type==3)||(!islower((U I) word[i])&&type==4)||(!ispunct((U I)word[i])&&type==5)||(!iscntrl((U I) word[i])&&type==6)||(!IP((U I)word[i])&&type==7)) R(0); R(1); } /* this function handles the --list command line argument. */ U SH usefilelist(C *path){ U SH r=0; U I i=0; C *tmppath; C lread[(BASE_BUFFER*4+1)]; FL *lfd; glob_t gb; gb.gl_offs=0; F(i=0;!parameter(path,i,0x3A);i++){ IF(SL(parm)){ IF(!(tmppath=(C *)M(SL(parm)+3))) pe("usefilelist(): allocation of memory error",1); B(tmppath,(SL(parm)+3)); SP(tmppath,"%s/*",parm); GB(tmppath,(i==0?GLOB_DOOFFS:(GLOB_DOOFFS|GLOB_APPEND)),0,&gb); FR(tmppath); } } F(i=0;(i<gb.gl_pathc&&i<1000);i++) nsprint("%.3d\t%.64s%s\n",i,gb.gl_pathv[i],(SL(gb.gl_pathv[i])>64?"...":"")); IF(!i){ pe("no files found to list",1); r=0; } E{ nsprint("enter list value to use(0-%d): ",(i-1)); IF(!(lfd=FO(ttyn,"r"))) pe("could not open standard input for read",1); E{ B(lread,(BASE_BUFFER*4+1)); IF(FS(lread,(SO(lread)-1),lfd)) F(i=0;i<SL(lread);i++) IF(lread[i]==0x0A) lread[i]=0x0; } FC(lfd); IF(!SL(lread)||!wischeck(lread,1)) r=0; E{ IF(gb.gl_pathc<=AI(lread)||0>AI(lread)) r=0; E{ IF(!(tofile=(C *)SDU(gb.gl_pathv[AI(lread)]))) pe("usefilelist(): duplication of memory error",1); r=1; } } } GBF(&gb); R(r); } /* this function is for using the stored history file(~/.nshistory) to */ /* quickly activate netscript. (most) output stderr, for this function. */ U SH usehistory(C *preread,U SH type){ U I i=0; U I j=0; U I k=0; U C hread[(BASE_BUFFER*4+1)]; FL *hfd; IF(!type){ IF(!(hfd=FO(histfile,"r"))) pe("history file does not appear to exist, or is not readable",1); E{ B(hread,(BASE_BUFFER*4+1)); W(FS(hread,(SO(hread)-1),hfd)&&j<1000){ F(i=0;i<SL(hread);i++) IF(hread[i]==0x0A) hread[i]=0x0; nsprint("%.3d\t%.64s%s\n",j++,hread,(SL(hread)>64?"...":"")); } } FC(hfd); IF(j==0) pe("history file does not contain any data",1); nsprint("enter history value to use(0-%d/clear): ",(j-1)); IF(!(hfd=FO(ttyn,"r"))) pe("could not open standard input for read",1); E{ B(hread,(BASE_BUFFER*4+1)); IF(FS(hread,(SO(hread)-1),hfd)) F(i=0;i<SL(hread);i++) IF(hread[i]==0x0A) hread[i]=0x0; } FC(hfd); IF(!SNC(hread,"clear",5)) nsexit(delhistory(histfile),0); IF(!SL(hread)||!wischeck(hread,1)) R(0); k=AI(hread); } E{ IF(!SL(preread)||!wischeck(preread,1)) R(0); k=AI(preread); } j=0; IF(!(hfd=FO(histfile,"r"))) pe("history file does not appear to exist, or is not readable",1); E{ B(hread,(BASE_BUFFER*4+1)); W(FS(hread,(SO(hread)-1),hfd)){ IF(j==k){ F(i=0;i<SL(hread);i++) IF(hread[i]==0x0A) hread[i]=0x0; IF(!(toenv=(C *)M(SL(hread)+1))) pe("usehistory(): allocation of memory error",1); B(toenv,(SL(hread)+1)); /* memory compatibility issue. so, instead, allocate+copy. */ SCP(toenv,hread); FC(hfd); R(1); } E j++; } } FC(hfd); R(0); } /* funcation to delete the history file. */ U SH delhistory(C *file){ /* check for existence, and write access. */ IF(AC(file,F_OK)&&AC(file,W_OK)){ pe("could not access the history file to delete",0); R(1); } /* no errors above, attempt to delete. */ EI(UN(file)){ pe("could not delete the history file",0); R(1); } /* deleted without a problem. */ pe("successfully removed the history file",0); R(0); } /* gets arguments out of +x files, if no arguments it will return false, and */ /* not continue. */ U SH getexecargs(C *ruleset){ U I i=0; U I j=0; /* if it is bigger than that someone is just trying to be evil. */ U C rread[(BASE_BUFFER*4+1)]; FL *fd; IF(!(fd=FO(ruleset,"r"))) pe("ruleset file does not appear to exist, or is not readable",1); E{ B(rread,(BASE_BUFFER*4+1)); /* only need to read the first two lines for the arguments. */ W(FS(rread,(SO(rread)-1),fd)&&j<2){ IF(SL(rread)>2&&!SNC(rread,"#?",2)){ /* ?(args) + -2("#?") + ?(ruleset) + 4(-r,space,space) + 1(extra). */ IF(!(toenv=(C *)M(SL(rread)-2+SL(ruleset)+4+1))) pe("getexecargs(): allocation of memory error",1); B(toenv,(SL(rread)-2+SL(ruleset)+4+1)); SP(toenv,"-r %s ",ruleset); F(i=2;i<SL(rread);i++){ /* finish true, and append 0x0. */ IF(rread[i]==0x0A){ toenv[SL(toenv)]=0x0; FC(fd); R(1); } toenv[SL(toenv)]=rread[i]; } } j++; } } FC(fd); R(0); } /* function to read /etc/services in conjunction with the -p option to */ /* support services in the form of a string. for example: "finger". */ /* port should really be a short instead of an int. but, i wanted error */ /* checking. so, i used int. */ U I portentry(C *service){ S servent *se; IF(!(se=GS(service,(isudp?"udp":"tcp")))) R(AI(service)); E /* convert back from the network byte order that the function does. */ R(NHS(se->s_port)); /* will never really make it here. */ R(0); } /* program initializes here. gets things started. */ I main(I ac,C **av){ U SH sethist=0; U SH setlist=0; U I i=0; U I j=0; U I k=0; U I l=0; U I m=0; U I n=0; /* the pid of the background process. */ PT bgpid=0; C *avo; C *envcmd; C *histline; /* threads are only needed for the gui. */ #ifdef GTK pthread_t pt; #endif /* set the static pid value. (for display) */ cpid=GPD(); /* set the program name. this is kind of like rindex()/strrchr(). but, */ /* slightly different. */ F(i=SL(av[0]);(av[0][i]!=0x2F&&i>0);i--) j++; IF(i<=0){ IF(!(progname=(C *)SDU(av[0]))) pe("main(): duplication of memory error",1); } E{ /* do not add extra zero'd byte, it is already there at this point. */ IF(!(progname=(C *)M(j))) pe("main(): allocation of memory error",1); B(progname,j); F(i=SL(av[0]);j;i--){ j--; progname[j]=av[0][i]; } } /* ctrl-c. */ SG(SIGINT,sighandler); /* segmentation fault, hope not to see that. */ SG(SIGSEGV,sighandler); /* kill, or terminate signal. */ SG(SIGTERM,sighandler); /* used for timed killing of netscript. */ SG(SIGALRM,sighandler); /* other signals to catch, for clean up. (not defined in the handler) */ SG(SIGILL,sighandler); SG(SIGTRAP,sighandler); SG(SIGBUS,sighandler); SG(SIGQUIT,sighandler); /* ignored for binding(with -I). do not want to exit due to it. */ SG(SIGPIPE,SIG_IGN); /* make global non-other, and non-group permissions for files made by */ /* netscript. */ UM(077); /* using this method for global knowledge that if netscript was started */ /* privileged, or not. any other way the -u option could change the */ /* effects of checking. since this gets processed first, it will know. */ /* just in the rare case netscript would need to be set*id. disables */ /* modules, file reading/writing, and third party execution support. if */ /* started set*id. (or could use stored values for later checking. but, i */ /* like this method) */ IF(GU()!=GEU()||GG()!=GEG()) isprivileged=1; E isprivileged=0; /* set*id = sete*id. (mainly for proper permission changes) */ SUD(GEU()); SGD(GEG()); /* write to the array of the defined options. (when compiled) */ setdefined(); /* only time this should be used. */ IF(!isprivileged){ setrc(RCFILE); sethistory(HISTFILE); } /* take care of the modules environmental variable first. */ #ifndef DISABLE_MODULES IF(G(ENV_MODULE)){ IF(isprivileged) pe("environmental variable module file ignored with privileged access",0); E modhandler((C *)G(ENV_MODULE)); } /* check, and use the ns_init() symbol, it passes the number of command */ /* line arguments, and the arguments. (int, char **) */ IF(vmodule) (*init_function)(ac,av); #endif /* set the shell for executing third party programs. make sure it is */ /* executable. */ IF(G(ENV_SHELL)&&!AC((C *)G(ENV_SHELL),X_OK)){ IF(!(eshell=(C *)SDU((C *)G(ENV_SHELL)))) pe("main(): duplication of memory error",1); } /* if all else fails. set default, and hope. */ E{ IF(!(eshell=(C *)SDU(SHPATH))) pe("main(): duplication of memory error",1); } /* set up the display name. */ setdname(); /* set up the tty name. */ IF(!AC(TN(0),R_OK)){ IF(!(ttyn=(C *)SDU(TN(0)))) pe("main(): duplication of memory error",1); } E{ IF(!(ttyn=(C *)SDU(INPUTPATH))) pe("main(): duplication of memory error",1); } /* made sure the usage is seen. */ IF(ac>=2&&!SNC(av[1],"--help",6)) usage(1); /* generalized support for the --hist[ory] option to read ~/.nshistory. */ IF(ac>=2&&!SNC(av[1],"--hist",6)){ IF(isprivileged) pe("can not use \"--hist\" while in privileged mode",1); E{ IF(ac>=3&&!SNC(av[2],"clear",5)) nsexit(delhistory(histfile),0); E{ k=usehistory((ac>=3?av[2]:0),(ac>=3?1:0)); IF(!k) pe("invalid history value",1); E sethist=1; } } } IF(G(ENV_PATH)||(ac>=2&&!SNC(av[1],"--list",6))){ IF(isprivileged) pe("can not use \"--list\" while in privileged mode",1); E{ /* handle the list, environmental variable overrides command line. */ setlist=usefilelist(G(ENV_PATH)?(C *)G(ENV_PATH):(ac>=3?av[2]:".")); IF(!setlist) pe("invalid list value",1); } } /* +x ruleset file support, generalized support. (or modified) */ IF(((av[1]&&!av[2])||setlist)&&!AC((setlist?tofile:av[1]),R_OK)&&!AC((setlist? tofile:av[1]),X_OK)) k=getexecargs(setlist?tofile:av[1]); /* last use of --list, then everything is passed over. */ IF(setlist){ FR(tofile); IF(!k) pe("not a valid (internal argument supplied) netscript ruleset",1); } /* check the environment for the command line override variable. or, take */ /* +x file arguments as env controller, all in one deal. */ IF(G(ENV_CMDLINE)||k){ /* priority 1 is +x files, priority 2 is env var, and priority 3 is the */ /* normal command line. */ IF(k){ IF(!(envcmd=(C *)M(SL(toenv)+SL(av[0])+2))) pe("main(): allocation of memory error",1); B(envcmd,(SL(toenv)+SL(av[0])+2)); } E{ IF(!(envcmd=(C *)M(SL((C *)G(ENV_CMDLINE))+SL(av[0])+2))) pe("main(): allocation of memory error",1); B(envcmd,(SL((C *)G(ENV_CMDLINE))+SL(av[0])+2)); } IF(k){ SP(envcmd,"%s %s",av[0],toenv); /* done with that buffer. */ FR(toenv); } E SP(envcmd,"%s %s",av[0],(C *)G(ENV_CMDLINE)); /* used this method to make a fresh argument list. */ /* finding out how many elements are needed. then, nulling the loop */ /* routine since it was all done in the process itself. */ F(ac=0;!parameter(envcmd,ac,0x20);ac++); /* creates the argument array. also, added an extra slot for argv[0], */ /* which will remain unused. but, getopt() expects it. */ IF(!(av=(C **)M((ac+1)*(SO(C *))))) pe("main(): allocation of memory error",1); /* fill the array with the data from the env var, or +x file. */ /* (ENV_CMDLINE|+x) */ F(ac=0;!parameter(envcmd,ac,0x20);ac++){ IF(!(av[ac]=(C *)SDU(parm))) pe("main(): duplication of memory error",1); } FR(envcmd); } /* add the -g option automatically, if it is linked by "gnetscript". */ #ifdef GTK IF((!SC(((C *)RI(progname,0x2F)?(C *)RI(progname,0x2F):"0"),"/gnetscript")|| !strcmp(progname,"gnetscript"))&&!isprivileged) isgui=1; #endif /* add the -_ option automatically, if it is linked by "nnetscript". */ #ifdef NCURSES IF((!SC(((C *)RI(progname,0x2F)?(C *)RI(progname,0x2F):"0"),"/nnetscript")|| !strcmp(progname,"nnetscript"))) isncursesa=1; #endif IF(ac>1&&SNC(av[1],"--interactive",13)){ /* set up, and build the (get) option list. */ n=89; #ifdef GTK n+=10; #endif #ifdef NCURSES n+=3; #endif #ifndef DISABLE_SYSLOG n+=1; #endif IF(!(avo=(C *)M(n+1))) pe("main(): allocation of memory error",1); B(avo,(n+1)); SCP(avo,"r:h:p:0:1:2:3:4:5:6:7:8:9:i:m:M:R:k:u:q:o:S:U:t:Q:l:e:E:O:x:Xaf@^Bn" "NjJFIsbTyYzLHDwPcCAdvV"); #ifdef GTK SCA(avo,"G:+:#:K:gW"); #endif #ifdef NCURSES SCA(avo,"_=:"); #endif #ifndef DISABLE_SYSLOG SCA(avo,"Z"); #endif /* interpret out the arguments supplied. */ /* i changed a method here, due to me using shorts for most of these */ /* options. i did not want a possible loop over bug to occur if someone */ /* was trying to break netscript with repeated arguments. (65536) */ W((i=getopt(ac,av,avo))!=EOF){ SW(i){ /* does not matter if a user has privileged access, and loads a ruleset. */ /* because, it never gets relayed verbose. (unless someone knows a rule, */ /* or is traced back/memory) no major concern. */ CS 'r': /* can not have both. */ IF(!inputrules&&!setfile){ /* does both parsedynamic(), and parsecharvars(). gets used often. */ parsecmdline(optarg); IF(!(rulesfile=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); setfile=1; } BR; CS 'h': IF(!bindmode&&!sethost){ W(!parameter(optarg,tshs,0x2C)){ parsecmdline(parm); IF(!(shost[tshs++]=(C *)SDU(SL(parsedline)?parsedline:"0"))) pe("main(): duplication of memory error",1); IF(tshs>=MAX_ARGS) pe("too many slots to store in memory",1); } sethost=1; } BR; CS 'p': IF(!sport) sport=portentry(optarg); BR; /* not very pretty. but, it will do. all of these will be handled the */ /* same way. the statically set dynamic variable options. */ CS '0': CS '1': CS '2': CS '3': CS '4': CS '5': CS '6': CS '7': CS '8': CS '9': /* do not reset the variable, could cause memory problems. */ IF(dynamicvarset[(i-0x30)]!=2){ parsecmdline(optarg); IF(!(dynamicvar[(i-0x30)]=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); /* define it not to be changed, or reset. */ dynamicvarset[(i-0x30)]=2; } BR; CS 'i': IF(!initsend){ parsecmdline(optarg); IF(!(iswrite=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); initsend=1; } BR; CS 'm': IF(!setcdir){ parsecmdline(optarg); IF(!(cdir=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); setcdir=1; } BR; CS 'M': IF(!setrdir){ parsecmdline(optarg); IF(!(rdir=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); setrdir=1; } BR; CS 'R': IF(!setroute){ parsecmdline(optarg); IF(!(rhost=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); setroute=1; } BR; CS 'k': IF(AI(optarg)>0&&!rport) rport=AI(optarg); BR; CS 'u': IF(!setperms){ setpermissions(optarg,0); setperms=1; } BR; CS 'q': IF(!isvhost){ IF(!(vhost=(C *)SDU(optarg))) pe("main(): duplication of memory error",1); isvhost=1; } BR; CS 'o': IF(!omitchars){ parsecmdline(optarg); IF(!(ochars=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); omitchars=1; } BR; CS 'S': IF(AI(optarg)>0&&!sdelay) sdelay=AI(optarg); BR; CS 'U': IF(AL(optarg)>0&&!sudelay) sudelay=AL(optarg); BR; CS 't': IF(AI(optarg)>0&&!alrm) alrm=AI(optarg); BR; CS 'Q': IF(!soptions){ parsecmdline(optarg); IF(!(sopts=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); soptions=1; } BR; CS 'l': IF(isprivileged) pe("can not log data to a file with privileged access",0); E IF(!islog){ parsecmdline(optarg); IF(!(logfile=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); islog=1; } BR; #ifdef GTK CS 'G': IF(!isguititle){ parsecmdline(optarg); IF(!(guititle=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); isguititle=1; } BR; CS '+': IF(AI(optarg)>0&&!guio) guio=(AI(optarg)>GUI_MAXLEN?GUI_MAXLEN:AI(optarg)); BR; CS '#': IF(!isguic){ parsecmdline(optarg); IF(SL(parsedline)==6){ B((V *)guic,SO(guic)); F(isguic=i=0;i<6;i+=2){ IF(IL((U I)parsedline[i])) j=(TL(parsedline[i])-0x56); E j=(parsedline[i]-0x2F); j*=16; IF(IL((U I)parsedline[i+1])) j+=(TL(parsedline[i+1])-0x56); E j+=(parsedline[i+1]-0x2F); j-=17; IF(j>=0&&j<256) guic[isguic]=(j*257); isguic++; } } } BR; CS 'K': IF(!isguil){ parsecmdline(optarg); W(!parameter(parsedline,isguil,0x3A)&&isguil<3){ IF(!(gblabel[isguil++]=(C *)SDU(SL(parm)?parm:"nolabel"))) pe("main(): duplication of memory error",1); } } BR; #endif CS 'e': IF(isprivileged) pe("third party programs can not be executed with privileged access",0); E IF(!runcmd){ parsecmdline(optarg); IF(!(execfile=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); runcmd=1; } BR; CS 'E': IF(!runpre){ parsecmdline(optarg); IF(!(execpre=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); runpre=1; } BR; CS 'O': IF(!setshell){ parsecmdline(optarg); /* make sure it is executable. */ IF(!AC(parsedline,X_OK)){ /* was set by the environment, or default earlier. free it. */ FR(eshell); IF(!(eshell=(C *)SDU(parsedline))) pe("main(): duplication of memory error",1); setshell=1; } } BR; CS 'x': IF(AI(optarg)>0&&!xalrm) xalrm=AI(optarg); BR; CS 'X': runexit=1; BR; CS 'a': isiexec=1; BR; CS 'f': editrules=1; BR; CS '@': isudp=1; BR; CS '^': isudpr=1; BR; CS 'B': isbg=1; BR; CS 'n': nossend=1; BR; CS 'N': nosrecv=1; BR; CS 'j': norsend=1; BR; CS 'J': norrecv=1; BR; CS 'F': nofrom=1; BR; CS 'I': forever=1; BR; CS 's': /* can not have both. */ IF(!setfile) inputrules=1; BR; CS 'b': /* can not have both. */ IF(!sethost) bindmode=1; BR; #ifdef GTK CS 'g': IF(!isgui){ IF(!isprivileged) isgui=1; E pe("the gui frontend can not be used when netscript is privileged",0); } E isbgui=1; BR; CS 'W': isguis=1; BR; #endif #ifdef NCURSES CS '_': isncursesa=1; BR; CS '=': IF(!isncursesl){ parsecmdline(optarg); W(!parameter(parsedline,isncursesl,0x3A)&&isncursesl<2){ IF(!(nclabel[isncursesl++]=(C *)SDU(SL(parm)?parm:"nolabel"))) pe("main(): duplication of memory error",1); } } #endif #ifndef DISABLE_SYSLOG CS 'Z': slog=1; BR; #endif CS 'T': tnet=1; BR; CS 'y': tnetraw=1; BR; CS 'Y': tnetraw=2; BR; CS 'z': notnetopt=1; BR; CS 'L': /* set option, and force the no wrapping option. (-w option) */ lnum=lnum_i=lnum_o=nowrap=1; BR; CS 'H': /* 0 = character, 1 = hex, 2 = decimal. */ displaytype=1; BR; CS 'D': /* 0 = character, 1 = hex, 2 = decimal. */ displaytype=2; BR; CS 'w': nowrap=1; BR; CS 'P': printonly=1; BR; CS 'c': noshowc=1; BR; CS 'C': noshowp=1; BR; CS 'A': noshowa=1; BR; CS 'd': displayv(); BR; CS 'v': showinfo(1); nsexit(0,0); BR; CS 'V': showv=2; BR; default: usage(0); BR; } } /* done with buffer forever. */ FR(avo); } E iface(IFACE_PREFIX); /* if chroot, handle first. */ IF(setrdir){ CR(rdir); FR(rdir); } /* if chdir, handle second. */ IF(setcdir){ CD(cdir); FR(cdir); } /* check for -r|s|f, -h|b, and -p(int->short style) options. */ IF((!setfile&&!inputrules&&!editrules)||(!sethost&&!bindmode)||(1>sport|| 65535<sport)){ pe("no ruleset option, host|bind option, and/or port option defined",0); IF(ac>1) usage(1); E nsexit(0,0); } /* default if invalid, or non-existent. */ IF(1>rport||65535<rport) rport=sport; /* ruleset editor. (-f option) */ IF(editrules&&!inputrules){ IF(setfile) editrules=2; ruleedit(setfile,(setfile?rulesfile:0)); } /* make, and define the ruleset. */ makelists(rulesfile); /* remove temporary ruleset, only if a temporary file. (no verbose) */ IF(editrules==1) UN(rulesfile); /* if gui mode is on, disable certain option(s). */ #ifdef GTK /* can not do both, at least making sense. */ IF(isbg) isgui=0; EI(isgui&&tnetraw){ tnetraw=0; tnet=1; } #endif /* if one of the telnet fix options is supplied, fix conflicting option(s). */ /* also, forces telnet mode. (-y, and -Y options) */ IF(tnetraw) tnet=noshowa=nossend=nosrecv=1; #ifdef GTK IF(isgui){ g_thread_init(0); /* gtk initialization, passes arguments for gtk to handle. */ gtk_init(&ac,&av); /* get things going. if it fails for some reason, exit. */ IF(pthread_create(&pt,0,(V *)*gtkrun,(inputrules?"(standard input)":rulesfile ))) pe("could not create pthread, for the gui",1); /* time to catch up. */ W(!isagui) USLP(250000); } #endif /* main argument checking done, continuing on. */ IF(showv) showinfo(showv); /* check for non-dfl columns, for the pd() display function with wordwrap. */ /* do this before using the pd() function at all. */ IF(G(ENV_COLUMNS)){ columns=AI((C *)G(ENV_COLUMNS)); /* no need for anything larger, unless you are trying to bother memory. */ IF(1024<columns){ pe("ENV_COLUMNS environmental variable is too large",0); columns=DFL_COLUMNS; } /* the prompt itself must be counted in the most minimal of cases. */ IF((1>columns&&nofrom)||(4>columns&&!nofrom)){ pe("ENV_COLUMNS environmental variable is too small",0); columns=DFL_COLUMNS; } } E columns=DFL_COLUMNS; /* same idea as above. except a different kind of checking. */ IF(G(ENV_BACKLOG)){ blog=AI((C *)G(ENV_BACKLOG)); IF(128<blog){ pe("ENV_BACKLOG environmental variable is too large",0); blog=DFL_BACKLOG; } IF(1>blog){ pe("ENV_BACKLOG environmental variable is too small",0); blog=DFL_BACKLOG; } } E blog=DFL_BACKLOG; /* command line is a priority. */ IF(!isvhost&&G(ENV_VHOST)){ IF(!(vhost=(C *)SDU((C *)G(ENV_VHOST)))) pe("main(): duplication of memory error",1); isvhost=1; } /* there would atleast have been one argument to have made it this far. */ F(j=1;j<ac;j++) /* +1 for the space. (CR) */ m+=(SL(av[j])+1); IF(!(histline=(C *)M(m+1))) pe("main(): allocation of memory error",1); B(histline,(m+1)); F(j=1;j<ac;j++){ SCA(histline,av[j]); IF((j+1)!=ac) SCA(histline," "); } #ifndef DISABLE_SYSLOG wrso("%d-%d id: %lu-%u.%u.%u.%u init: %s",slnum_t,(slnum_s++),cpid,GU(),GEU(), GG(),GEG(),(SL(histline)?histline:"<no command line>")); #endif /* no need to re-write history. (sethist) */ IF(!isprivileged&&!sethist&&SL(histline)) addhistory(histline); /* done with this, forever. */ FR(histline); SW(isbg?(bgpid=FK()):0){ CS -1: pe("could not fork into the background",1); BR; CS 0: /* only if really backgrounding. */ IF(isbg){ /* no more output now. close up shop, just to make sure nothing is */ /* outputed. */ CL(0); CL(1); CL(2); isbga=1; } /* initialize ncurses, after everything is ready to go. (compiled option) */ #ifdef NCURSES IF(!(!isncursesa||isbg||tnetraw)) #ifdef GTK IF(!isgui) #endif ncursesinit(); #endif /* infinite connecting/binding. (-I option) */ IF(forever){ W(1){ /* either stops after all those hosts, to get reset. or, stays binded */ /* forever. */ W(l<tshs||bindmode){ parsesocket(bindmode?0:shost[l++],sport); #ifndef DISABLE_SYSLOG /* should only log closings, if is a multi-remote run. otherwise, it */ /* would show the static close, and exit everytime. a waste of space. */ wrso("%d-%d id: %lu-%u.%u.%u.%u closed: %d",slnum_t,slnum_s,cpid,GU(), GEU(),GG(),GEG(),slnum_t); /* reset system log counter. */ slnum_s=0; /* +1 the total. */ slnum_t++; #endif /* better safe than sorry, do not want fds to fill up. */ closesocket(0); SLP(1); } l=0; } } E{ W(l<tshs||bindmode){ parsesocket(bindmode?0:shost[l++],sport); /* turn bindmode off to leave this loop, and exit. (if bindmode) */ bindmode=0; /* better safe than sorry, do not want fds to fill up. */ closesocket(0); SLP(1); } } /* for backgrounding only. */ IF(isbga) nsexit(0,1); BR; default: nsprint("PID: [%lu@%s]\n",bgpid,nname); BR; } nsexit(0,0); /* never will actually make it to this point. but, will shut up warnings. */ exit(0); } /* EOF */