netscript.c: version 1.7.1/visual source code.
/* [ 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 <user> <pass> on this daemon. so, upon *
* receiving the error it sends the 3rd argument from the error message as *
* the <user> 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 <arpa/inet.h> /* socket related. */
#endif
#include <ctype.h> /* for wildcard (character) wordmatching. */
#ifdef NCURSES
#include <curses.h> /* ncurses/gui related. */
#endif
#ifndef DISABLE_MODULES
#include <dlfcn.h> /* dynlink/module usage. */
#endif
#include <errno.h> /* error display. */
#ifdef GTK
#include <glib.h> /* gui related. */
#endif
#include <glob.h> /* list related. */
#include <grp.h> /* get group names/gids. */
#ifdef GTK
#include <gtk/gtk.h> /* gui related. */
#endif
#include <netdb.h> /* socket related. */
#include <netinet/in.h> /* socket related. */
#ifdef GTK
#include <pthread.h> /* gui (incorporated) related. */
#endif
#include <pwd.h> /* get passwd names/uids. */
#include <stdarg.h> /* format uses. */
#include <stdio.h> /* multiple uses. */
#include <stdlib.h> /* multiple uses. */
#include <signal.h> /* to handle signals. ctrl-c, memory errors, etc. */
#include <string.h> /* multiple uses. */
#include <strings.h> /* multiple uses. */
#include <sys/socket.h> /* socket related. */
#include <sys/stat.h> /* umask related. */
#include <sys/time.h> /* log/etc. times. */
#include <sys/types.h> /* socket related. */
#include <sys/utsname.h> /* uname related. */
#include <sys/wait.h> /* exec related. */
#ifndef DISABLE_SYSLOG
#include <syslog.h> /* system logging. */
#endif
#include <time.h> /* log/etc. times. */
#include <unistd.h> /* 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 "<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 log=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;j<SL(swrite);j++)
swrite[(j-i)]=swrite[j];
swrite[(j-i)]=0x0;
R;
}
/* this function is meant to replace $001-255, and $01-FF to character */
/* format for the ruleset, also for replacement of the $&, and $# random */
/* variables. (not server related) */
V parsecharvars(C *line){
U I i=0;
U I j=0;
U I tmp=0;
S timeval tv;
FR(parsedline);
IF(!(parsedline=(C *)M(SL(line)+1)))
pe("parsecharvars(): allocation of memory error",1);
F(i=0;i<SL(line);i++){
IF(PARAMETER_VAR_CHAR==line[i]){
/* handle decimal truncation. */
IF(line[i+3]&&ID((U I)line[i+1])&&ID((U I)line[i+2])&&ID((U I)line[i+3])){
/* to not get confused with the length check wildcard. */
IF(!(line[i+4]&&ID((U I)line[i+4]))){
tmp=(((line[i+1]-0x30)*100)+((line[i+2]-0x30)*10)+(line[i+3]-0x30));
IF(tmp>0&&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<SL(in);i++){
IF(in[(i+3)]&&in[i]==PARAMETER_VAR_CHAR&&in[(i+1)]==0x7B&&ID((U I)in[(i+2)])
&&in[(i+3)]==0x7D&&!(i==0&&in[(i+4)]&&in[(i+4)]==0x3D)){
IF(dynamicvarset[(in[(i+2)]-0x30)])
j+=SL(dynamicvar[(in[(i+2)]-0x30)]);
i+=3;
}
E
j++;
}
FR(parseddynamic);
IF(!(parseddynamic=(C *)M(j+1)))
pe("parsedynamic(): allocation of memory error",1);
B(parseddynamic,(j+1));
F(i=0;i<SL(in);i++){
IF(in[(i+3)]&&in[i]==PARAMETER_VAR_CHAR&&in[(i+1)]==0x7B&&ID((U I)in[(i+2)])
&&in[(i+3)]==0x7D&&!(i==0&&in[(i+4)]&&in[(i+4)]==0x3D)){
/* only if the variable has been set, use it. */
IF(dynamicvarset[(in[(i+2)]-0x30)])
SCA(parseddynamic,dynamicvar[(in[(i+2)]-0x30)]);
i+=3;
}
E
parseddynamic[SL(parseddynamic)]=in[i];
}
R;
}
/* this function was made because these two functions are often with */
/* eachother. saves repetition space. */
V parsecmdline(C *in){
parsedynamic(in);
parsecharvars(parseddynamic);
R;
}
/* this function will set up the display name to be used by other functions. */
V setdname(V){
S utsname un;
/* get the display infromation. must check for equal or greater than zero. */
/* due to the fact different platforms handle this differently. but, */
/* errors being a negative number is an apparent constant. */
IF(UE(&un)>-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<SL(hread);i++)
IF(hread[i]==0x0A||hread[i]==0x0D)
hread[i]=0x0;
/* abort it already exists. */
IF(!SC(hread,data)){
FC(hfd);
R;
}
/* clean out. */
B(hread,(BASE_BUFFER*4+1));
}
FC(hfd);
}
IF((hfd=FO(histfile,"a"))){
FP(hfd,"%s\n",data);
FC(hfd);
}
R;
}
/* this is supposed to get the input, and output from the ruleset file. */
/* the file format is per line stacked, must have both. like so: */
/* input given. (wildcards apply here) */
/* output to responed. (pre-data/actions apply here) */
/* input given. (wildcards apply here) */
/* output to responed. (pre-data/actions apply here, and so on..) */
/* also partly handles the "one time" variable. */
V makelists(C *path){
/* yes, i could have reused some. but, i like to be able to keep track. */
/* loop ints. */
U I i=0;
U I j=0;
U I k=0;
U I l=0;
/* for the last input/output line. */
U C *lasti;
U C *lasto;
/* rather large size for possible long requests. */
U C rread[(BASE_BUFFER*16+1)];
FL *fd;
/* this switches to standard input if the argument is provided. */
IF(inputrules){
IF(!(fd=FO(ttyn,"r")))
pe("standard input does not appear to exist, or is not readable",1);
pe("awaiting ruleset from standard input, followed by ^D",0);
}
E{
IF(!(fd=FO(path,"r")))
pe("ruleset file does not appear to exist, or is not readable",1);
}
B(rread,(BASE_BUFFER*16+1));
W(FS(rread,(SO(rread)-1),fd)){
/* maximum input/output storage met. exits when it occurs. */
IF(j>=MAX_ARGS)
pe("too many slots to store in memory",1);
IF(rread[0]!=0x23){
F(i=0;i<SL(rread);i++)
IF(rread[i]==0x0A||rread[i]==0x0D)
rread[i]=0x0;
IF(rread[0]!=0x0A&&rread[0]!=0x0D&&rread[0]!=0x0){
/* simple on/off int to write line of input then line of output, then */
/* checking at the end to make sure the input, and output lines are */
/* even. (at the end of the function) */
IF(k)
k=0;
E
k=1;
IF(k){
/* replaces the hex, dec, and random variables. */
parsecharvars(rread);
IF(!(input[tot_i]=(SCC(rread,NS_REPEAT)||!tot_i?(C *)SDU(parsedline):(C *)
SDU(lasti))))
pe("makelists(): duplication of memory error",1);
/* store last input. */
IF(tot_i)
FR(lasti);
IF(!(lasti=(C *)SDU(input[tot_i++])))
pe("makelists(): duplication of memory error",1);
}
E{
/* decided not to allow an only function sleep, so data is required. */
/* virtually makes sure its exactly five numerics, like it must be. */
IF(SL(rread)>6&&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<SL(rread);l++)
rread[(l-SL(NS_ONCE))]=rread[l];
rread[(l-SL(NS_ONCE))]=0x0;
rs_static[tot_o]=1;
}
E
rs_static[tot_o]=0;
/* replaces the hex, dec, and random variables. */
parsecharvars(rread);
IF(!(output[tot_o]=(SCC(rread,NS_REPEAT)||!tot_o?(C *)SDU(parsedline):
(C *)SDU(lasto))))
pe("makelists(): duplication of memory error",1);
/* store last output. */
IF(tot_o)
FR(lasto);
/* add the effects of the copied output rule. (if copied) */
IF(!SCC(rread,NS_REPEAT)&&tot_o){
rs_static[tot_o]=rs_static[(tot_o-1)];
rs_delay[tot_o]=rs_delay[(tot_o-1)];
}
IF(!(lasto=(C *)SDU(output[tot_o++])))
pe("makelists(): duplication of memory error",1);
}
}
B(rread,(BASE_BUFFER*16+1));
}
j++;
}
FC(fd);
/* check for equal amount of input to outputs, so the ruleset corresponds. */
IF(tot_i!=tot_o)
pe("input/output data from the ruleset does not correspond",1);
/* no rules, no go. (might as well use telnet then) */
IF(!tot_i||!tot_o)
pe("no input/output responses supplied from the ruleset file",1);
/* status showing for stdin ruleset input. */
IF(inputrules)
pe("valid ruleset supplied via input, continuing",0);
/* clear one last time, these buffers would have both been used to make */
/* it this far. */
FR(lasti);
FR(lasto);
R;
}
/* this function is for printing arguments passed to it, mainly for the */
/* purpose of GTK/ncurses support, so it can be directed. */
V nsprint(C *format,...){
SI I i=0;
/* nothing should get this big, but its virtually the max used anywheres */
/* in netscript. */
U I j=(BASE_BUFFER*8);
C *display;
VAL ap;
/* small fixed font to use. */
#ifdef GTK
GdkFont *gf;
GdkColormap *gcm;
GdkColor gc;
#endif
/* return if backgrounded or malloc() failed. */
IF(isbga||!(display=(C *)M(j)))
R;
W(1){
VAS(ap,format);
i=VS(display,j,format,ap);
VAE(ap);
IF(i>-1&&i<j){
/* send to gui window instead, if in gui mode. */
#ifdef GTK
IF(isgui&&isagui){
gcm=gdk_colormap_get_system();
gc.red=guic[0];
gc.green=guic[1];
gc.blue=guic[2];
IF(!gdk_color_alloc(gcm,&gc))
pe("could not allocate color for the gui",1);
E{
GTE();
/* nice, and standard font. like fixed. */
IF(!isbgui)
gf=GFL(GUI_FONT);
gtk_text_insert(GTK_TEXT(gte),(isbgui?0:gf),(isguic?&gc:0),0,display,
SL(display));
GTL();
}
}
E
#endif
#ifdef NCURSES
{
IF(isncurses){
NWP(nfocus,"%s",display);
NRE(nfocus);
/* default (back) to main window. */
nfocus=nw3;
}
E
P("%s",display);
}
#else
P("%s",display);
#endif
FR(display);
R;
}
IF(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<SL(in);i++){
/* 0 = character, 1 = hex, 2 = decimal. */
IF(displaytype==1)
SP(&chrdump[k],"\\x%.2x",in[i]);
E
SP(&chrdump[k],"%.3d%c",in[i],((i+1)!=SL(in))?0x20:0x0);
k+=4;
}
}
/* make the chrdump buffer a standard character buffer if no dispalytype to */
/* wordwrap up later. */
IF(!displaytype){
IF(!(chrdump=(C *)SDU(in)))
pe("pd(): duplication of memory error",1);
}
B(prompt,4);
IF(!io&&!nossend)
SP(prompt,"-> ");
EI(io&&!nosrecv)
SP(prompt,"<- ");
IF(!nowrap){
B(line,(size+1));
F(i=0;i<SL(chrdump);i++){
IF(!SL(line))
SP(line,"%s",!nofrom?prompt:"");
/* next two checks are impossible to effect hex, or dec dumps. */
/* makes sure tabs do not screw up the wordwrap. */
IF(chrdump[i]==0x09)
/* 7 spaces = 1 tab(sort of, at a tab max), if it is beyond the buffer */
/* size the tab will get cut off. does not handle like a tab does. */
F(j=0;(j<7&&!(SL(line)>=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(log&&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<j){
/* could fail to write. if it does, it probably was not a superuser, */
/* which is all that is desired to be logged anyways. */
SLG(LOG_WARNING,"%s",wlog);
FR(wlog);
R;
}
IF(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;j<SL(dump);j++){
IF(dump[j]==0x0A){
tmpdump[i]=0x0;
nsprint("%s\n",tmpdump);
B(tmpdump,(SL(dump)+1));
i=0;
}
E
tmpdump[i++]=dump[j];
}
IF(SL(tmpdump)){
tmpdump[i]=0x0;
nsprint("%s",tmpdump);
}
/* no need to zero out the buffer since it is going to be free'd next. */
}
}
FR(tmpdump);
R;
}
/* this is for use with dumping a programs output to the socket. also, */
/* used for the $` execution comparison variable. */
V dumpexec(C *path,U SH type){
U SH r=0;
U SH s=0;
U I i=0;
U I j=0;
U I k=0;
/* to be duplicated. */
I fd[2];
PT fp;
/* will wrap if needed to this size. */
U C eread[(BASE_BUFFER*8+1)];
/* temporary buffer must be as big as its counterpart. */
U C ereadl[(BASE_BUFFER*8+1)];
/* timeout of waiting for input. */
S timeval tv;
/* for select(). */
fd_set ffd;
/* set to null, in case anything fails before anything actually happens. */
IF(type){
FR(execformat);
IF(!(execformat=(C *)SDU("(null)")))
pe("dumpexec(): duplication of memory error",1);
}
/* just incase of setuid/setgid. */
#ifdef GTK
IF(isgui){
pe("can not execute third party programs while in gui/gtk mode",0);
R;
}
#endif
#ifndef DISABLE_SYSLOG
wrso("%d-%d id: %lu-%u.%u.%u.%u exec: %s",slnum_t,(slnum_s++),cpid,GU(),GEU(),
GG(),GEG(),path);
#endif
IF(!noshowp&&!type)
pe("entering execution dump, incoming data suspended",0);
IF(isprivileged)
pe("third party programs can not be executed with privileged access",0);
E{
/* pair the two duplicate fd's. */
IF(socketpair(PF_UNIX,SOCK_STREAM,0,fd)==-1){
pe("execution dump failed, incoming data resumed",0);
R;
}
SW(fp=FK()){
CS -1:
pe("execution dump failed, incoming data resumed",0);
CL(fd[0]);
CL(fd[1]);
BR;
CS 0:
/* close, and duplicate the fd's. if netscript is in the background */
/* this will not want to be evaluated. */
IF(!isbga){
CL(0);
CL(1);
CL(2);
}
/* this will allow interaction inside the program, stdin->socket. */
/* 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<SL(eread));i++){
IF(eread[i]==0x0A||eread[i]==0x0D||j>=(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(log&&!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. */
(isudp?sock:ssock)=SK(AF_INET,(isudp?SOCK_DGRAM:SOCK_STREAM),(isudp?
IPPROTO_UDP: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(log&&!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;i<tot_i;i++){
IF(rs_static[i]>1)
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<SL(iread);o++)
IF(iread[o]==0x0A)
iread[o]=0x0;
IF(!noshowp)
pe("input received, incoming data resumed",0);
IF(!nossend)
pd(iread,0,columns);
wro(iread,SL(iread),0);
wro("\n",1,0);
IF(log&&!tnetraw)
logdata(iread,0);
}
FC(ifd);
}
#ifdef GTK
}
#endif
}
E{
/* sends the initial data supplied by the argument if supplied. */
IF(!nossend)
pd(iswrite,0,columns);
wro(iswrite,SL(iswrite),0);
wro("\n",1,0);
/* add the initial data to the log, if enabled. (-i, and -l option) */
IF(log&&!tnetraw)
logdata(iswrite,0);
}
}
IF(runcmd)
dumpexec(execfile,0);
IF(alrm)
A(alrm);
W(1){
B(sread,(BASE_BUFFER*4+1));
IF(!RD(sock,sread,(SO(sread)-1))){
pe("socket reading halted/finished",0);
closesocket(0);
R;
}
/* handle incoming telnet dumping. (-y, and -Y options) */
dumptelnet(sread);
IF(log&&tnetraw)
logdata(sread,3);
/* check, and use the ns_incoming_raw() symbol. it passes the raw dump of */
/* the socket read buffer, the size of the buffer, and the length of the */
/* buffer. (char *, int, int) */
#ifndef DISABLE_MODULES
IF(vmodule)
(*incoming_raw_function)(sread,SO(sread),SL(sread));
#endif
F(i=0;i<SL(sread);i++){
/* telnet protocol handling, bytes set before handled. */
/* using this method will have socket reading not wait for a \r, or a \n. */
/* (the -T option) */
IF(tnet&&sread[i]==0xFF&&sread[i+1]&&sread[i+2]){
B(telnet,3);
telnet[0]=0xFF;
IF(sread[i+1]==0xFC||sread[i+1]==0xFB)
telnet[1]=0xFE;
EI(sread[i+1]==0xFE||sread[i+1]==0xFD)
telnet[1]=0xFC;
IF(telnet[1]==0xFE||telnet[1]==0xFC){
/* checks to change socket handling for later. */
IF(!truetnet){
pe("received a telnet protocol option, entering telnet reading mode",0);
truetnet=1;
}
/* the option. */
telnet[2]=sread[i+2];
wro(telnet,SO(telnet),0);
IF(!nossend&&!notnetopt)
nsprint("%s(TELNETD-OPT REPLIED: 0x%.2x 0x%.2x 0x%.2x -> 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(log&&!tnetraw)
logdata(sreadl,1);
/* reset the temporary variable. */
IF(stoprules==2)
stoprules=0;
F(k=0;k<tot_i&&SL(sreadl);k++){
/* have not formed the swrite buffer yet, read the output for the */
/* start variable, no need to modify anything yet anyways. */
IF((!stoprules||!SNCC(output[k],NS_START,SL(NS_START)))&&!prewordmatch(
input[k],sreadl)&&!(rs_static[k]&&rs_dynamic[k])){
/* cancel possibility of a repeated rule. */
IF(rs_static[k]){
IF(!noshowp)
pe("ruleset defined this rule to only be used once",0);
rs_dynamic[k]=1;
}
IF(rs_delay[k]){
IF(!noshowp)
pe("ruleset defined a delay before processing of this rule",0);
SLP(rs_delay[k]);
}
/* parse the arguments input->output, $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;o<SL(iwrite);o++)
IF(iwrite[o]==0x0A)
iwrite[o]=0x0;
IF(!noshowp)
pe("input received, incoming data resumed",0);
IF(!nossend)
pd(iwrite,0,columns);
wro(iwrite,SL(iwrite),0);
wro("\n",1,0);
IF(log&&!tnetraw)
logdata(iwrite,0);
FC(ifd);
}
#ifdef GTK
}
#endif
}
/* check, and handle the remove/replace variable. */
EI(!SNCC(swrite,NS_TRUNC,SL(NS_TRUNC))){
/* changes buffer to dump the variable. for later use. */
truncateoutput(SL(NS_TRUNC));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
/* has to have at least one character to remove. */
IF(SL(swrite)==1){
F(l=0;l<SL(sreadl);l++)
IF(sreadl[l]==swrite[0]){
/* push the rest of the line back. */
F(m=(l+1);m<SL(sreadl);m++){
sreadl[(m-1)]=sreadl[m];
}
/* remove the leftover byte. */
sreadl[(m-1)]=0x0;
/* possibly a new character is here. */
l--;
}
}
/* two, or more replaces. instead of removal. */
EI(SL(swrite)>1)
F(l=0;l<SL(sreadl);l++)
IF(sreadl[l]==swrite[0])
sreadl[l]=swrite[1];
}
EI(!SNCC(swrite,NS_TOKENL,SL(NS_TOKENL))){
/* changes buffer to dump the variable. for later use. */
truncateoutput(SL(NS_TOKENL));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
IF(SL(swrite)>0)
/* using the int again here. */
F(l=0;l<SL(sreadl);l++)
IF(sreadl[l]==swrite[0])
sreadl[l]=0x0;
}
EI(!SNCC(swrite,NS_TOKENR,SL(NS_TOKENR))){
/* changes buffer to dump the variable. for later use. */
truncateoutput(SL(NS_TOKENR));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
IF(SL(swrite)>0){
/* using the int(s) again here. */
F(m=l=0;l<SL(sreadl);l++){
IF(m)
sreadl[(l-m)]=sreadl[l];
IF(sreadl[l]==swrite[0]&&!m)
m=(l+1);
}
IF(m)
sreadl[(l-m)]=0x0;
}
}
/* check, and handle the display variable. */
EI(!SNCC(swrite,NS_STR,SL(NS_STR))){
/* changes buffer to dump the variable. for later use. */
truncateoutput(SL(NS_STR));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
/* check for the comma with data, so atoi() will not fault. */
IF(!parameter(swrite,0,0x2C))
left=AI(parm);
/* only happens if the variable is by itself. */
E
left=0;
IF(!parameter(swrite,1,0x2C))
right=AI(parm);
/* also, only happens if the variable is by itself. */
E
right=-1;
/* can not be less than zero. or, should not be. */
IF(left<0)
left=0;
/* commonly thought that negative values equal to the end of the */
/* line. agree with the standard. */
IF(right<0||right>SL(sreadl))
right=SL(sreadl);
F(r=q=0;q<SL(sreadl);q++){
/* starts at point(left). but, stops before point(right). */
IF(q>=left&&q<right)
sreadl[r++]=sreadl[q];
}
sreadl[r]=0x0;
}
/* check, and handle the format variable. */
EI(!SNCC(swrite,NS_FMT,SL(NS_FMT))){
/* changes buffer to dump the variable. for later formatting. */
truncateoutput(SL(NS_FMT));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
/* clean it out. */
B(sreadl,(BASE_BUFFER*16+1));
/* byte-by-byte transfer/check. */
F(p=0;((p<(SO(sreadl)-1))&&(p<(SL(swrite))));p++)
sreadl[p]=swrite[p];
sreadl[p]=0x0;
}
/* check, and handle the display variable. */
EI(!SNCC(swrite,NS_ECHO,SL(NS_ECHO))){
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_ECHO));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
/* no possibility of format bug, pe() handles like text. */
/* ruleset defined this, so -C will not cut this off. */
pe(SL(swrite)?swrite:"ruleset defined an empty display rule",0);
}
/* check, and handle the no return write (raw) variable. */
/* shows up like a standard write out. */
EI(!SNCC(swrite,NS_RAW,SL(NS_RAW))){
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_RAW));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
IF(!nossend)
pd(swrite,0,columns);
wro(swrite,SL(swrite),0);
}
/* check, and handle the disable rule variable. */
EI(!SNCC(swrite,NS_DISABLE,SL(NS_DISABLE))){
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_DISABLE));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
IF(SL(swrite)){
l=AI(swrite);
IF(l<tot_i){
IF(!noshowp)
pe("ruleset defined a rule to be disabled",0);
rs_dynamic[l]=1;
/* if the value is two. so, it will get reset every connection. */
/* will be three if its already set to go off. */
IF(rs_static[l]<=1)
rs_static[l]+=2;
}
E
IF(!noshowp)
pe("ruleset defined a non-existent rule to be disabled",0);
}
}
/* check, and handle the file dump variable. */
EI(!SNCC(swrite,NS_DUMP,SL(NS_DUMP))){
IF(isprivileged)
pe("can not read/dump data from a file with privileged access",0);
E{
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_DUMP));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
#ifndef DISABLE_SYSLOG
wrso("%d-%d id: %lu-%u.%u.%u.%u read: %s",slnum_t,(slnum_s++),cpid,
GU(),GEU(),GG(),GEG(),swrite);
#endif
IF(AC(swrite,R_OK))
pe("could not access the file requested to dump in the ruleset",0);
E{
IF(!(dfd=FO(swrite,"r")))
pe("file requested by ruleset does not appear to exist, or is not re"
"adable",0);
E{
B(dread,(BASE_BUFFER*4+1));
/* no need to parse the data that comes from this file, instead it */
/* directly dumps the file data. single byte writing for all */
/* character types. */
IF(!noshowp)
pe("ruleset requested a file dump to the remote host",0);
W((n=FG(dfd))!=EOF){
sb[0]=n;
wro(sb,1,0);
}
IF(!noshowp)
pe("ruleset requested file dump was successful",0);
}
FC(dfd);
}
}
}
/* check, and handle the write/append variable. checks for append */
/* first, beacuse if one variable is going to be larger it will be */
/* the apppend variable. */
EI(!SNCC(swrite,NS_WRITE,SL(NS_WRITE))||!SNCC(swrite,NS_APPEND,
SL(NS_APPEND))){
IF(isprivileged)
pe("can not write data to a file with privileged access",0);
E{
/* find out which variable it is, two in one function here. */
IF(!SNCC(swrite,NS_APPEND,SL(NS_APPEND))){
n=SL(NS_APPEND);
/* append type, fopen(). */
sb[0]=0x61;
}
E{
n=SL(NS_WRITE);
/* write type, fopen(). */
sb[0]=0x77;
}
/* changes buffer to dump the variable. for later display. */
truncateoutput(n);
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
#ifndef DISABLE_SYSLOG
wrso("%d-%d id: %lu-%u.%u.%u.%u write: %s",slnum_t,(slnum_s++),cpid,
GU(),GEU(),GG(),GEG(),swrite);
#endif
/* check for existence with non-writability. */
IF(!AC(swrite,F_OK)&&AC(swrite,W_OK))
pe("could not access the file requested to write to in the ruleset",
0);
E{
IF(!(dfd=FO(swrite,sb)))
pe("file requested to write to could not be opened properly",0);
E{
FP(dfd,"%s\n",sreadl);
IF(!noshowp)
pe("ruleset requested write out was successful",0);
}
FC(dfd);
}
}
}
/* check, and handle the chdir variable. */
EI(!SNCC(swrite,NS_CHDIR,SL(NS_CHDIR))){
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_CHDIR));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
IF(SL(swrite)){
IF(CD(swrite)){
IF(!noshowp)
pe("ruleset requested directory change failed",0);
}
E{
IF(!noshowp)
pe("ruleset requested directory change was successful",0);
}
}
}
/* check, and handle the (send to) route host variable. */
EI(!SNCC(swrite,NS_ROUTE,SL(NS_ROUTE))){
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_ROUTE));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
IF(SL(swrite)){
IF(rsock==-1){
IF(!noshowp)
pe("rulset requested route write failed, no (open) route socket",0);
}
E{
wro(swrite,SL(swrite),2);
wro("\n",1,2);
IF(!noshowp)
pe("ruleset requested route write was successful",0);
}
}
}
/* check, and handle the time passed (send) variable. */
EI(!SNCC(swrite,NS_TIMED,SL(NS_TIMED))){
/* set the current time to check the value, compared to the */
/* connection value. */
TM(&ctm);
/* changes buffer to dump the variable. for later display. */
truncateoutput(SL(NS_TIMED));
/* update the new clean buffer. */
parseoutput(sreadl,swrite);
parameter(swrite,0,0x2C);
IF(wischeck(parm,1)&&(rtm+AI(parm))<ctm){
IF(SL(swrite)>(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(log&&!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;i<SL(iread);i++){
IF(iread[i]==0x0A||iread[i]==0x0D)
iread[i]=0x0;
/* apply question marks to unprintable characters. */
IF(iread[i]&&!isprint(iread[i]))
iread[i]=0x3F;
}
}
/* will close the stream below, now that its finished. */
EI(s)
s=0;
}
IF(!s)
FC(ifd);
/* command handling. */
IF(!SNCC(iread,"anotify",7)){
noshowa=(noshowa?0:1);
nsprint("anotify: %sabled\n",(noshowa?"en":"dis"));
}
EI(!SNCC(iread,"background",10)){
isbg=(isbg?0:1);
nsprint("background: %sabled\n",(isbg?"en":"dis"));
}
EI(!SNCC(iread,"bind",4)){
IF(sethost)
nsprint("bind: there are hostname(s) defined to connect to, can not define"
".\n");
E{
bindmode=(bindmode?0:1);
nsprint("bind: %sabled\n",(bindmode?"en":"dis"));
}
}
EI(!SNCC(iread,"chdir",5)){
IF(!parameter(iread,1,0x20)){
IF(setcdir)
FR(cdir);
parsecmdline(parm);
IF(!(cdir=(C *)SDU(parsedline)))
pe("iface(): duplication of memory error",1);
setcdir=1;
}
nsprint("chdir: %s\n",(setcdir?cdir:IFACE_UNSET));
}
EI(!SNCC(iread,"chroot",6)){
IF(!parameter(iread,1,0x20)){
IF(setrdir)
FR(rdir);
parsecmdline(parm);
IF(!(rdir=(C *)SDU(parsedline)))
pe("iface(): duplication of memory error",1);
setrdir=1;
}
nsprint("chroot: %s\n",(setrdir?rdir:IFACE_UNSET));
}
EI(!SNCC(iread,"cnotify",7)){
noshowc=(noshowc?0:1);
nsprint("cnotify: %sabled\n",(noshowc?"en":"dis"));
}
EI(!SNCC(iread,"disparrows",10)){
nofrom=(nofrom?0:1);
nsprint("disparrows: %sabled\n",(nofrom?"en":"dis"));
}
EI(!SNCC(iread,"dispincoming",12)){
nosrecv=(nosrecv?0:1);
nsprint("dispincoming: %sabled\n",(nosrecv?"en":"dis"));
}
EI(!SNCC(iread,"dispoutgoing",12)){
nossend=(nossend?0:1);
nsprint("dispoutgoing: %sabled\n",(nossend?"en":"dis"));
}
EI(!SNCC(iread,"disptype",8)){
IF(displaytype++>1)
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;k<isguil;k++)
FR(gblabel[k]);
isguil=0;
}
parsecmdline(parm);
W(!parameter(parsedline,isguil,0x3A)&&isguil<3){
IF(!(gblabel[isguil++]=(C *)SDU(SL(parm)?parm:"nolabel")))
pe("iface(): duplication of memory error",1);
}
}
nsprint("guititle: %s%s\n",(isguil?gblabel[0]:IFACE_UNSET),(isguil>1?
" <...>":""));
}
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<tshs;k++)
FR(shost[k]);
tshs=0;
}
parsecmdline(parm);
W(!parameter(parsedline,tshs,0x2C)){
IF(!(shost[tshs++]=(C *)SDU(SL(parm)?parm:"0")))
pe("iface(): duplication of memory error",1);
IF(tshs>=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(log)
FR(logfile);
parsecmdline(parm);
IF(!(logfile=(C *)SDU(parsedline)))
pe("iface(): duplication of memory error",1);
log=1;
}
nsprint("logfile: %s\n",(log?logfile:IFACE_UNSET));
}
}
#ifdef NCURSES
EI(!SNCC(iread,"ncurseslabel",12)){
IF(!parameter(iread,1,0x20)){
IF(isncursesl){
F(k=0;k<isncursesl;k++)
FR(nclabel[k]);
isncursesl=0;
}
parsecmdline(parm);
W(!parameter(parsedline,isncursesl,0x3A)&&isncursesl<2){
IF(!(nclabel[isncursesl++]=(C *)SDU(SL(parm)?parm:"nolabel")))
pe("iface(): duplication of memory error",1);
}
}
nsprint("ncurseslabel: %s%s\n",(isncursesl?nclabel[0]:IFACE_UNSET),
(isncursesl>1?" <...>":""));
}
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> <data>\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<SL(iread);i++)
iread[(i-1)]=iread[i];
iread[(i-1)]=0x0;
SW(fp=FK()){
CS -1:
nsprint("!: fork() failed.\n");
BR;
CS 0:
/* allow aborts to be handled, since its passed over to the program. */
SG(SIGINT,SIG_DFL);
EL(eshell,eshell,(SL(iread)?"-c":0),(SL(iread)?iread:0),0);
_exit(1);
BR;
default:
/* wait up. */
WP(fp,0,0);
BR;
}
}
}
EI(!SNCC(iread,"help",4)){
nsprint("anotify\t\t\t\t- disables display of all netscript comments.\n"
"background\t\t\t- sends netscript to the background.\n"
"bind\t\t\t\t- binds to the supplied port.\n"
"chdir\t\t<directory>\t- changes the working directory of netscript.\n"
"chroot\t\t<directory>\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<file>\t\t- dumps the program data to the socket.\n"
"execinteractive\t\t\t- will allow interactive use of programs.\n"
"execpre\t\t<data>\t\t- precurse data to attach for each line dumped.\n"
"execshell\t<file>\t\t- will use an alternate shell for executions.\n"
"execwait\t<second(s)>\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<ffffff>\t- sets a text foreground color for the gui.\n"
"guilabel\t<l1:l2:l3>\t- defines button labels for the gui.\n"
"guipd\t\t\t\t- automatically start pulled down. (non-generic)\n"
"guipdlen\t<size>\t\t- increase the length of the gui. (non-generic)\n"
"guititle\t<title>\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(log)
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(log)
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(!log){
parsecmdline(optarg);
IF(!(logfile=(C *)SDU(parsedline)))
pe("main(): duplication of memory error",1);
log=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 */