1 /* [ NETSCRIPT: lightweight tcp/udp socket scripting -- version 1.7.1 ] ******
2  * (portable/multi-platform) lightweight tcp/udp socket scripting.  intended *
3  * for (non-)experienced persons to be able to use to automate situations,   *
4  * built on a word-to-word ruleset response system.  includes wildcard       *
5  * support, character replacement, random replacement, argument inclusion,   *
6  * server timeout, initial send, display altering, multiple character dump   *
7  * formats, telnet protocol support, logging, program to socket dumping,     *
8  * executable ruleset support, reverse binding, module support, data         *
9  * truncation, data formatting, permission options, virtual hosting support, *
10  * history storage, dynamic storage variables, directory placement,          *
11  * character omitting, timed rules, background support, syslog support,      *
12  * routing support, interactive mode, and a graphical user interface among   *
13  * other things.                                                             *
14  *                                                                           *
15  * AUTHOR:                                                                   *
16  *  v9@fakehalo.deadpig.org, fakehalo.deadpig.org. (* version)               *
17  *                                                                           *
18  * COMPILE:                                                                  *
19  *  system type(generic, multiple methods/possible combinations):            *
20  *   # gcc netscript.c -o netscript                                          *
21  *   # gcc netscript.c -o netscript -lc                                      *
22  *   # gcc netscript.c -o netscript -ldl                                     *
23  *   # gcc netscript.c -o netscript -rdynamic                                *
24  *   # gcc netscript.c -o netscript -DARPA                                   *
25  *   # gcc netscript.c -o netscript -DDISABLE_MODULES                        *
26  *   # gcc netscript.c -o netscript -DDISABLE_SRCIP                          *
27  *   # gcc netscript.c -o netscript -DDISABLE_SYSLOG                         *
28  *                                                                           *
29  *  system type(Linux):                                                      *
30  *   # gcc netscript.c -o netscript -lc -rdynamic -ldl -DARPA -DLINUX_T      *
31  *                                                                           *
32  *  system type(BSD):                                                        *
33  *   # gcc netscript.c -o netscript -lc -rdynamic -DARPA -DBSD_T             *
34  *   # gcc netscript.c -o netscript -lc -rdynamic -ldl -DARPA -DBSD_T        *
35  *                                                                           *
36  *  system type(IRIX):                                                       *
37  *   # gcc netscript.c -o netscript -lc -DARPA -DIRIX_T                      *
38  *                                                                           *
39  *  system type(SunOS/Solaris):                                              *
40  *   # gcc netscript.c -o netscript -lc -ldl -lnsl -lsocket -DARPA -DSUNOS_T *
41  *                                                                           *
42  *  note: append "-DGTK `gtk-config --cflags --libs gthread`" (if you have   *
43  *  GTK+ available on your system), and append "-DNCURSES -lcurses" (if you  *
44  *  have ncurses available on your system)                                   *
45  *                                                                           *
46  * BASIC TUTORIAL:                                                           *
47  *  the minimal command line requires -r(or -s), -h(or -b), and -p, like so: *
48  *                                                                           *
49  *   # ./netscript -r rulesetfile -h host.com -p port                        *
50  *                                                                           *
51  *  or, if you have it properly set up(like examples that come with the      *
52  *  package) you can run it like so:                                         *
53  *                                                                           *
54  *   # chmod +x rulesetfile                                                  *
55  *   # ./rulesetfile                                                         *
56  *                                                                           *
57  *  the ruleset file(-r argument) should contain a list similar to this:     *
58  * ------------------------------------------------------------------------- *
59  *  001 Started remote daemon.                                               *
60  *  USER test                                                                *
61  *  002 Enter password.                                                      *
62  *  PASS test                                                                *
63  * ------------------------------------------------------------------------- *
64  *  this ruleset file would send "USER test" upon receiving the data "001    *
65  *  Started remote daemon.", and "PASS test" upon receiving the data "002    *
66  *  Enter password."                                                         *
67  *                                                                           *
68  * EXTENDED TUTORIAL:                                                        *
69  *  using variables, and wildcard matches are also used.  this is taken from *
70  *  the basic tutorial ruleset file with some modifications:                 *
71  * ------------------------------------------------------------------------- *
72  *  001 $*                                                                   *
73  *  USER test                                                                *
74  *  002 $*                                                                   *
75  *  PASS test                                                                *
76  * ------------------------------------------------------------------------- *
77  *  this would send the same data as in the basic tutorial.  here is a list  *
78  *  of the wild card match variables, for use only with the input (line) of  *
79  *  the ruleset(use the -d option of netscript for more specifics):          *
80  *                                                                           *
81  *   $;     = placed at the beginning of the line, will match only if the    *
82  *            data following the variable does not match the input.          *
83  *            (wildcards apply, like a normal input rule)                    *
84  *   $*     = if words before match until the point this variable is used.   *
85  *   $?     = if anything fills a single word.                               *
86  *   $ALPHA = if the word is an alphabetical word.                           *
87  *   $DIGIT = if the word is a numerical word.                               *
88  *   $ALNUM = if the word is an alphabetical+numerical word.                 *
89  *   $UPPER = if the word is an upper case word.                             *
90  *   $LOWER = if the word is a lower case word.                              *
91  *   $PUNCT = if the word is a printable/non-standard word.                  *
92  *   $CNTRL = if the word is a control character word.                       *
93  *   $PRINT = if the word is a printable word.                               *
94  *   $####  = must be 4 digits exactly(# = numeric).  if the word is equal   *
95  *            in length to the value supplied. (for example: checking for a  *
96  *            length equal to 12 would be $0012)                             *
97  *   ${#}   = the dynamic storage variables can also be applied to checking  *
98  *            for wildcard matching on the input line.  if the word stored   *
99  *            in the dynamic variable, and the server data match. (where #   *
100  *            is a numerical value between 0-9)                              *
101  *                                                                           *
102  *  here is a list of the output (line) response variables:                  *
103  *                                                                           *
104  *   $@     = stops using the ruleset provided at the starting of netscript. *
105  *   $^     = restarts using ruleset provided at the starting of netscript.  *
106  *   $:     = stops ruleset reading once the rule is hit, single stop.       *
107  *   $!     = closes the socket once the rule is hit, cycling netscript.     *
108  *   $~     = prompts for data to send to the remote server.                 *
109  *   $/     = used to truncate data for use in rules to follow.  if only one *
110  *            character is provided after the variable it will truncate it.  *
111  *            if two, or more characters are provided it will take the       *
112  *            second character, and replace it with the first in the server  *
113  *            output.                                                        *
114  *   $]     = used to truncate data for use in rules to follow.  this        *
115  *            variable takes the character after the variable as a point     *
116  *            to cut the line off at, and tokenizes it to the left.  the     *
117  *            variable will use the first character point that occurs.       *
118  *   $[     = used to truncate data for use in rules to follow.  this        *
119  *            variable takes the character after the variable as a point     *
120  *            to cut the line off at, and tokenizes it to the right.  the    *
121  *            variable will use the first character point that occurs.       *
122  *   $,     = used to truncate data for use in the rules to follow.  this    *
123  *            variable is used with two arguments separated by a comma       *
124  *            between two numbers.  the first number is taken as a start     *
125  *            point, and the second number is taken as a stop point.         *
126  *   $|     = used to format data for use in the rules to follow.  this will *
127  *            take the output line, and replace the input line with it.  for *
128  *            use in rules to come.                                          *
129  *   $%     = echo/displys text to the local host.                           *
130  *   $_     = sends the provided data without CR(0x0A/\n).                   *
131  *   $-     = uses rule only once, you can use other variables with this.    *
132  *   $.     = disables another rule.  by placing a numerical value equal to  *
133  *            that of the rule to disable after the variable.                *
134  *   $<     = dumps the supplied file after the variable to the socket.      *
135  *   $>     = writes the info that matched to the supplied file after the    *
136  *            variable.                                                      *
137  *   $+     = appends the info that matched to the supplied file after the   *
138  *            variable.                                                      *
139  *   $'     = changes the current working directory to the supplied          *
140  *            directory after the variable.                                  *
141  *   $\     = writes data after the variable to the route host, if used.     *
142  *   $"     = only writes data to the socket if the specified time has       *
143  *            passed.  data is separated by a comma. (seconds,senddata)      *
144  *   $=     = dumps the execution data of the supplied file after the        *
145  *            variable to the socket. (runs the program)                     *
146  *   $`     = dumps the first line from the execution data of the supplied   *
147  *            file after the variable to the input line. (formatted use)     *
148  *   $##### = must be 5 digits exactly(# = numeric).  this variable must be  *
149  *            tagged on the end of an output line(the last data on the line) *
150  *            to work, it sleeps the time of the value supplied. (for        *
151  *            example: $00012 would sleep 12 seconds)                        *
152  *                                                                           *
153  *  note: anything attached after for $@, $^, $:, $!, $~, $/, $], $[, $,,    *
154  *  $|, $%, $_, $-, $., $<, $>, $+, $', $\, $", $=, and $` will be used for  *
155  *  either text/display, information, truncation/modifcation, or a filename. *
156  *  dependant on the type of variable being used.  (in $-'s case, the rule   *
157  *  to be used one time.  $- requires data after it to be taken as a         *
158  *  variable, and can be used with other pre-variables)                      *
159  *                                                                           *
160  *  now, here is an example of a numerical variable in a new ruleset:        *
161  * ------------------------------------------------------------------------- *
162  *  001 Daemon ready.                                                        *
163  *  USER test                                                                *
164  *  002 Sorry, user $? needs a password.                                     *
165  *  USER $3 mypasswd                                                         *
166  * ------------------------------------------------------------------------- *
167  *  as you can see, once the ruleset sees "001 Daemon ready." it sends "USER *
168  *  test".  but, the format is USER <user> <pass> on this daemon.  so, upon  *
169  *  receiving the error it sends the 3rd argument from the error message as  *
170  *  the <user> argument, which should be the same username.  this is not     *
171  *  practical.  but, an example.  here are the numerical, and replacement    *
172  *  variables.  for use with all aspects of the ruleset(use the -d option of *
173  *  netscript for more specifics):                                           *
174  *                                                                           *
175  *   $#       = given argument responses, from the server.  this is output   *
176  *              only. (where "#" is a numerical value between 0-9.  $#- will *
177  *              dump the rest of the line.  for example: $0-)                *
178  *   $##      = hex->character replacement. (where "##" is 01-FF)            *
179  *   $###     = dec->character replacement. (where "###" is 001-255)         *
180  *   $&       = random alphabetical character replacement.                   *
181  *   $#       = random numerical character replacement. (where # = #)        *
182  *   $REPEAT  = must be the only thing on the input/output line.  this       *
183  *              variable will do the same thing as the corresponding         *
184  *              input/output variable does before it.                        *
185  *                                                                           *
186  *  when using dynamic storage variables on the output line, you can set     *
187  *  them one of two ways.  one way is in the ruleset by using "${#}=value"   *
188  *  on the output line of a rule, the value can contain formatted data.      *
189  *  the other way to set data is via the command line.  by using the command *
190  *  line options(s) "-#" you can statically set the variable with the data   *
191  *  that follows the argument.  these dynamic variables can be used on the   *
192  *  output line, or the input line(wildcard checking) by using "${#}"        *
193  *  anywheres on the line.  these variables will be reset upon               *
194  *  disconnection, unless they are statically set by the command line        *
195  *  option(s). (where "#" is a numerical value between 0-9)                  *
196  *                                                                           *
197  *  here is an example of dynamic variables can be used in a ruleset:        *
198  * ------------------------------------------------------------------------- *
199  *  $? $?                                                                    *
200  *  ${0}=$0 and $1                                                           *
201  *  $? $?                                                                    *
202  *  you said ${0}, my home directory is: ${1}.                               *
203  * ------------------------------------------------------------------------- *
204  *  this example would require you to use the command line argument "-1      *
205  *  $HOME" to statically define the home directory to ${1}.                  *
206  *                                                                           *
207  * ENVIRONMENT:                                                              *
208  *  $NS_CMDLINE                                                              *
209  *   this environmental variable will take the data in the variable as a     *
210  *   command line, it has priority over typical command line usage.  but,    *
211  *   will not override +x files.                                             *
212  *                                                                           *
213  *  $NS_TIMEOUT                                                              *
214  *   this environmental variable will take the data in the variable as a     *
215  *   timeout to give up on connecting to a remote host. (2 minutes is the    *
216  *   default if no environmental variable is used)                           *
217  *                                                                           *
218  *  $NS_MODULE                                                               *
219  *   this environmental variable will take the data in the variable as a     *
220  *   path to a file.  this path should be a shared library containing        *
221  *   ns_init(), ns_exit(), ns_connect(), ns_incoming(), ns_incoming_char(),  *
222  *   ns_incoming_raw(), and ns_outgoing().                                   *
223  *                                                                           *
224  *  $NS_HOST                                                                 *
225  *   this environmental variable will take the data in the variable as a     *
226  *   virtual hostname, or ip to use.  this will apply to both outgoing,      *
227  *   and incoming connections.                                               *
228  *                                                                           *
229  *  $NS_BACKLOG                                                              *
230  *   this environmental variable will take the data in the variable as a     *
231  *   maximum number of connections to allow to have pending. (if the -b      *
232  *   option is supplied)                                                     *
233  *                                                                           *
234  *  $NS_PATH                                                                 *
235  *   this environmental variable will take the data in the variable as a     *
236  *   path string.  this path string should be similar to that of the $PATH   *
237  *   environmental variable.  it will list the file(s) in the provided       *
238  *   path(s), and allow quick use of (internal argument supplied)            *
239  *   ruleset(s).                                                             *
240  *                                                                           *
241  *  $COLUMNS                                                                 *
242  *   this environmental variable will take the data in the variable as a     *
243  *   maximum number of characters to print per line for input/output         *
244  *   displaying. (if the -w option is not supplied)                          *
245  *                                                                           *
246  *  $SHELL                                                                   *
247  *   this environmental variable will take the data in the variable as a     *
248  *   shell to use for execution of third party programs. (-O overrides)      *
249  *                                                                           *
250  *  $EDITOR                                                                  *
251  *   this environmental variable will take the data in the variable as a     *
252  *   program to use as a text editor, to make temporary rulesets.            *
253  *                                                                           *
254  * BUGS:                                                                     *
255  *  there is a known bug in the handling of the telnet protocol that can not *
256  *  be fixed, and keep functionality.  it occurs when incoming data is       *
257  *  broken into multiple segments, netscript will not process these segments *
258  *  like it should.  it will break them into two, or more different rule     *
259  *  readings.  if netscript were to wait for the following segment(s) to     *
260  *  make a single rule reading it would limit the possibility of reading     *
261  *  prompts, and other non-CR/LF situations.  the -y, and -Y options will    *
262  *  clean up the appearance of the broken segments.  but, it will not apply  *
263  *  to the handling of the ruleset.                                          *
264  *                                                                           *
265  * SECURITY:                                                                 *
266  *  there is possible security condition that can occur.  if you do not      *
267  *  properly setup your ruleset it is possible for the remote host to run    *
268  *  ruleset variables, including the execution variable.  this is more       *
269  *  thought of as a perk.  but, if an unknowning person makes a              *
270  *  misconfigured ruleset it could result in exploitation.  the condition    *
271  *  occurs when you place a user supplied value at the beginning of the      *
272  *  output line.  for example, "$0-" at the start of the output line could   *
273  *  result in the remote host sending "$=/bin/rm -rf /".                     *
274  *                                                                           *
275  *  if this is a major concern, simply add a truncation variable at the top  *
276  *  of your ruleset to take effect on all rules.  like "$/$" to filter out   *
277  *  "$"'s, or "$[$" to take out everything before the first "$"(including    *
278  *  the "$").                                                                *
279  *                                                                           *
280  * FILES:                                                                    *
281  *  files used, or related to netscript use:                                 *
282  *   ~/.nshistory  = used to store, read, and use past arguments.            *
283  *   ~/.nsrc       = used to precurse any other interactive commands.        *
284  *   /dev/tty      = used to read standard input. (if ttyname() fails)       *
285  *   /etc/group    = used for the -u option to convert names to ids.         *
286  *   /etc/passwd   = used like /etc/group, and for using the home directory. *
287  *   /etc/services = used for the -p option to convert services to ports.    *
288  *                                                                           *
289  * COMMENTS:                                                                 *
290  *  like most things, i perfer things to be portable.  so i made this around *
291  *  a single file.  other files are not needed for netscript to run          *
292  *  properly.  i tried to make netscript as basic as possible, with minimal  *
293  *  usage of uncommon functions, so it can be easily portable.  platform to  *
294  *  platform.  if you do not understand the proper way to make a ruleset,    *
295  *  you may want to consult the packaged netscript(if this is not already    *
296  *  from the packaged netscript) for examples of usage.                      *
297  *                                                                           *
298  * netscript.c: program source code for netscript.    (5346l!19588w!175695b) *
299  *****************************************************************************/
300 #ifdef ARPA
301 #include <arpa/inet.h> /* socket related. */
302 #endif
303 #include <ctype.h> /* for wildcard (character) wordmatching. */
304 #ifdef NCURSES
305 #include <curses.h> /* ncurses/gui related. */
306 #endif
307 #ifndef DISABLE_MODULES
308 #include <dlfcn.h> /* dynlink/module usage. */
309 #endif
310 #include <errno.h> /* error display. */
311 #ifdef GTK
312 #include <glib.h> /* gui related. */
313 #endif
314 #include <glob.h> /* list related. */
315 #include <grp.h> /* get group names/gids. */
316 #ifdef GTK
317 #include <gtk/gtk.h> /* gui related. */
318 #endif
319 #include <netdb.h> /* socket related. */
320 #include <netinet/in.h> /* socket related. */
321 #ifdef GTK
322 #include <pthread.h> /* gui (incorporated) related. */
323 #endif
324 #include <pwd.h> /* get passwd names/uids. */
325 #include <stdarg.h> /* format uses. */
326 #include <stdio.h> /* multiple uses. */
327 #include <stdlib.h> /* multiple uses. */
328 #include <signal.h> /* to handle signals.  ctrl-c, memory errors, etc. */
329 #include <string.h> /* multiple uses. */
330 #include <strings.h> /* multiple uses. */
331 #include <sys/socket.h> /* socket related. */
332 #include <sys/stat.h> /* umask related. */
333 #include <sys/time.h> /* log/etc. times. */
334 #include <sys/types.h> /* socket related. */
335 #include <sys/utsname.h> /* uname related. */
336 #include <sys/wait.h> /* exec related. */
337 #ifndef DISABLE_SYSLOG
338 #include <syslog.h> /* system logging. */
339 #endif
340 #include <time.h> /* log/etc. times. */
341 #include <unistd.h> /* multiple uses. */
342 /* definitions, most can be changed.  but, not particularly recommended. */
343 #define VERSION "1.7.1" /* version information. */
344 #define MAX_ARGS 1024 /* total input/output slots allowed, combined. */
345 #define BASE_BUFFER 1024 /* generic buffer size, base for all increments. */
346 #define NOSRCIP "xxx.xxx.xxx.xxx" /* filler, if no ip options were defined. */
347 #define HISTFILE ".nshistory" /* history filename. (home directory) */
348 #define RCFILE ".nsrc" /* rc filename. (home directory) */
349 #define IFACE_PREFIX "netscript> " /* for interactive netscript, the prompt. */
350 #define IFACE_UNSET "<unset>" /* for interactive netscript, unset vaule(s). */
351 #define DFL_COLUMNS 80 /* default characters per line with in/out data. */
352 #define DFL_BACKLOG 1 /* default amount of connections to allow pending. */
353 #define DFL_TIMEOUT 120 /* default timeout for connection in seconds. (2min) */
354 #define DFL_EDITOR "/bin/vi" /* default ruleset editor, if no $EDITOR. */
355 #define PARAMETER_VAR_CHAR 0x24 /* identifier for args/convs/len checks, $. */
356 #define ENV_CMDLINE "NS_CMDLINE" /* env var treated as a command line. */
357 #define ENV_TIMEOUT "NS_TIMEOUT" /* env var for connection (to) timeout. */
358 #define ENV_MODULE "NS_MODULE" /* env var for module support. */
359 #define ENV_VHOST "NS_HOST" /* env var for using a virtual host. */
360 #define ENV_BACKLOG "NS_BACKLOG" /* env var for pending connections. (bind) */
361 #define ENV_PATH "NS_PATH" /* env var for file list selection. (--list) */
362 #define ENV_COLUMNS "COLUMNS" /* env var for in/out data line size. */
363 #define ENV_SHELL "SHELL" /* env var for executing third party programs. */
364 #define ENV_EDITOR "EDITOR" /* env var for text editor executable. . */
365 #ifdef GTK
366 #define GUI_MAXLEN 2048 /* maximum length to set the gui. (-+ option) */
367 #define GUI_FONT "-misc-fixed-*-*-*-*-8-*-*-*-*-*-*-*" /* regular gui font. */
368 #endif
369 #define NS_REPEAT "$REPEAT" /* pre-match, repeats the last in/out line. */
370 #define NS_ALL "$*" /* wildcard for any words after that point. */
371 #define NS_ANY "$?" /* wildcard for any word. */
372 #define NS_ALPHA "$ALPHA" /* wildcard for alphabet characters. */
373 #define NS_DIGIT "$DIGIT" /* wildcard for numeric characters. */
374 #define NS_ALNUM "$ALNUM" /* wildcard for alphabet, and numeric characters. */
375 #define NS_LOWER "$LOWER" /* wildcard for lower case words. */
376 #define NS_UPPER "$UPPER" /* wildcard for upper case words. */
377 #define NS_PUNCT "$PUNCT" /* wildcard for punctuated words. */
378 #define NS_CNTRL "$CNTRL" /* wildcard for control character words. */
379 #define NS_PRINT "$PRINT" /* wildcard for printable words. */
380 #define NS_NMATCH "$;" /* (no) comparison match. (input rule, unique) */
381 #define NS_STOP "$@" /* pre-match, stops using the ruleset after this. */
382 #define NS_START "$^" /* pre-match, restarts using the ruleset after this. */
383 #define NS_HALT "$:" /* pre-match, stops the ruleset for one run. */
384 #define NS_QUIT "$!" /* pre-match, exits netscript if exact. */
385 #define NS_ASK "$~" /* pre-match, asks data to reply with. */
386 #define NS_TRUNC "$/" /* pre-match, removes, or replaces a character. */
387 #define NS_TOKENL "$]" /* pre-match, chomps data off after the char. (left) */
388 #define NS_TOKENR "$[" /* pre-match, chomps data off after the char. (right) */
389 #define NS_STR "$," /* pre-match, changes the string to set limits. */
390 #define NS_FMT "$|" /* pre-match, changes the format of the string. */
391 #define NS_ECHO "$%" /* pre-match, displays data after variable. */
392 #define NS_RAW "$_" /* pre-match, writes to the socket without \n. */
393 #define NS_ONCE "$-" /* pre-match, uses rule one time per connection. */
394 #define NS_DISABLE "$." /* pre-match, disables the use of another rule. */
395 #define NS_DUMP "$<" /* pre-match, dumps the following file to the socket. */
396 #define NS_WRITE "$>" /* pre-match, writes the match line to a file. */
397 #define NS_APPEND "$+" /* pre-match, appends the match line to a file. */
398 #define NS_CHDIR "$'" /* pre-match, change to the supplied directory. */
399 #define NS_ROUTE "$\\" /* pre-match, send data to the route host. ($\) */
400 #define NS_TIMED "$\"" /* pre-match, only send data if time has passed. ($") */
401 #define NS_EXEC "$=" /* pre-match, locally executes a file. */
402 #define NS_EXECF "$`" /* pre-match, locally executes a file for formatting. */
403 #define INPUTPATH "/dev/tty" /* if no ttyname(), this is the generic name. */
404 #define SHPATH "/bin/sh" /* if no $SHELL is set, this is the default shell. */
405 /* checks for defines.  if it never get defined, it puts generic. */
406 /* generated to Linux. */
407 #ifdef LINUX_T
408 #define COMPTYPE "lin-gen"
409 #endif
410 /* generated to BSD. */
411 #ifdef BSD_T
412 #undef COMPTYPE
413 #define COMPTYPE "bsd-gen"
414 #endif
415 /* generated to SunOS/Solaris. */
416 #ifdef SUNOS_T
417 #undef COMPTYPE
418 #define COMPTYPE "sns-gen"
419 #endif
420 /* generated to IRIX. */
421 #ifdef IRIX_T
422 #undef COMPTYPE
423 #define COMPTYPE "irx-gen"
424 #endif
425 /* no generation. */
426 #ifndef COMPTYPE
427 #define COMPTYPE "generic"
428 #endif
429 /* module related, headers are different on different os/dists. */
430 /* these define(s) should be included from dlfcn.h. */
431 #ifndef DISABLE_MODULES
432 #ifdef RTLD_NOW
433 #define RTLD_TYPE RTLD_NOW
434 /* this will do. */
435 #elif RTLD_LAZY
436 #define RTLD_TYPE RTLD_LAZY
437 /* this should never happen.  but, it should not be a problem. */
438 #else
439 #define RTLD_TYPE 1
440 #endif
441 #endif
442 /* these should not be changed at all, space savers.  more so, made to save */
443 /* me typing time.  i am lazy.  if anyone plans on reading this code other */
444 /* than myself, i am sorry.  but, filesize, and my laziness comes first. */
445 #define A alarm
446 #define AC access
447 #define AI atoi
448 #define AL atol
449 #define AT accept
450 #define B bzero
451 #define BI bind
452 #define BR break
453 #define C char
454 #define CD chdir
455 #define CL close
456 #define CO connect
457 #define CR chroot
458 #define CS case
459 #define CT ctime
460 #define D dup2
461 #define E else
462 #define EI else if
463 #define EL execl
464 #define EX extern
465 #define F for
466 #define FDO fdopen
467 #define FC fclose
468 #define FG fgetc
469 #define FK fork
470 #define FL FILE
471 #define FO fopen
472 #define FP fprintf
473 #define FR free
474 #define FS fgets
475 #ifdef GTK
476 #define GBPS gtk_box_pack_start
477 #define GC gchar
478 #define GCSBW gtk_container_set_border_width
479 #define GFL gdk_font_load
480 #define GHN gtk_hbox_new
481 #define GPT gpointer
482 #define GSC gtk_signal_connect
483 #define GTA gtk_table_attach
484 #define GTE gdk_threads_enter
485 #define GTL gdk_threads_leave
486 #define GVN gtk_vbox_new
487 #define GW GtkWidget
488 #define GWGF gtk_widget_grab_focus
489 #define GWH gtk_widget_hide
490 #define GWS gtk_widget_show
491 #define GWSU gtk_widget_set_usize
492 #endif
493 #define G getenv
494 #define GB glob
495 #define GBF globfree
496 #define GD gettimeofday
497 #define GEG getegid
498 #define GEU geteuid
499 #define GG getgid
500 #define GGG getgrgid
501 #define GH gethostbyname
502 #define GI gid_t
503 #define GP getpwnam
504 #define GPD getpid
505 #define GPN getpeername
506 #define GPPD getppid
507 #define GPU getpwuid
508 #define GR getgrnam
509 #define GS getservbyname
510 #define GU getuid
511 #define GWD getcwd
512 #define HL htonl
513 #define HS htons
514 #define I int
515 #define IA inet_addr
516 #define ID isdigit
517 #define IF if
518 #define IL isalpha
519 #ifndef DISABLE_SRCIP
520 #define IN inet_ntoa
521 #endif
522 #define IP isprint
523 #define K kill
524 #define L long
525 #define LI listen
526 #define M malloc
527 #define MC memcpy
528 #ifdef NCURSES
529 #define NE werase
530 #define NMW mvprintw
531 #define NR refresh
532 #define NRE wrefresh
533 #define NSO scrollok
534 #define NSW subwin
535 #define NW WINDOW
536 #define NWP wprintw
537 #define NWV mvwaddch
538 #endif
539 #define NHS ntohs
540 #define P printf
541 #define PT pid_t
542 #define R return
543 #define RD read
544 #define RF recvfrom
545 #define RI rindex
546 #define S struct
547 #define SA sockaddr
548 #define SAN sockaddr_in
549 #define SC strcmp
550 #define SCA strcat
551 #define SCC strcasecmp
552 #define SCP strcpy
553 #define SD shutdown
554 #define SDU strdup
555 #define SE select
556 #define SEGD setegid
557 #define SEUD seteuid
558 #define SG signal
559 #define SGD setgid
560 #define SH short
561 #define SI signed
562 #define SK socket
563 #define SL strlen
564 #ifndef DISABLE_SYSLOG
565 #define SLG syslog
566 #endif
567 #define SLP sleep
568 #define SNC strncmp
569 #define SNCC strncasecmp
570 #define SO sizeof
571 #define SP sprintf
572 #define SR srand
573 #define SSO setsockopt
574 #define ST static
575 #define STC strchr
576 #define STT stat
577 #define SUD setuid
578 #define SW switch
579 #define T time_t
580 #define TL tolower
581 #define TM time
582 #define TN ttyname
583 #define U unsigned
584 #define UE uname
585 #define UI uid_t
586 #define UM umask
587 #define UN unlink
588 #define USLP usleep
589 #define V void
590 #define VAE va_end
591 #define VAL va_list
592 #define VAS va_start
593 #define VS vsnprintf
594 #define W while
595 #define WP waitpid
596 #define WR write
597 /* global stored information, used throughout.  also, id info. */
598 /* these are all filled with 0, or 1. (to that extent) */
599 U SH defined[6];
600 U SH dynamicvarset[10];
601 /* 65535 is the max color setting, so it will be defined a short. */
602 #ifdef GTK
603 U SH guic[3];
604 #endif
605 U SH rs_dynamic[((MAX_ARGS/2)+2)];
606 U SH rs_static[((MAX_ARGS/2)+2)];
607 U SH bindmode=0;
608 U SH editrules=0;
609 U SH displaytype=0;
610 U SH forever=0;
611 U SH initsend=0;
612 U SH inputrules=0;
613 #ifdef GTK
614 U SH isagui=0;
615 U SH isbgui=0;
616 U SH isgui=0;
617 U SH isguic=0;
618 U SH isguil=0;
619 U SH isguis=0;
620 U SH isguititle=0;
621 U SH isguiwait=0;
622 #endif
623 U SH isbg=0;
624 U SH isbga=0;
625 U SH isiexec=0;
626 #ifdef NCURSES
627 U SH isncurses=0;
628 U SH isncursesa=0;
629 U SH isncursesl=0;
630 #endif
631 U SH isprivileged=0;
632 U SH isudp=0;
633 U SH isudpr=0;
634 U SH isvhost=0;
635 U SH lnum=0;
636 U SH islog=0;
637 U SH nofrom=0;
638 U SH norrecv=0;
639 U SH norsend=0;
640 U SH noshowa=0;
641 U SH noshowc=0;
642 U SH noshowp=0;
643 U SH nosrecv=0;
644 U SH nossend=0;
645 U SH notnetopt=0;
646 U SH nowrap=0;
647 U SH omitchars=0;
648 U SH printonly=0;
649 U SH runcmd=0;
650 U SH runexit=0;
651 U SH runpre=0;
652 U SH setcdir=0;
653 U SH setfile=0;
654 U SH sethost=0;
655 U SH setperms=0;
656 U SH setrdir=0;
657 U SH setroute=0;
658 U SH setshell=0;
659 U SH showv=0;
660 #ifndef DISABLE_SYSLOG
661 U SH slog=0;
662 #endif
663 U SH soptions=0;
664 U SH tnet=0;
665 U SH tnetraw=0;
666 U SH truetnet=0;
667 #ifndef DISABLE_MODULES
668 U SH vmodule=0;
669 #endif
670 /* these could end up being larger sets. */
671 U I rs_delay[((MAX_ARGS/2)+2)];
672 U I alrm=0;
673 U I lnum_i=0;
674 U I lnum_o=0;
675 U I rport=0;
676 U I sdelay=0;
677 #ifndef DISABLE_SYSLOG
678 U I slnum_s=0;
679 U I slnum_t=0;
680 #endif
681 U I sport=0;
682 U I tot_i=0;
683 U I tot_o=0;
684 U I tshs=0;
685 U I xalrm=0;
686 I blog=0;
687 #ifdef GTK
688 I guih=0;
689 I guio=0;
690 I guiw=0;
691 #endif
692 I columns=0;
693 I rsock=0;
694 I sock=0;
695 I ssock=0;
696 /* usleep(unsigned long), on most systems.  could cause a warning on others. */
697 U L sudelay=0;
698 /* stored uid, and gid information. */
699 UI nuid=0;
700 GI ngid=0;
701 /* constant pid value. */
702 PT cpid=0;
703 /* the all purpose module handle. (related to two functions, global) */
704 #ifndef DISABLE_MODULES
705 V *dyn;
706 #endif
707 ST C author[]="vade79/v9@fakehalo.deadpig.org, fakehalo.deadpig.org";
708 ST C id[]="$Id: netscript.c,v "VERSION" 2002/10/07 22:59:01 vade79 Exp $";
709 ST C license[]="public domain";
710 C *dynamicvar[10];
711 #ifdef GTK
712 C *gblabel[3];
713 #endif
714 C *input[((MAX_ARGS/2)+2)];
715 C *output[((MAX_ARGS/2)+2)];
716 C *shost[MAX_ARGS];
717 C *cdir;
718 C *eshell;
719 C *execfile;
720 C *execformat;
721 C *execpre;
722 #ifdef GTK
723 C *guititle;
724 #endif
725 C *histfile;
726 C *iswrite;
727 C *logfile;
728 #ifdef NCURSES
729 C *nclabel[2];
730 #endif
731 C *nname;
732 C *parm;
733 C *ochars;
734 C *parseddynamic;
735 C *parsedline;
736 C *progname;
737 C *rcfile;
738 C *rdir;
739 C *rhost;
740 C *rulesfile;
741 C *sopts;
742 C *swrite;
743 C *toenv;
744 C *tofile;
745 C *ttyn;
746 C *vhost;
747 /* externals. */
748 EX I errno;
749 EX C *optarg;
750 /* gtk (global) widgets. */
751 #ifdef GTK
752 GW *gb1;
753 GW *gb2;
754 GW *gbu;
755 GW *gen;
756 GW *ghb;
757 GW *giw;
758 GW *gpb;
759 GW *gpd;
760 GW *gta;
761 GW *gte;
762 GW *gvn;
763 GW *gvs;
764 #endif
765 /* ncurses (global) windows. */
766 #ifdef NCURSES
767 NW *nfocus;
768 NW *nw1;
769 NW *nw2;
770 NW *nw3;
771 #endif
772 /* functions, mainly put this as an index.  since i am not returning */
773 /* anything except integers, i noticed that it takes less space to just */
774 /* return short true/false responses, and write to global strings if needed, */
775 /* especially for routines used multiple times in different situations. */
776 /* (prototypes) */
777 V sighandler(I); /* all-round signal handler. */
778 V modhandler(C *); /* all-round module handler. (must have all defined) */
779 V setdefined(V); /* sets the compiler defines to an array, used once. */
780 V parseoutput(C *,C *); /* replace input arguments into output resp. */
781 V truncateoutput(U I); /* chomps the output response to clean out variables. */
782 V parsecharvars(C *); /* replace hex, dec, and random variables. */
783 V parsedynamic(C *); /* handles the dynamic variables for other functions. */
784 V parsecmdline(C *); /* very small function for command line repetition. */
785 V setdname(V); /* set up the display name to be used by other functions. */
786 V setrc(C *); /* to set the rc filename. */
787 V sethistory(C *); /* to set the history filename. */
788 V addhistory(U C *); /* appends a line to the history file. */
789 V makelists(C *); /* make in/out lists, from the ruleset. */
790 V nsprint(C *,...); /* format, and direct data to display. */
791 V pe(C *,U SH); /* prints data (and/or) exits. */
792 V pd(U C *,U SH,U I); /* prints in/out data, formats. */
793 V wro(C *,U I,U SH); /* writes data to the socket(s). */
794 #ifndef DISABLE_SYSLOG
795 V wrso(C *,...); /* logs when privileged, info to the system log. */
796 #endif
797 V setpermissions(C *,U SH); /* set permissions of netscript to run under. */
798 V ruleedit(U SH,C *); /* ruleset editor, uses a third party program to edit. */
799 V logdata(C *,U SH); /* adds data to the log file. */
800 V dumptelnet(C *); /* dumps the raw telnet information. (-Y, and -y) */
801 V dumpexec(C *,U SH); /* execution of a program that dumps to the socket. */
802 V dumpexecline(C *); /* to handle data passed from dumpexec(), to be dumped. */
803 V closesocket(U SH); /* closes the socket connection/binding/etc. */
804 V parsesocketopt(I,I); /* handles the user supplied socket option(s). */
805 V parsesocket(C *,U I); /* all-round socket handler. */
806 V iface(C *); /* prompted version of the netscript interactive handler. */
807 V showinfo(U SH); /* show different types of version information. */
808 V displayv(V); /* displays the variables for matches, and replacements. */
809 V usage(U SH); /* displays the program usage. */
810 V nsexit(SH,U SH); /* optional exit routine to be placed. */
811 /* the following is for only ncurses support. */
812 #ifdef NCURSES
813 V ncursesinit(V); /* initialize ncurses screen. */
814 #endif
815 /* the following are for only gui support. */
816 #ifdef GTK
817 V gtkec(GW *,GW *); /* handle the entry data, from the entry widget. */
818 V gtkcl(GW *,GPT); /* handle the clear button callback. */
819 V gtkpd(GW *,GPT); /* handle the pulldown check button. (non-generic mode) */
820 V gtkca(GW *,GPT); /* handle the exit button callback. */
821 V gtkrun(C *); /* run, and create the (main) gui. */
822 #endif
823 U SH wordmatch(C *,C *); /* wildcard match handler. */
824 U SH prewordmatch(C *,C *); /* checks for negative rule/passes on. */
825 U SH parameter(C *,I,U I); /* gets a parameter from the string. */
826 U SH wischeck(C *,U I); /* checks for word format of its counterpart. */
827 U SH usefilelist(C *); /* handles the --list command line argument. */
828 U SH usehistory(C *,U SH); /* uses the history file, to select arguments. */
829 U SH delhistory(C *); /* attempts to delete the history file. */
830 U SH getexecargs(C *); /* gets arguments from +x files. */
831 U I portentry(C *); /* checks for /etc/services string, converts otherwise. */
832 /* these are for the module support, used with NS_MODULE. */
833 #ifndef DISABLE_MODULES
834 ST I (*init_function)(); /* symbol for initialization handling. */
835 ST I (*exit_function)(); /* symbol for global exit handling. */
836 ST I (*connect_function)(); /* symbol used when connected handling. */
837 ST I (*incoming_function)(); /* symbol for incoming data handling. */
838 ST I (*incoming_char_function)(); /* symbol for incoming data, per char. */
839 ST I (*incoming_raw_function)(); /* symbol for incoming data, raw dump. */
840 ST I (*outgoing_function)(); /* symbol for outgoing data handling. */
841 #endif
842 /* this handles the signals netscript receives. */
sighandler(I sig)843 V sighandler(I sig){
844  /* clean up before exiting completely. */
845  closesocket(0);
846  closesocket(1);
847  IF(!isbga){
848 #ifdef GTK
849   IF(isgui){
850    IF(sig==SIGALRM){
851     pe("alarm timed out",0);
852     nsexit(0,0);
853    }
854   }
855   E{
856 #endif
857    /* precursor to every kill message. */
858    FP(stderr,"(killed -- ");
859    SW(sig){
860     CS SIGINT:
861      FP(stderr,"user aborted");
862      BR;
863     CS SIGSEGV:
864 #ifndef DISABLE_SYSLOG
865     /* force the system logging(if accessible), even if the -Z option is not */
866     /* enabled. (this is not documented) */
867     slog++;
868     wrso("*-* id: %lu-%u.%u.%u.%u notice: internal memory error, forced log (s"
869     "egmentation fault)",cpid,GU(),GEU(),GG(),GEG());
870     /* return to previous logging status. */
871     slog--;
872 #endif
873      FP(stderr,"segmentation/memory fault");
874      BR;
875     CS SIGTERM:
876      FP(stderr,"terminated");
877      BR;
878     CS SIGALRM:
879      FP(stderr,"alarm");
880      BR;
881     default:
882      FP(stderr,"undefined signal: %d",sig);
883      BR;
884    }
885    /* cap the kill line. */
886    FP(stderr,")\n");
887 #ifdef GTK
888   }
889 #endif
890  }
891  /* make sure to exit properly if in gtk mode. */
892 #ifdef GTK
893  IF(isgui)
894   isgui=0;
895 #endif
896  /* exit. */
897  nsexit(1,0);
898 }
899 /* this function handles the module suport for initialization, input, and */
900 /* output.  they must all be defined to be used.  since this will only be */
901 /* used once, the file will just be left open until netscript exits. */
902 #ifndef DISABLE_MODULES
modhandler(C * path)903 V modhandler(C *path){
904  U SH i=0;
905  IF(!(dyn=dlopen(path,RTLD_TYPE))&&(i=1))
906   pe("module file does not exist, is not readable, or is unusable",0);
907  E{
908   IF(!i&&!(init_function=dlsym(dyn,"ns_init"))&&(i=1))
909    pe("module file does not have ns_init() properly defined",0);
910   IF(!i&&!(exit_function=dlsym(dyn,"ns_exit"))&&(i=1))
911    pe("module file does not have ns_exit() properly defined",0);
912   IF(!i&&!(connect_function=dlsym(dyn,"ns_connect"))&&(i=1))
913    pe("module file does not have ns_connect() properly defined",0);
914   IF(!i&&!(incoming_function=dlsym(dyn,"ns_incoming"))&&(i=1))
915    pe("module file does not have ns_incoming() properly defined",0);
916   IF(!i&&!(incoming_char_function=dlsym(dyn,"ns_incoming_char"))&&(i=1))
917    pe("module file does not have ns_incoming_raw() properly defined",0);
918   IF(!i&&!(incoming_raw_function=dlsym(dyn,"ns_incoming_raw"))&&(i=1))
919    pe("module file does not have ns_incoming_raw() properly defined",0);
920   IF(!i&&!(outgoing_function=dlsym(dyn,"ns_outgoing"))&&(i=1))
921    pe("module file does not have ns_outgoing() properly defined",0);
922  }
923  IF(!i)
924   vmodule=1;
925  R;
926 }
927 #endif
928 /* stores the included values into an array.  statically defined in the */
929 /* binary.  used for informational(-v option), and internal purposes. */
setdefined(V)930 V setdefined(V){
931 #ifndef DISABLE_MODULES
932  defined[0]=1;
933 #else
934  defined[0]=0;
935 #endif
936 #ifndef DISABLE_SRCIP
937  defined[1]=1;
938 #else
939  defined[1]=0;
940 #endif
941 #ifdef ARPA
942  defined[2]=1;
943 #else
944  defined[2]=0;
945 #endif
946 #ifdef GTK
947  defined[3]=1;
948 #else
949  defined[3]=0;
950 #endif
951 #ifndef DISABLE_SYSLOG
952  defined[4]=1;
953 #else
954  defined[4]=0;
955 #endif
956 #ifdef NCURSES
957  defined[5]=1;
958 #else
959  defined[5]=0;
960 #endif
961  R;
962 }
963 /* this is the function that fills in the $# replacement of output.  the */
964 /* function parsecharvars() is used for both input, and output of the */
965 /* ruleset file.  making these two functions somewhat differ, so they each */
966 /* got their own function.  also, handles $#-, which will dump the rest of */
967 /* the data.  for example: $2- will dump everything after argument 2. */
968 /* finally, dynamic variables get placed to this function by */
969 /* parsedynamic(). (${#}, #=0-9) */
parseoutput(C * input,C * output)970 V parseoutput(C *input,C *output){
971  U I i=0;
972  U I j=0;
973  U I k=0;
974  U I l=0;
975  /* no comparisons here. */
976  C *tmpio;
977  /* handles the dynamic variables.  ruleset only, not remote info. (${0-9}) */
978  parsedynamic(output);
979  /* find out the size of the buffer needed. */
980  W(!parameter(parseddynamic,i++,0x20)){
981   IF(((SL(parm)==2)||(SL(parm)==3&&parm[2]==0x2D))&&(parm[0]==
982   PARAMETER_VAR_CHAR&&ID((U I)parm[1]))){
983    IF(SL(parm)==3){
984     l=k=(parm[1]-0x30);
985     W(!parameter(input,k++,0x20))
986      /* add spaces where defined. */
987      j+=((k!=(l+1)||i!=1)?1+SL(parm):SL(parm));
988    }
989    E{
990     IF(!parameter(input,((parm[1]-0x30)),0x20))
991      j+=(i!=1?1+SL(parm):SL(parm));
992    }
993   }
994   E
995    j+=(i!=1?1+SL(parm):SL(parm));
996  }
997  /* allocate what was calculated above. */
998  IF(!(tmpio=(C *)M(j+1)))
999   pe("parseoutput(): allocation of memory error",1);
1000  B(tmpio,(j+1));
1001  /* was used above, and is about to be used again.  reset. */
1002  i=0;
1003  /* fill in the buffer with the data. */
1004  W(!parameter(parseddynamic,i++,0x20)){
1005   IF(((SL(parm)==2)||(SL(parm)==3&&parm[2]==0x2D))&&(parm[0]==
1006   PARAMETER_VAR_CHAR&&ID((U I)parm[1]))){
1007    IF(SL(parm)==3){
1008     l=k=(parm[1]-0x30);
1009     W(!parameter(input,k++,0x20)){
1010      /* add spaces where defined. */
1011      IF((k!=(l+1))||i!=1)
1012       SCA(tmpio," ");
1013      SCA(tmpio,parm);
1014     }
1015    }
1016    E{
1017     IF(!parameter(input,(parm[1]-0x30),0x20)){
1018      IF(i!=1)
1019       SCA(tmpio," ");
1020      SCA(tmpio,parm);
1021     }
1022    }
1023   }
1024   E{
1025    IF(i!=1)
1026     SCA(tmpio," ");
1027    SCA(tmpio,parm);
1028   }
1029  }
1030  /* using, and reusing the global "swrite" buffer. */
1031  FR(swrite);
1032  IF(!(swrite=(C *)SDU(tmpio)))
1033   pe("parseoutput(): duplication of memory error",1);
1034  /* finished buffer. */
1035  FR(tmpio);
1036  R;
1037 }
1038 /* very small function to stop repetitive use of the same thing, it will */
1039 /* cut the variable out of the output response.  so, the same buffer can be */
1040 /* used elsewhere. */
truncateoutput(U I i)1041 V truncateoutput(U I i){
1042  U I j=0;
1043  F(j=i;j<SL(swrite);j++)
1044   swrite[(j-i)]=swrite[j];
1045  swrite[(j-i)]=0x0;
1046  R;
1047 }
1048 /* this function is meant to replace $001-255, and $01-FF to character */
1049 /* format for the ruleset, also for replacement of the $&, and $# random */
1050 /* variables. (not server related) */
parsecharvars(C * line)1051 V parsecharvars(C *line){
1052  U I i=0;
1053  U I j=0;
1054  U I tmp=0;
1055  S timeval tv;
1056  FR(parsedline);
1057  IF(!(parsedline=(C *)M(SL(line)+1)))
1058   pe("parsecharvars(): allocation of memory error",1);
1059  F(i=0;i<SL(line);i++){
1060   IF(PARAMETER_VAR_CHAR==line[i]){
1061    /* handle decimal truncation. */
1062    IF(line[i+3]&&ID((U I)line[i+1])&&ID((U I)line[i+2])&&ID((U I)line[i+3])){
1063     /* to not get confused with the length check wildcard. */
1064     IF(!(line[i+4]&&ID((U I)line[i+4]))){
1065      tmp=(((line[i+1]-0x30)*100)+((line[i+2]-0x30)*10)+(line[i+3]-0x30));
1066      IF(tmp>0&&tmp<256){
1067       parsedline[j++]=tmp;
1068       i+=3;
1069      }
1070      E
1071       parsedline[j++]=line[i];
1072     }
1073     E
1074      parsedline[j++]=line[i];
1075    }
1076    /* handle hex truncation. */
1077    EI(line[i+2]&&isxdigit((U I)line[i+1])&&isxdigit((U I)line[i+2])){
1078     /* to not get confused with the length check wildcard. */
1079     IF(!(line[i+3]&&line[i+4]&&ID((U I)line[i+3])&&ID((U I)line[i+4]))){
1080      IF(IL((U I)line[i+1]))
1081       tmp=(TL(line[i+1])-0x56);
1082      E
1083       tmp=(line[i+1]-0x2F);
1084      tmp*=16;
1085      IF(IL((U I)line[i+2]))
1086       tmp+=(TL(line[i+2])-0x56);
1087      E
1088       tmp+=(line[i+2]-0x2F);
1089      tmp-=17;
1090      IF(tmp>0&&tmp<256){
1091       parsedline[j++]=tmp;
1092       i+=2;
1093      }
1094      E
1095       parsedline[j++]=line[i];
1096     }
1097     E
1098      parsedline[j++]=line[i];
1099    }
1100    /* handle random(alpha) truncation. */
1101    EI(line[i+1]==0x26){
1102     GD(&tv,(S timezone *)0);
1103     SR(tv.tv_usec);
1104     IF((2.0*rand()/(RAND_MAX+1.0))>1)
1105      parsedline[j++]=(0x41+(26.0*rand()/(RAND_MAX+1.0)));
1106     E
1107      parsedline[j++]=(0x61+(26.0*rand()/(RAND_MAX+1.0)));
1108     i++;
1109    }
1110    /* handle random(numeric) truncation. */
1111    EI(line[i+1]==0x23){
1112     GD(&tv,(S timezone *)0);
1113     SR(tv.tv_usec);
1114     parsedline[j++]=(0x30+(10.0*rand()/(RAND_MAX+1.0)));
1115     i++;
1116    }
1117    E
1118     parsedline[j++]=line[i];
1119   }
1120   E
1121    parsedline[j++]=line[i];
1122  }
1123  parsedline[j]=0x0;
1124  R;
1125 }
1126 /* parsing for ${0-9} dynamic user storage variables, makes the */
1127 /* "parseddynamic" buffer. */
parsedynamic(C * in)1128 V parsedynamic(C *in){
1129  U I i=0;
1130  U I j=0;
1131  F(j=i=0;i<SL(in);i++){
1132   IF(in[(i+3)]&&in[i]==PARAMETER_VAR_CHAR&&in[(i+1)]==0x7B&&ID((U I)in[(i+2)])
1133   &&in[(i+3)]==0x7D&&!(i==0&&in[(i+4)]&&in[(i+4)]==0x3D)){
1134    IF(dynamicvarset[(in[(i+2)]-0x30)])
1135     j+=SL(dynamicvar[(in[(i+2)]-0x30)]);
1136    i+=3;
1137   }
1138   E
1139    j++;
1140  }
1141  FR(parseddynamic);
1142  IF(!(parseddynamic=(C *)M(j+1)))
1143   pe("parsedynamic(): allocation of memory error",1);
1144  B(parseddynamic,(j+1));
1145  F(i=0;i<SL(in);i++){
1146   IF(in[(i+3)]&&in[i]==PARAMETER_VAR_CHAR&&in[(i+1)]==0x7B&&ID((U I)in[(i+2)])
1147   &&in[(i+3)]==0x7D&&!(i==0&&in[(i+4)]&&in[(i+4)]==0x3D)){
1148    /* only if the variable has been set, use it. */
1149    IF(dynamicvarset[(in[(i+2)]-0x30)])
1150     SCA(parseddynamic,dynamicvar[(in[(i+2)]-0x30)]);
1151    i+=3;
1152   }
1153   E
1154    parseddynamic[SL(parseddynamic)]=in[i];
1155  }
1156  R;
1157 }
1158 /* this function was made because these two functions are often with */
1159 /* eachother.  saves repetition space. */
parsecmdline(C * in)1160 V parsecmdline(C *in){
1161  parsedynamic(in);
1162  parsecharvars(parseddynamic);
1163  R;
1164 }
1165 /* this function will set up the display name to be used by other functions. */
setdname(V)1166 V setdname(V){
1167  S utsname un;
1168  /* get the display infromation.  must check for equal or greater than zero. */
1169  /* due to the fact different platforms handle this differently.  but, */
1170  /* errors being a negative number is an apparent constant. */
1171  IF(UE(&un)>-1){
1172   IF(!(nname=(C *)M(SL(un.nodename)+SL(un.machine)+2)))
1173    pe("setdname(): allocation of memory error",1);
1174   B(nname,(SL(un.nodename)+SL(un.machine)+2));
1175   SP(nname,"%s-%s",un.nodename,un.machine);
1176  }
1177  E{
1178   IF(!(nname=(C *)SDU("unknown")))
1179    pe("setdname(): duplication of memory error",1);
1180  }
1181  R;
1182 }
1183 /* function to set the rc filename. */
setrc(C * file)1184 V setrc(C *file){
1185  S passwd *pent;
1186  IF(!(pent=GPU(GU())))
1187   R;
1188  IF(!(rcfile=(C *)M(SL(pent->pw_dir)+SL(file)+2)))
1189   pe("setrc(): allocation of memory error",1);
1190  B(rcfile,(SL(pent->pw_dir)+SL(file)+2)) ;
1191  SP(rcfile,"%s/%s",pent->pw_dir,file);
1192  R;
1193 }
1194 /* function to set the history filename. */
sethistory(C * file)1195 V sethistory(C *file){
1196  S passwd *pent;
1197  IF(!(pent=GPU(GU())))
1198   R;
1199  IF(!(histfile=(C *)M(SL(pent->pw_dir)+SL(file)+2)))
1200   pe("sethistory(): allocation of memory error",1);
1201  B(histfile,(SL(pent->pw_dir)+SL(file)+2)) ;
1202  SP(histfile,"%s/%s",pent->pw_dir,file);
1203  R;
1204 }
1205 /* funcation to append a line to the history file. */
addhistory(U C * data)1206 V addhistory(U C *data){
1207  U I i=0;
1208  U C hread[(BASE_BUFFER*4+1)];
1209  FL *hfd;
1210  /* no verbose error warnings in this function, quiet. */
1211  IF((hfd=FO(histfile,"r"))){
1212   W(FS(hread,(SO(hread)-1),hfd)){
1213    F(i=0;i<SL(hread);i++)
1214     IF(hread[i]==0x0A||hread[i]==0x0D)
1215      hread[i]=0x0;
1216    /* abort it already exists. */
1217    IF(!SC(hread,data)){
1218     FC(hfd);
1219     R;
1220    }
1221    /* clean out. */
1222    B(hread,(BASE_BUFFER*4+1));
1223   }
1224   FC(hfd);
1225  }
1226  IF((hfd=FO(histfile,"a"))){
1227   FP(hfd,"%s\n",data);
1228   FC(hfd);
1229  }
1230  R;
1231 }
1232 /* this is supposed to get the input, and output from the ruleset file. */
1233 /* the file format is per line stacked, must have both.  like so: */
1234 /* input given. (wildcards apply here) */
1235 /* output to responed. (pre-data/actions apply here) */
1236 /* input given. (wildcards apply here) */
1237 /* output to responed. (pre-data/actions apply here, and so on..) */
1238 /* also partly handles the "one time" variable. */
makelists(C * path)1239 V makelists(C *path){
1240  /* yes, i could have reused some.  but, i like to be able to keep track. */
1241  /* loop ints. */
1242  U I i=0;
1243  U I j=0;
1244  U I k=0;
1245  U I l=0;
1246  /* for the last input/output line. */
1247  U C *lasti;
1248  U C *lasto;
1249  /* rather large size for possible long requests. */
1250  U C rread[(BASE_BUFFER*16+1)];
1251  FL *fd;
1252  /* this switches to standard input if the argument is provided. */
1253  IF(inputrules){
1254   IF(!(fd=FO(ttyn,"r")))
1255    pe("standard input does not appear to exist, or is not readable",1);
1256   pe("awaiting ruleset from standard input, followed by ^D",0);
1257  }
1258  E{
1259   IF(!(fd=FO(path,"r")))
1260    pe("ruleset file does not appear to exist, or is not readable",1);
1261  }
1262  B(rread,(BASE_BUFFER*16+1));
1263  W(FS(rread,(SO(rread)-1),fd)){
1264   /* maximum input/output storage met.  exits when it occurs. */
1265   IF(j>=MAX_ARGS)
1266    pe("too many slots to store in memory",1);
1267   IF(rread[0]!=0x23){
1268    F(i=0;i<SL(rread);i++)
1269     IF(rread[i]==0x0A||rread[i]==0x0D)
1270      rread[i]=0x0;
1271    IF(rread[0]!=0x0A&&rread[0]!=0x0D&&rread[0]!=0x0){
1272     /* simple on/off int to write line of input then line of output, then */
1273     /* checking at the end to make sure the input, and output lines are */
1274     /* even. (at the end of the function) */
1275     IF(k)
1276      k=0;
1277     E
1278      k=1;
1279     IF(k){
1280      /* replaces the hex, dec, and random variables. */
1281      parsecharvars(rread);
1282      IF(!(input[tot_i]=(SCC(rread,NS_REPEAT)||!tot_i?(C *)SDU(parsedline):(C *)
1283      SDU(lasti))))
1284       pe("makelists(): duplication of memory error",1);
1285      /* store last input. */
1286      IF(tot_i)
1287       FR(lasti);
1288      IF(!(lasti=(C *)SDU(input[tot_i++])))
1289       pe("makelists(): duplication of memory error",1);
1290     }
1291     E{
1292      /* decided not to allow an only function sleep, so data is required. */
1293      /* virtually makes sure its exactly five numerics, like it must be. */
1294      IF(SL(rread)>6&&ID((U I)rread[(SL(rread)-1)])&&ID((U I)rread[
1295      (SL(rread)-2)])&&ID((U I)rread[(SL(rread)-3)])&&ID((U I)rread[
1296      (SL(rread)-4)])&&ID((U I)rread[(SL(rread)-5)])&&rread[(SL(rread)-6)]
1297      ==PARAMETER_VAR_CHAR){
1298       rs_delay[tot_o]=(((rread[(SL(rread)-5)]-0x30)*10000)+((rread[(SL(rread)-
1299       4)]-0x30)*1000)+((rread[(SL(rread)-3)]-0x30)*100)+((rread[(SL(rread)-2)]-
1300       0x30)*10)+(rread[(SL(rread)-1)]-0x30));
1301       rread[(SL(rread)-6)]=0x0;
1302      }
1303      /* this checks for the "one time" variable.  then, adds it to the int */
1304      /* buffer, if no data is provided after the variable it will be treated */
1305      /* as normal text. */
1306      IF(SL(rread)>SL(NS_ONCE)&&!SNCC(rread,NS_ONCE,SL(NS_ONCE))){
1307       /* kill the two variable bytes. (output) */
1308       F(l=SL(NS_ONCE);l<SL(rread);l++)
1309        rread[(l-SL(NS_ONCE))]=rread[l];
1310       rread[(l-SL(NS_ONCE))]=0x0;
1311       rs_static[tot_o]=1;
1312      }
1313      E
1314       rs_static[tot_o]=0;
1315      /* replaces the hex, dec, and random variables. */
1316      parsecharvars(rread);
1317      IF(!(output[tot_o]=(SCC(rread,NS_REPEAT)||!tot_o?(C *)SDU(parsedline):
1318      (C *)SDU(lasto))))
1319       pe("makelists(): duplication of memory error",1);
1320      /* store last output. */
1321      IF(tot_o)
1322       FR(lasto);
1323      /* add the effects of the copied output rule. (if copied) */
1324      IF(!SCC(rread,NS_REPEAT)&&tot_o){
1325       rs_static[tot_o]=rs_static[(tot_o-1)];
1326       rs_delay[tot_o]=rs_delay[(tot_o-1)];
1327      }
1328      IF(!(lasto=(C *)SDU(output[tot_o++])))
1329       pe("makelists(): duplication of memory error",1);
1330     }
1331    }
1332    B(rread,(BASE_BUFFER*16+1));
1333   }
1334   j++;
1335  }
1336  FC(fd);
1337  /* check for equal amount of input to outputs, so the ruleset corresponds. */
1338  IF(tot_i!=tot_o)
1339   pe("input/output data from the ruleset does not correspond",1);
1340  /* no rules, no go. (might as well use telnet then) */
1341  IF(!tot_i||!tot_o)
1342   pe("no input/output responses supplied from the ruleset file",1);
1343  /* status showing for stdin ruleset input. */
1344  IF(inputrules)
1345   pe("valid ruleset supplied via input, continuing",0);
1346  /* clear one last time, these buffers would have both been used to make */
1347  /* it this far. */
1348  FR(lasti);
1349  FR(lasto);
1350  R;
1351 }
1352 /* this function is for printing arguments passed to it, mainly for the */
1353 /* purpose of GTK/ncurses support, so it can be directed. */
nsprint(C * format,...)1354 V nsprint(C *format,...){
1355  SI I i=0;
1356  /* nothing should get this big, but its virtually the max used anywheres */
1357  /* in netscript. */
1358  U I j=(BASE_BUFFER*8);
1359  C *display;
1360  VAL ap;
1361  /* small fixed font to use. */
1362 #ifdef GTK
1363  GdkFont *gf;
1364  GdkColormap *gcm;
1365  GdkColor gc;
1366 #endif
1367  /* return if backgrounded or malloc() failed. */
1368  IF(isbga||!(display=(C *)M(j)))
1369   R;
1370  W(1){
1371   VAS(ap,format);
1372   i=VS(display,j,format,ap);
1373   VAE(ap);
1374   IF(i>-1&&i<j){
1375   /* send to gui window instead, if in gui mode. */
1376 #ifdef GTK
1377    IF(isgui&&isagui){
1378     gcm=gdk_colormap_get_system();
1379     gc.red=guic[0];
1380     gc.green=guic[1];
1381     gc.blue=guic[2];
1382     IF(!gdk_color_alloc(gcm,&gc))
1383      pe("could not allocate color for the gui",1);
1384     E{
1385      GTE();
1386      /* nice, and standard font.  like fixed. */
1387      IF(!isbgui)
1388       gf=GFL(GUI_FONT);
1389      gtk_text_insert(GTK_TEXT(gte),(isbgui?0:gf),(isguic?&gc:0),0,display,
1390      SL(display));
1391      GTL();
1392     }
1393    }
1394    E
1395 #endif
1396 #ifdef NCURSES
1397    {
1398     IF(isncurses){
1399      NWP(nfocus,"%s",display);
1400      NRE(nfocus);
1401      /* default (back) to main window. */
1402      nfocus=nw3;
1403     }
1404     E
1405      P("%s",display);
1406    }
1407 #else
1408     P("%s",display);
1409 #endif
1410    FR(display);
1411    R;
1412   }
1413   IF(i>-1)
1414    j=(i+1);
1415   E
1416    j*=2;
1417   IF((display=realloc(display,j))==0){
1418    /* size change failed.  free anyways, and return. */
1419    FR(display);
1420    R;
1421   }
1422  }
1423  R;
1424 }
1425 /* displays argv[0], the supplied text, and exits if non-zero. */
pe(C * err,U SH quit)1426 V pe(C *err,U SH quit){
1427  /* simple enough handling on this option. */
1428  IF(!noshowa)
1429   nsprint("%s: %s.\n",progname,err);
1430  IF(quit)
1431   nsexit(quit,0);
1432  R;
1433 }
1434 /* displays hex, dec, or regular with the from/to prompt option. */
1435 /* 0 = output, 1 = input, 2 = other. */
pd(U C * in,U SH io,U I size)1436 V pd(U C *in,U SH io,U I size){
1437  U I i=0;
1438  U I j=0;
1439  U I k=0;
1440  /* will be used for hex, or dec (or duplication of the original). */
1441  U C *chrdump;
1442  U C *line;
1443  C prompt[4];
1444  /* columns gets set before pd() is ever ran, in main(). */
1445  IF(!(line=(C *)M(size+1)))
1446   pe("pd(): allocation of memory error",1);
1447  B(line,(size+1));
1448  IF(displaytype){
1449   /* size multiplied four times because every byte in the original */
1450   /* buffer is going to be equal to four in the new buffer. */
1451   IF(!(chrdump=(C *)M((SL(in)*4)+1)))
1452    pe("pd(): allocation of memory error",1);
1453   B(chrdump,((SL(in)*4)+1));
1454   F(i=0;i<SL(in);i++){
1455    /* 0 = character, 1 = hex, 2 = decimal. */
1456    IF(displaytype==1)
1457     SP(&chrdump[k],"\\x%.2x",in[i]);
1458    E
1459     SP(&chrdump[k],"%.3d%c",in[i],((i+1)!=SL(in))?0x20:0x0);
1460    k+=4;
1461   }
1462  }
1463  /* make the chrdump buffer a standard character buffer if no dispalytype to */
1464  /* wordwrap up later. */
1465  IF(!displaytype){
1466   IF(!(chrdump=(C *)SDU(in)))
1467    pe("pd(): duplication of memory error",1);
1468  }
1469  B(prompt,4);
1470  IF(!io&&!nossend)
1471   SP(prompt,"-> ");
1472  EI(io&&!nosrecv)
1473   SP(prompt,"<- ");
1474  IF(!nowrap){
1475   B(line,(size+1));
1476   F(i=0;i<SL(chrdump);i++){
1477    IF(!SL(line))
1478     SP(line,"%s",!nofrom?prompt:"");
1479    /* next two checks are impossible to effect hex, or dec dumps. */
1480    /* makes sure tabs do not screw up the wordwrap. */
1481    IF(chrdump[i]==0x09)
1482     /* 7 spaces = 1 tab(sort of, at a tab max), if it is beyond the buffer */
1483     /* size the tab will get cut off.  does not handle like a tab does. */
1484     F(j=0;(j<7&&!(SL(line)>=size));j++)
1485      line[SL(line)]=0x20;
1486    /* do not want a screwed up wordwrap, just slap a linefeed there instead. */
1487    EI(chrdump[i]==0x0A)
1488     line[SL(line)]=0x0D;
1489    E
1490     line[SL(line)]=chrdump[i];
1491    IF(SL(line)>=size){
1492 #ifdef NCURSES
1493    nfocus=(io?nw1:nw2);
1494 #endif
1495     nsprint("%s\n",line);
1496     B(line,(size+1));
1497    }
1498   }
1499   IF(SL(line)){
1500 #ifdef NCURSES
1501    nfocus=(io?nw1:nw2);
1502 #endif
1503    nsprint("%s\n",line);
1504   }
1505  }
1506  /* for disabled wordwrap, which also includes th -L option. (-w option) */
1507  EI(SL(chrdump)){
1508   /* precurse with number of lines. */
1509   IF(lnum){
1510 #ifdef NCURSES
1511    nfocus=(io?nw1:nw2);
1512 #endif
1513    nsprint("(%.4d) ",(!io?(lnum_o++):(lnum_i++)));
1514    /* restart it to zero. */
1515    IF(lnum_o>=10000)
1516     lnum_o=1;
1517    IF(lnum_i>=10000)
1518     lnum_i=1;
1519   }
1520 #ifdef NCURSES
1521   nfocus=(io?nw1:nw2);
1522 #endif
1523   nsprint("%s%s\n",!nofrom?prompt:"",chrdump);
1524  }
1525  FR(chrdump);
1526  FR(line);
1527  R;
1528 }
1529 /* writes data to the socket, and handles the ns_outgoing() module.  also, */
1530 /* handles the telnet dump for outgoing. (-y, and -Y options) */
wro(C * output,U I size,U SH io)1531 V wro(C *output,U I size,U SH io){
1532  U SH s=0;
1533  fd_set cfd;
1534  fd_set crfd;
1535  S timeval tv;
1536  /* check, and use the ns_outgoing() symbol, it passes the output to be */
1537  /* wrote to the socket, the amount that will be wrote, the actual size of */
1538  /* the data, and the socket value. (char *, int, int, int) */
1539 #ifndef DISABLE_MODULES
1540  IF(vmodule&&SL(output)&&size&&!io)
1541   (*outgoing_function)(output,size,SL(output),sock);
1542 #endif
1543  IF(sock!=-1&&!io){
1544   FD_ZERO(&cfd);
1545   FD_SET(sock,&cfd);
1546   /* handle outgoing telnet dumping. (-y, and -Y options) */
1547   dumptelnet(output);
1548   /* no time needed. */
1549   tv.tv_sec=0;
1550   tv.tv_usec=0;
1551   /* make sure the socket is really there. */
1552   IF(SE((sock+1),0,&cfd,0,&tv)>0)
1553    WR(sock,output,size);
1554   IF(islog&&tnetraw)
1555    logdata(output,3);
1556  }
1557  IF(setroute){
1558   /* to still check for activity with select(). */
1559   IF(((norrecv&&io)||(norsend&&!io))&&io!=2)
1560    s=1;
1561   IF(rsock!=-1){
1562    FD_ZERO(&crfd);
1563    FD_SET(rsock,&crfd);
1564    tv.tv_sec=0;
1565    tv.tv_usec=0;
1566    IF(SE((rsock+1),0,&crfd,0,&tv)>0){
1567     IF(!s)
1568      WR(rsock,output,size);
1569    }
1570    /* silent. */
1571    E{
1572     SD(rsock,2);
1573     CL(rsock);
1574     rsock=-1;
1575     setroute=0;
1576    }
1577   }
1578  }
1579  R;
1580 }
1581 /* this function will write the supplied arguments to the system log.  it */
1582 /* has a similar usage to nsprint(). (-Z option) */
1583 #ifndef DISABLE_SYSLOG
wrso(C * format,...)1584 V wrso(C *format,...){
1585  SI I i=0;
1586  /* max size. */
1587  U I j=(BASE_BUFFER*8);
1588  C *wlog;
1589  VAL ap;
1590  /* only do if enabled. (-Z option) */
1591  IF(!slog)
1592   R;
1593  /* return if backgrounded or malloc() failed. */
1594  IF(!(wlog=(C *)M(j)))
1595   R;
1596  W(1){
1597   VAS(ap,format);
1598   i=VS(wlog,j,format,ap);
1599   VAE(ap);
1600   IF(i>-1&&i<j){
1601    /* could fail to write.  if it does, it probably was not a superuser, */
1602    /* which is all that is desired to be logged anyways. */
1603    SLG(LOG_WARNING,"%s",wlog);
1604    FR(wlog);
1605    R;
1606   }
1607   IF(i>-1)
1608    j=(i+1);
1609   E
1610    j*=2;
1611   IF((wlog=realloc(wlog,j))==0){
1612    /* size change failed.  free anyways, and return. */
1613    FR(wlog);
1614    R;
1615   }
1616  }
1617  R;
1618 }
1619 #endif
1620 /* function to set the permissions of netscript to run under.  set after */
1621 /* connected.  but, set before taking any input, or sending any output. */
setpermissions(C * string,U SH type)1622 V setpermissions(C *string,U SH type){
1623  S passwd *pent;
1624  S group *gent;
1625  /* read the string. */
1626  IF(!type){
1627   /* set them up default.  in case no data is provided, it will just reset. */
1628   ngid=GEG();
1629   nuid=GEU();
1630   /* if a "." exists.  take the first token as uid, and then second as gid. */
1631   IF(!parameter(string,1,0x2E)){
1632    IF(!(gent=GR(parm)))
1633     ngid=AI(parm);
1634    E
1635     ngid=gent->gr_gid;
1636    parameter(string,0,0x2E);
1637    IF(!(pent=GP(parm)))
1638     nuid=AI(parm);
1639    E
1640     nuid=pent->pw_uid;
1641   }
1642   E{
1643    IF(!(pent=GP(string)))
1644     nuid=AI(string);
1645     /* gid should be defaulted, already. */
1646    E{
1647     nuid=pent->pw_uid;
1648     ngid=pent->pw_gid;
1649    }
1650    /* apply the gid of the user, since no other gid was specified. */
1651   }
1652  }
1653  /* do what setpermissions() said to when called earlier. */
1654  E{
1655   /* note the new id information.  to potentially, clarify the discontinue */
1656   /* of logging.*/
1657 #ifndef DISABLE_SYSLOG
1658   wrso("%d-%d id: %lu-%u.%u.%u.%u new: %lu-%u.%u.%u.%u",slnum_t,(slnum_s++),
1659   cpid,GU(),GEU(),GG(),GEG(),cpid,nuid,nuid,ngid,ngid);
1660 #endif
1661   /* set the groups up, to follow. */
1662   IF((pent=GPU(nuid)))
1663    initgroups(pent->pw_name,ngid);
1664   /* setre*id() is not on some systems.  virtually the same thing.  keeps */
1665   /* the groups.  also, no need for setfs*id(), sete*id() will do it. */
1666   /* setfs*id() is not supported everywheres either. */
1667   SGD(ngid);
1668   SEGD(ngid);
1669   SUD(nuid);
1670   SEUD(nuid);
1671  }
1672  R;
1673 }
1674 /* ruleset editor, uses a third party text editor on a file. */
ruleedit(U SH type,C * path)1675 V ruleedit(U SH type,C *path){
1676  C *editor;
1677  C *tmpfile;
1678  PT fp;
1679  T tm;
1680  S stat mod;
1681  IF(isprivileged)
1682   pe("a third party editor can not be executed with privileged access",0);
1683  E{
1684   IF(G(ENV_EDITOR)){
1685    IF(!(editor=(C *)SDU((C *)G(ENV_EDITOR))))
1686     pe("ruleedit(): duplication of memory error",1);
1687   }
1688   E{
1689    IF(!(editor=(C *)SDU(DFL_EDITOR)))
1690     pe("ruleedit(): duplication of memory error",1);
1691   }
1692   IF(!type){
1693    IF(!(tmpfile=(C *)M(5+10+5+10+1)))
1694     pe("ruleedit(): allocation of memory error",1);
1695    B(tmpfile,(5+10+5+10+1));
1696    TM(&tm);
1697    SP(tmpfile,"/tmp/netscript.%.5lu%.10lu",(U L)cpid,(U L)tm);
1698   }
1699   E{
1700    IF(!(tmpfile=(C *)SDU(path)))
1701     pe("ruleedit(): duplication of memory error",1);
1702   }
1703   SW(fp=FK()){
1704    CS -1:
1705     pe("failed forking for the third party text editor",0);
1706     BR;
1707    CS 0:
1708     SG(SIGINT,SIG_DFL);
1709     EL(editor,editor,tmpfile,0);
1710     pe("failed execution of (ruleset) file editor",0);
1711     _exit(1);
1712     BR;
1713    default:
1714     /* wait till finished. */
1715     WP(fp,0,0);
1716     BR;
1717   }
1718   IF(STT(tmpfile,&mod))
1719    pe("could not access the temporary/ruleset file passed to the editor",1);
1720   EI(!setfile){
1721    /* this should never happen.  but, just incase. */
1722    IF(mod.st_uid!=GEU()||mod.st_gid!=GEG())
1723     pe("the temporary file has a different owner/group than the current proces"
1724     "s",1);
1725    EI(!setfile){
1726     IF(!(rulesfile=(C *)SDU(tmpfile)))
1727      pe("ruleedit(): duplication of memory error",1);
1728     setfile=1;
1729    }
1730   }
1731   FR(editor);
1732   FR(tmpfile);
1733  }
1734  R;
1735 }
1736 /* this function does the logging. (-l option) */
1737 /* 0 = output, 1 = input, 2 = other, else = raw. */
logdata(C * data,U SH io)1738 V logdata(C *data,U SH io){
1739  /* will be used to hold the ctime data. */
1740  C *timebuf;
1741  C prompt[3];
1742  T tm;
1743  FL *fd;
1744  /* opens, and allows appending to the log file. */
1745  IF(!(fd=FO(logfile,"a")))
1746   pe("log file can not be created, or is not writable",1);
1747  E{
1748   TM(&tm);
1749   IF(!(timebuf=(C *)SDU(CT(&tm))))
1750    pe("logdata(): duplication of memory error",1);
1751   IF(timebuf[(SL(timebuf)-1)]==0x0A)
1752    timebuf[(SL(timebuf)-1)]=0x0;
1753   B(prompt,3);
1754   IF(!io)
1755    SP(prompt,"->");
1756   EI(io==1)
1757    SP(prompt,"<-");
1758   EI(io==2)
1759    SP(prompt,"!!");
1760   IF(SL(data)){
1761    /* raw data write. (-y, and -Y options) */
1762    IF(!SL(prompt))
1763     FP(fd,"%s",data);
1764    E
1765     /* regular data write. */
1766     FP(fd,"%s: %s %s\n",timebuf,prompt,data);
1767   }
1768   FR(timebuf);
1769   FC(fd);
1770  }
1771  R;
1772 }
1773 /* the fixed dumping of information with the telnet option.  has */
1774 /* comparisons. (-y, and -Y in conjunction with -T option) */
dumptelnet(C * dump)1775 V dumptelnet(C *dump){
1776  U I i=0;
1777  U I j=0;
1778  U C *tmpdump;
1779  IF(!(tmpdump=(C *)M(SL(dump)+1)))
1780   pe("dumptelnet(): allocation of memory error",1);
1781  IF(tnetraw){
1782   /* 1 = stderr, 2 = stdout(regular). */
1783   IF(tnetraw==1){
1784    /* do not show if backgrounded. */
1785    IF(!isbga)
1786     FP(stderr,"%s",dump);
1787   }
1788   E{
1789    /* mainly did it this way for debug purposes. */
1790    B(tmpdump,(SL(dump)+1));
1791    F(i=j=0;j<SL(dump);j++){
1792     IF(dump[j]==0x0A){
1793      tmpdump[i]=0x0;
1794      nsprint("%s\n",tmpdump);
1795      B(tmpdump,(SL(dump)+1));
1796      i=0;
1797     }
1798     E
1799      tmpdump[i++]=dump[j];
1800    }
1801    IF(SL(tmpdump)){
1802     tmpdump[i]=0x0;
1803     nsprint("%s",tmpdump);
1804    }
1805    /* no need to zero out the buffer since it is going to be free'd next. */
1806   }
1807  }
1808  FR(tmpdump);
1809  R;
1810 }
1811 /* this is for use with dumping a programs output to the socket.  also, */
1812 /* used for the $` execution comparison variable. */
dumpexec(C * path,U SH type)1813 V dumpexec(C *path,U SH type){
1814  U SH r=0;
1815  U SH s=0;
1816  U I i=0;
1817  U I j=0;
1818  U I k=0;
1819  /* to be duplicated. */
1820  I fd[2];
1821  PT fp;
1822  /* will wrap if needed to this size. */
1823  U C eread[(BASE_BUFFER*8+1)];
1824  /* temporary buffer must be as big as its counterpart. */
1825  U C ereadl[(BASE_BUFFER*8+1)];
1826  /* timeout of waiting for input. */
1827  S timeval tv;
1828  /* for select(). */
1829  fd_set ffd;
1830  /* set to null, in case anything fails before anything actually happens. */
1831  IF(type){
1832   FR(execformat);
1833   IF(!(execformat=(C *)SDU("(null)")))
1834    pe("dumpexec(): duplication of memory error",1);
1835  }
1836  /* just incase of setuid/setgid. */
1837 #ifdef GTK
1838  IF(isgui){
1839   pe("can not execute third party programs while in gui/gtk mode",0);
1840   R;
1841  }
1842 #endif
1843 #ifndef DISABLE_SYSLOG
1844  wrso("%d-%d id: %lu-%u.%u.%u.%u exec: %s",slnum_t,(slnum_s++),cpid,GU(),GEU(),
1845  GG(),GEG(),path);
1846 #endif
1847  IF(!noshowp&&!type)
1848   pe("entering execution dump, incoming data suspended",0);
1849  IF(isprivileged)
1850   pe("third party programs can not be executed with privileged access",0);
1851  E{
1852   /* pair the two duplicate fd's. */
1853   IF(socketpair(PF_UNIX,SOCK_STREAM,0,fd)==-1){
1854    pe("execution dump failed, incoming data resumed",0);
1855    R;
1856   }
1857   SW(fp=FK()){
1858    CS -1:
1859     pe("execution dump failed, incoming data resumed",0);
1860     CL(fd[0]);
1861     CL(fd[1]);
1862     BR;
1863    CS 0:
1864     /* close, and duplicate the fd's.  if netscript is in the background */
1865     /* this will not want to be evaluated. */
1866     IF(!isbga){
1867      CL(0);
1868      CL(1);
1869      CL(2);
1870     }
1871     /* this will allow interaction inside the program, stdin->socket. */
1872     /* if desired. */
1873     IF(isiexec)
1874      D(sock,0);
1875     /* output. */
1876     D(fd[1],1);
1877     D(fd[1],2);
1878     /* better than a raw execution. */
1879     EL(eshell,eshell,"-c",path,0);
1880     /* make sure the handler is still defined, should be anyways. */
1881     SG(SIGINT,sighandler);
1882     /* should never make it here.  if it does, since its duplicated, it will */
1883     /* send any output to the socket.  so, looks better just to be silent. */
1884     _exit(1);
1885     BR;
1886    default:
1887     /* ignore temporarily to send the signal only to the forked pid. */
1888     SG(SIGINT,SIG_IGN);
1889     FD_ZERO(&ffd);
1890     FD_SET(fd[0],&ffd);
1891     W(!k){
1892      /* defined amount of delay time, 3 seconds by default. (-x option) */
1893      tv.tv_sec=(xalrm?xalrm:3);
1894      /* no need to be so precise. */
1895      tv.tv_usec=0;
1896      IF((s=SE((fd[0]+1),&ffd,0,0,&tv))>0){
1897       B(eread,(BASE_BUFFER*8+1));
1898       IF(RD(fd[0],eread,(BASE_BUFFER*8))){
1899        F(i=0;(s>0&&i<SL(eread));i++){
1900         IF(eread[i]==0x0A||eread[i]==0x0D||j>=(BASE_BUFFER*8)){
1901          /* count back for the missed byte. */
1902          IF(j>=(BASE_BUFFER*8))
1903           i--;
1904          ereadl[j]=0x0;
1905          IF(type&&!r){
1906           /* free the pre-placed "null". */
1907           FR(execformat);
1908           IF(!(execformat=(C *)SDU(ereadl)))
1909            pe("dumpexec(): duplication of memory error",1);
1910           /* let other positions know the buffer is set. */
1911           r=1;
1912           /* can only use one line.  so, (fool) exit after one exists. */
1913           s=0;
1914          }
1915          E
1916           dumpexecline(ereadl);
1917          B(ereadl,(BASE_BUFFER*8+1));
1918          /* reset counter. */
1919          j=0;
1920         }
1921         E
1922          ereadl[j++]=eread[i];
1923        }
1924        B(eread,(BASE_BUFFER*8+1));
1925       }
1926      }
1927      /* if statement, and not else.  because, of the fool exit possibility. */
1928      IF(s<=0){
1929       /* cap it off, for the next function. */
1930       ereadl[j]=0x0;
1931       IF(type&&!r&&SL(ereadl)){
1932        /* free the pre-placed "null". */
1933        FR(execformat);
1934        IF(!(execformat=(C *)SDU(ereadl)))
1935         pe("dumpexec(): duplication of memory error",1);
1936        /* no need to set short r, to notify, it is never used again. */
1937       }
1938       /* will dump any leftovers, as if there was a CR. */
1939       E
1940        dumpexecline(ereadl);
1941       B(ereadl,(BASE_BUFFER*8+1));
1942       /* force it, incase it timed out. */
1943       K(fp,SIGKILL);
1944       /* wait up, do not want defunctness. */
1945       WP(fp,0,0);
1946       /* bye bye. */
1947       CL(fd[0]);
1948       CL(fd[1]);
1949       /* unignore ctrl-c aborts. */
1950       SG(SIGINT,sighandler);
1951       k=1;
1952      }
1953     }
1954     BR;
1955   }
1956  }
1957  /* it would never make it to this point two times with variable usage. */
1958  /* so, no need to support such an event.  required information. */
1959  IF(runexit&&!type)
1960   pe("completed execution dump, exiting netscript",1);
1961  EI(!noshowp&&!type)
1962   pe("completed execution dump, incoming data resumed",0);
1963  R;
1964 }
1965 /* to actually handle the line passed from dumpexec(). */
dumpexecline(C * line)1966 V dumpexecline(C *line){
1967  U C *dump;
1968  IF(SL(line)){
1969   IF(!(dump=(C *)M(SL(line)+(runpre?SL(execpre):0)+1)))
1970    pe("dumpexecline(): allocation of memory error",1);
1971   B(dump,(SL(line)+(runpre?SL(execpre):0)+1));
1972   IF(runpre)
1973    SCA(dump,execpre);
1974   SCA(dump,line);
1975   /* last use of eread for this run. */
1976   IF(!nossend)
1977    pd(dump,0,columns);
1978   wro(dump,SL(dump),0);
1979   wro("\n",1,0);
1980   /* add the output to the log, if enabled. (-l option) */
1981   IF(islog&&!tnetraw)
1982    logdata(dump,0);
1983   /* last use of dump for this run. */
1984   FR(dump);
1985  }
1986  R;
1987 }
1988 /* small function to close sockets.  related to connecting, and binding. */
closesocket(U SH type)1989 V closesocket(U SH type){
1990  /* server connection/connected. (and routed along with it) */
1991  IF(!type){
1992   IF(sock>=0){
1993    SD(sock,2);
1994    CL(sock);
1995    sock=-1;
1996   }
1997   IF(setroute&&rsock>=0){
1998    SD(rsock,2);
1999    CL(rsock);
2000    rsock=-1;
2001   }
2002  }
2003  /* server bind socket. */
2004  E{
2005   IF(ssock>=0){
2006    SD(ssock,2);
2007    CL(ssock);
2008    ssock=-1;
2009   }
2010  }
2011  R;
2012 }
2013 /* this function handles the user supplied socket option(s). */
parsesocketopt(I type,I sockv)2014 V parsesocketopt(I type,I sockv){
2015  U I i=0;
2016  I j=0;
2017  I soargs[2];
2018  C *curopt;
2019  /* even if no options are set, set this automatically. (bind socket only) */
2020  IF(type==1){
2021   j=1;
2022   SSO(sockv,SOL_SOCKET,SO_REUSEADDR,(V *)&j,SO(j));
2023   /* was not defined on one of the supported platforms, check to be safe. */
2024 #ifdef SO_REUSEPORT
2025   SSO(sockv,SOL_SOCKET,SO_REUSEPORT,(V *)&j,SO(j));
2026 #endif
2027  }
2028  IF(soptions){
2029   parsedynamic(sopts);
2030   /* find out the size of the buffer needed. */
2031   W(!parameter(parseddynamic,i++,0x3A)){
2032    IF(!(curopt=(C *)SDU(parm)))
2033     pe("parsesocketopt(): duplication of memory error",1);
2034    parameter(curopt,0,0x2C);
2035    /* int->int comparison. */
2036    IF(AI(curopt)==type){
2037     B((V *)soargs,SO(soargs));
2038     IF(!parameter(curopt,1,0x2C)){
2039      soargs[0]=AI(parm);
2040      IF(!parameter(curopt,2,0x2C)){
2041       soargs[1]=AI(parm);
2042       IF(SSO(sockv,SOL_SOCKET,soargs[0],(V *)&soargs[1],SO(soargs[1])))
2043        pe("internal setting of socket option failed",0);
2044      }
2045     }
2046    }
2047    FR(curopt);
2048   }
2049  }
2050  R;
2051 }
2052 /* the socket connection, and line parser.  takes the data from the remote */
2053 /* host, and puts it in a per line format, then passes it along to the match */
2054 /* function(s).  also includes some specific variable handling. */
parsesocket(C * host,U I port)2055 V parsesocket(C *host,U I port){
2056  /* this is only used in this function. */
2057  U SH stoprules=0;
2058  /* many loop ints used to help keep track of what is what.  still re-used */
2059  /* some i knew would never cross paths. */
2060  U I i=0;
2061  U I j=0;
2062  U I k=0;
2063  U I l=0;
2064  U I m=0;
2065  U I n=0;
2066  U I o=0;
2067  U I p=0;
2068  U I q=0;
2069  U I r=0;
2070  U I s=0;
2071  /* for the $, truncation variable. */
2072  SI I left=0;
2073  SI I right=0;
2074  /* socket (size) related. */
2075  SI I salen=0;
2076  /* file dump read buffer. (variable $<) */
2077  U C dread[(BASE_BUFFER*4+1)];
2078  /* special read buffer for initial data. */
2079  U C iread[(BASE_BUFFER*4+1)];
2080  /* initial write buffer. */
2081  U C iwrite[(BASE_BUFFER*4+1)];
2082  /* read buffer for socket data.  needs comparisons. */
2083  U C sread[(BASE_BUFFER*4+1)];
2084  /* buffer for data built up till a completed line, otherwise gets cleared. */
2085  /* allowance of large lines. */
2086  U C sreadl[(BASE_BUFFER*16+1)];
2087  /* three byte response buffer, for telnet protocol responses. */
2088  U C telnet[3];
2089  /* single byte, multiple uses.  no comparisons. */
2090  C sb[1];
2091  S hostent *he;
2092  /* connect to socket / bind client socket. */
2093  S SAN ns;
2094  /* bind server socket. */
2095  S SAN sns;
2096  /* route client socket. */
2097  S SAN rns;
2098  /* for the $"(time passed) rule. */
2099  T ctm;
2100  T rtm;
2101  FL *dfd;
2102  FL *ifd;
2103  /* reset the line values to one. (-L option) */
2104  IF(lnum)
2105   lnum_i=lnum_o=1;
2106  IF(!noshowc)
2107   /* could have used tot_i, or tot_o for the second argument, i used tot_i. */
2108   nsprint("[%lu@%s] * Session started with %d rule(s) defined.\n",cpid,nname,
2109   tot_i);
2110  /* handling for socket binding. */
2111  IF(bindmode){
2112   /* only happens on the first binding. (for forever mode) */
2113   /* unless udp mode is active, then will rebind. */
2114   IF(bindmode!=2||isudp){
2115    /* main server sockaddr structure. */
2116    if(isudp)
2117      sock=SK(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
2118    else
2119      ssock=SK(AF_INET,SOCK_STREAM,IPPROTO_TCP);
2120    parsesocketopt(1,(isudp?sock:ssock));
2121    B((V *)&sns,SO(sns));
2122    sns.sin_family=AF_INET;
2123    sns.sin_port=HS(port);
2124    IF(isvhost){
2125     /* resolve/set the host. */
2126     IF((sns.sin_addr.s_addr=IA(vhost))){
2127      IF(!(he=GH(vhost))){
2128       IF(!noshowc)
2129        nsprint("[%lu@%s] * Could not resolve the provided virtual host, using "
2130        "any...\n",cpid,nname);
2131       sns.sin_addr.s_addr=HL(INADDR_ANY);
2132      }
2133      E
2134       MC((C *)&sns.sin_addr,(C *)he->h_addr,SO(sns.sin_addr));
2135     }
2136     E
2137      sns.sin_addr.s_addr=HL(INADDR_ANY);
2138    }
2139    /* bind to the ip/port. (-b option) */
2140    IF(BI((isudp?sock:ssock),(S SA *)&sns,SO(sns))<0){
2141     IF(!noshowc)
2142      nsprint("[%lu@%s] * Bind failed: %s.\n",cpid,nname,strerror(errno));
2143     /* yet again.  better safe than sorry, do not want fds to fill up. */
2144     closesocket(0);
2145     closesocket(1);
2146     R;
2147    }
2148    /* so it does not re-bind, again. */
2149    bindmode=2;
2150   }
2151   IF(!noshowc)
2152    nsprint("[%lu@%s] * Awaiting incoming connection...\n",cpid,nname);
2153   /* one time connection(per listen), should not need more than one. */
2154   IF(isudp){
2155    i=SO(S SA);
2156    IF(RF(sock,sread,(BASE_BUFFER*4),MSG_PEEK,(S SA *)&sns,&i)<0){
2157      nsprint("[%lu@%s] * Bind failed: recvfrom()\n",cpid,nname);
2158     /* close up shop. */
2159     closesocket(0);
2160     closesocket(1);
2161     R;
2162    }
2163    IF(CO(sock,(S SA *)&sns,SO(sns))){
2164     IF(!noshowc)
2165      nsprint("[%lu@%s] * Connection failed: %s.\n",cpid,nname,strerror(errno));
2166     R;
2167    }
2168   }
2169   E{
2170    IF(LI(ssock,blog)<0){
2171     pe("could not listen on supplied port",0);
2172     R;
2173    }
2174    salen=SO(ns);
2175    IF((sock=AT(ssock,(S SA *)&ns,&salen))<0){
2176     pe("could not accept remote connection",0);
2177     R;
2178    }
2179    parsesocketopt(0,sock);
2180   }
2181   /* close it, if its just one time. (bind) */
2182   IF(!forever)
2183    closesocket(1);
2184   IF(isudp){
2185    i=SO(ns);
2186    /* if fails, doesnt really matter. (hopefully) */
2187    GPN(sock,(S SA *)&ns,&i);
2188   }
2189   IF(!noshowc){
2190    nsprint("[%lu@%s] * Accepted connection from: %s:%d.\n",cpid,nname,
2191    /* since these ips do not really exist, other than in an error */
2192    /* situation.  blank out the confusion of an error. */
2193 #ifndef DISABLE_SRCIP
2194    ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))
2195    ?NOSRCIP:IN(ns.sin_addr))
2196 #else
2197    NOSRCIP
2198 #endif
2199    ,port);
2200   }
2201  }
2202  /* handling for socket connection. */
2203  E{
2204   sock=SK(AF_INET,(isudp?SOCK_DGRAM:SOCK_STREAM),(isudp?IPPROTO_UDP:
2205   IPPROTO_TCP));
2206   parsesocketopt(0,sock);
2207   B((V *)&ns,SO(ns));
2208   ns.sin_family=AF_INET;
2209   IF(isvhost){
2210    /* resolve/set the host. */
2211    IF((ns.sin_addr.s_addr=IA(vhost))){
2212     IF(!(he=GH(vhost))){
2213      IF(!noshowc)
2214       nsprint("[%lu@%s] * Could not resolve the provided virtual host, using a"
2215       "ny...\n",cpid,nname);
2216      ns.sin_addr.s_addr=HL(INADDR_ANY);
2217     }
2218     E
2219      MC((C *)&ns.sin_addr,(C *)he->h_addr,SO(ns.sin_addr));
2220    }
2221    IF(BI(sock,(S SA *)&ns,SO(ns))<0){
2222     /* clean up, and use any. */
2223     pe("error binding name to socket, using any",0);
2224     B((V *)&ns,SO(ns));
2225     ns.sin_family=AF_INET;
2226     ns.sin_addr.s_addr=HL(INADDR_ANY);
2227     IF(BI(sock,(S SA *)&ns,SO(ns))<0)
2228      pe("could not bind name properly",0);
2229    }
2230   }
2231   B((V *)&ns,SO(ns));
2232   ns.sin_family=AF_INET;
2233   ns.sin_port=HS(port);
2234   IF(!noshowc)
2235    nsprint("[%lu@%s] * Checking the provided host...\n",cpid,nname);
2236   IF((ns.sin_addr.s_addr=IA(host))){
2237    /* if not valid, attempts to resolve as a host. */
2238    IF(!(he=GH(host))){
2239     /* nothing left to try. */
2240     IF(!noshowc)
2241      nsprint("[%lu@%s] * Could not resolve the provided host.\n",cpid,nname);
2242     R;
2243    }
2244    E
2245     /* successfully resolved. */
2246     MC((C *)&ns.sin_addr,(C *)he->h_addr,SO(ns.sin_addr));
2247   }
2248   IF(!noshowc)
2249    nsprint("[%lu@%s] * Attempting to connect to the provided host...\n",cpid,
2250    nname);
2251   /* if you can not connect to the server the first time might as well kill */
2252   /* the program, same problem would continue infinitely.  so, if it times */
2253   /* out after ??(2 minutes by default) seconds it will just exit. */
2254   IF(G(ENV_TIMEOUT)&&AI((C *)G(ENV_TIMEOUT))>0)
2255    A(AI((C *)G(ENV_TIMEOUT)));
2256   E
2257    A(DFL_TIMEOUT);
2258   /* like it looks, attempts to connect to the remote server. */
2259   IF(CO(sock,(S SA *)&ns,SO(ns))){
2260    A(0);
2261    IF(!noshowc)
2262     nsprint("[%lu@%s] * Connection failed: %s.\n",cpid,nname,strerror(errno));
2263    R;
2264   }
2265   E{
2266    A(0);
2267    IF(!noshowc)
2268     nsprint("[%lu@%s] * %s: %s:%d.\n",cpid,nname,(isudp?"Created connection":
2269     "Connected successfully"),
2270     /* since these ips do not really exist, other than in an error */
2271     /* situation.  blank out the confusion of an error. */
2272 #ifndef DISABLE_SRCIP
2273     ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))?
2274     NOSRCIP:IN(ns.sin_addr))
2275 #else
2276     NOSRCIP
2277 #endif
2278     ,port);
2279   }
2280  }
2281  /* only do the following if outside GTK+. (changing id levels would make */
2282  /* for display problems) */
2283 #ifdef GTK
2284  IF(!isgui){
2285 #endif
2286   /* set the permissions before taking any input, or sending any output. */
2287   /* only done once.  since binding would have occured already. */
2288   IF(setperms){
2289    setpermissions(0,1);
2290    setperms=0;
2291   }
2292 #ifdef GTK
2293  }
2294 #endif
2295 #ifndef DISABLE_SYSLOG
2296  wrso("%d-%d id: %lu-%u.%u.%u.%u remote: %s-%u type: %s",slnum_t,(slnum_s++),
2297  cpid,GU(),GEU(),GG(),GEG(),
2298 #ifndef DISABLE_SRCIP
2299  ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))?
2300  NOSRCIP:IN(ns.sin_addr))
2301 #else
2302  NOSRCIP
2303 #endif
2304  ,port,(bindmode?"incoming":"outgoing"));
2305 #endif
2306  IF(setroute){
2307   rsock=SK(AF_INET,(isudpr?SOCK_DGRAM:SOCK_STREAM),(isudpr?IPPROTO_UDP:
2308   IPPROTO_TCP));
2309   parsesocketopt(2,rsock);
2310   B((V *)&rns,SO(rns));
2311   rns.sin_family=AF_INET;
2312   IF(isvhost){
2313    IF((rns.sin_addr.s_addr=IA(vhost))){
2314     IF(!(he=GH(vhost))){
2315      IF(!noshowc)
2316       nsprint("[%lu@%s] * Could not resolve the provided virtual host, using a"
2317       "ny...\n",cpid,nname);
2318      rns.sin_addr.s_addr=HL(INADDR_ANY);
2319     }
2320     E
2321      MC((C *)&rns.sin_addr,(C *)he->h_addr,SO(rns.sin_addr));
2322    }
2323    IF(BI(rsock,(S SA *)&rns,SO(rns))<0){
2324     /* clean up, and use any. */
2325     pe("error binding name to socket, using any",0);
2326     B((V *)&rns,SO(rns));
2327     rns.sin_family=AF_INET;
2328     rns.sin_addr.s_addr=HL(INADDR_ANY);
2329     IF(BI(rsock,(S SA *)&rns,SO(rns))<0){
2330      pe("could not bind name properly, proceeding anyways",0);
2331      rsock=-1;
2332     }
2333    }
2334   }
2335   IF(rsock!=-1){
2336    B((V *)&rns,SO(rns));
2337    rns.sin_family=AF_INET;
2338    rns.sin_port=HS(rport);
2339    IF(!noshowc)
2340     nsprint("[%lu@%s] * Checking the provided (route) host...\n",cpid,nname);
2341    IF((rns.sin_addr.s_addr=IA(rhost))){
2342     /* if not valid, attempts to resolve as a host. */
2343     IF(!(he=GH(rhost))){
2344      /* nothing left to do. */
2345      IF(!noshowc)
2346       nsprint("[%lu@%s] * Could not resolve the provided host, proceeding anyw"
2347       "ays...\n",cpid,nname);
2348      rsock=-1;
2349     }
2350     E
2351      /* successfully resolved. */
2352      MC((C *)&rns.sin_addr,(C *)he->h_addr,SO(rns.sin_addr));
2353    }
2354    IF(!noshowc&&rsock!=-1)
2355     nsprint("[%lu@%s] * Attempting to connect to the provided (route) host..."
2356     "\n",cpid,nname);
2357    IF(G(ENV_TIMEOUT)&&AI((C *)G(ENV_TIMEOUT))>0)
2358     A(AI((C *)G(ENV_TIMEOUT)));
2359    E
2360     A(DFL_TIMEOUT);
2361    IF(rsock==-1||CO(rsock,(S SA *)&rns,SO(rns))){
2362     A(0);
2363     IF(rsock!=-1&&!noshowc)
2364      nsprint("[%lu@%s] * Route connection failed: %s. (proceeding)\n",cpid,
2365      nname,strerror(errno));
2366     /* ensure the error is known. */
2367     rsock=-1;
2368    }
2369    E{
2370     A(0);
2371     IF(!noshowc)
2372      nsprint("[%lu@%s] * Connected (route) successfully: %s:%d.\n",cpid,nname,
2373 #ifndef DISABLE_SRCIP
2374      ((!SC(IN(rns.sin_addr),"255.255.255.255")||!SC(IN(rns.sin_addr),"0.0.0.0")
2375      )?NOSRCIP:IN(rns.sin_addr))
2376 #else
2377      NOSRCIP
2378 #endif
2379      ,rport);
2380    }
2381   }
2382  }
2383  /* states log start time, and ip that was used.  if enabled. (-l option) */
2384  IF(islog&&!tnetraw){
2385   logdata("NEW NETSCRIPT SESSION STARTED.",2);
2386   /* logging of the ip used. */
2387   logdata(
2388   /* since these ips do not really exist, other than in an error situation. */
2389   /* blank out the confusion of an error. */
2390 #ifndef DISABLE_SRCIP
2391   ((!SC(IN(ns.sin_addr),"255.255.255.255")||!SC(IN(ns.sin_addr),"0.0.0.0"))?
2392   NOSRCIP:IN(ns.sin_addr))
2393 #else
2394   NOSRCIP
2395 #endif
2396   ,2);
2397  }
2398  /* check, and use the ns_connect() symbol, it passes the connection type, */
2399  /* ip value, and port. (short, unsigned long int, int) */
2400 #ifndef DISABLE_MODULES
2401  IF(vmodule)
2402   (*connect_function)(bindmode,ns.sin_addr,port);
2403 #endif
2404  /* for the $" rule, will set the time of the connection to be compared to. */
2405  TM(&rtm);
2406  /* cleans out the dynamic (int)buffer for the "one time" variable. */
2407  B((V *)rs_dynamic,SO(rs_dynamic));
2408  /* this is for the "$." variable, it makes it not truely static.  resets */
2409  /* every connection if the value is two. (or back to one) */
2410  F(i=0;i<tot_i;i++){
2411   IF(rs_static[i]>1)
2412    rs_static[i]-=2;
2413  }
2414  /* cleans out the dynamic (int)buffer for variable data. (usable) */
2415  /* little more involved than a bzero() for the static vars set by the */
2416  /* command line. */
2417  F(i=0;i<10;i++){
2418   IF(dynamicvarset[i]==1){
2419    FR(dynamicvar[i]);
2420    dynamicvarset[i]=0;
2421   }
2422  }
2423  IF(initsend){
2424   /* handle the unique initial input data.  if it is a "?" it will prompt */
2425   /* for input.  make sure not to allow if backgrounded. */
2426   IF(!SC(iswrite,"?")&&!isbga){
2427    /* gui version of the request. */
2428 #ifdef GTK
2429    IF(isgui){
2430     IF(isguiwait)
2431      R;
2432     E{
2433      nsprint("input request: enter dynamic initial data to send.\n");
2434      /* only if non-generic. */
2435      IF(!isbgui){
2436       GTE();
2437       /* make sure focus is on the entry box. */
2438       GWGF(gen);
2439       /* show the entry box. */
2440       GWS(gen);
2441       GTL();
2442      }
2443      isguiwait=1;
2444      W(isguiwait)
2445       USLP(250000);
2446     }
2447    }
2448    /* typical version of the request. */
2449    E{
2450 #endif
2451     IF(!(ifd=FO(ttyn,"r")))
2452      pe("could not open standard input for read",0);
2453     E{
2454      /* none of this will work anyways if backgrounded.  will close the fd. */
2455      IF(!isbga){
2456       IF(!noshowp)
2457        pe("initial send defined user input, incoming data suspended",0);
2458       /* show default, or reason prompt, if not in raw mode. */
2459       IF(!tnetraw)
2460        nsprint("enter initial data to send: ");
2461       B(iread,(BASE_BUFFER*4+1));
2462       /* truncated for pd(). */
2463       IF(FS(iread,(SO(iread)-1),ifd))
2464        F(o=0;o<SL(iread);o++)
2465         IF(iread[o]==0x0A)
2466          iread[o]=0x0;
2467       IF(!noshowp)
2468        pe("input received, incoming data resumed",0);
2469       IF(!nossend)
2470        pd(iread,0,columns);
2471       wro(iread,SL(iread),0);
2472       wro("\n",1,0);
2473       IF(islog&&!tnetraw)
2474        logdata(iread,0);
2475      }
2476      FC(ifd);
2477     }
2478 #ifdef GTK
2479    }
2480 #endif
2481   }
2482   E{
2483    /* sends the initial data supplied by the argument if supplied. */
2484    IF(!nossend)
2485     pd(iswrite,0,columns);
2486    wro(iswrite,SL(iswrite),0);
2487    wro("\n",1,0);
2488    /* add the initial data to the log, if enabled. (-i, and -l option) */
2489    IF(islog&&!tnetraw)
2490     logdata(iswrite,0);
2491   }
2492  }
2493  IF(runcmd)
2494   dumpexec(execfile,0);
2495  IF(alrm)
2496   A(alrm);
2497  W(1){
2498   B(sread,(BASE_BUFFER*4+1));
2499   IF(!RD(sock,sread,(SO(sread)-1))){
2500    pe("socket reading halted/finished",0);
2501    closesocket(0);
2502    R;
2503   }
2504   /* handle incoming telnet dumping. (-y, and -Y options) */
2505   dumptelnet(sread);
2506   IF(islog&&tnetraw)
2507    logdata(sread,3);
2508   /* check, and use the ns_incoming_raw() symbol.  it passes the raw dump of */
2509   /* the socket read buffer, the size of the buffer, and the length of the */
2510   /* buffer. (char *, int, int) */
2511 #ifndef DISABLE_MODULES
2512   IF(vmodule)
2513    (*incoming_raw_function)(sread,SO(sread),SL(sread));
2514 #endif
2515   F(i=0;i<SL(sread);i++){
2516    /* telnet protocol handling, bytes set before handled. */
2517    /* using this method will have socket reading not wait for a \r, or a \n. */
2518    /* (the -T option) */
2519    IF(tnet&&sread[i]==0xFF&&sread[i+1]&&sread[i+2]){
2520     B(telnet,3);
2521     telnet[0]=0xFF;
2522     IF(sread[i+1]==0xFC||sread[i+1]==0xFB)
2523      telnet[1]=0xFE;
2524     EI(sread[i+1]==0xFE||sread[i+1]==0xFD)
2525      telnet[1]=0xFC;
2526     IF(telnet[1]==0xFE||telnet[1]==0xFC){
2527      /* checks to change socket handling for later. */
2528      IF(!truetnet){
2529       pe("received a telnet protocol option, entering telnet reading mode",0);
2530       truetnet=1;
2531      }
2532      /* the option. */
2533      telnet[2]=sread[i+2];
2534      wro(telnet,SO(telnet),0);
2535      IF(!nossend&&!notnetopt)
2536       nsprint("%s(TELNETD-OPT REPLIED: 0x%.2x 0x%.2x 0x%.2x -> 0x%.2x 0x%.2x "
2537       "0x%.2x)\n",!nofrom?"-> ":"",sread[i],sread[i+1],sread[i+2],telnet[0],
2538       telnet[1],telnet[2]);
2539     }
2540    }
2541    /* telnet mode will not wait for a \r, or \n, must get one or more telnet */
2542    /* option before automatically allowed. so, not to create problems with */
2543    /* bad syntax. */
2544    IF(sread[i]==0x0A||sread[i]==0x0D||(tnet&&truetnet&&!sread[i+1])){
2545     /* check where to place the null byte, and make sure byte exists for the */
2546     /* extended null byte.  it will not add the last byte if its the last */
2547     /* byte. */
2548     IF(tnet&&truetnet&&!sread[i+1]&&(BASE_BUFFER*16+1)>(j+1)){
2549      /* check, and use the ns_incoming_char() symbol, it passes the byte to */
2550      /* be added to the buffer. (int) */
2551 #ifndef DISABLE_MODULES
2552      IF(vmodule)
2553       (*incoming_char_function)(sread[i]);
2554 #endif
2555      /* append the byte that is usually a \r, or \n.  but, for telent */
2556      /* support a non-static character. */
2557      sreadl[j]=sread[i];
2558      sreadl[(j+1)]=0x0;
2559     }
2560     E
2561      sreadl[j]=0x0;
2562     /* handle the -S, and -U command line arguments for delaying. */
2563     IF(sdelay)
2564      SLP(sdelay);
2565     IF(sudelay)
2566      USLP(sudelay);
2567     /* pass to the routed host, if enabled. (-R option) */
2568     IF(setroute){
2569      wro(sreadl,SL(sreadl),1);
2570      IF(SL(sreadl))
2571       wro("\n",1,1);
2572     }
2573     /* check, and use the ns_incoming() symbol, it passes the incoming */
2574     /* string of data, the size of that data, and the socket value. */
2575     /* (char *, int, int) */
2576 #ifndef DISABLE_MODULES
2577     IF(vmodule&&SL(sreadl))
2578      (*incoming_function)(sreadl,SL(sreadl),sock);
2579 #endif
2580     IF(!nosrecv)
2581      pd(sreadl,1,columns);
2582     /* add the output to the log, if enabled. (-l option) */
2583     IF(islog&&!tnetraw)
2584      logdata(sreadl,1);
2585     /* reset the temporary variable. */
2586     IF(stoprules==2)
2587      stoprules=0;
2588     F(k=0;k<tot_i&&SL(sreadl);k++){
2589      /* have not formed the swrite buffer yet, read the output for the */
2590      /* start variable, no need to modify anything yet anyways. */
2591      IF((!stoprules||!SNCC(output[k],NS_START,SL(NS_START)))&&!prewordmatch(
2592      input[k],sreadl)&&!(rs_static[k]&&rs_dynamic[k])){
2593       /* cancel possibility of a repeated rule. */
2594       IF(rs_static[k]){
2595        IF(!noshowp)
2596         pe("ruleset defined this rule to only be used once",0);
2597        rs_dynamic[k]=1;
2598       }
2599       IF(rs_delay[k]){
2600        IF(!noshowp)
2601         pe("ruleset defined a delay before processing of this rule",0);
2602        SLP(rs_delay[k]);
2603       }
2604       /* parse the arguments input->output, $1 $2 $3, makes swrite buf. */
2605       /* rules will redo this for possible skipped arguments in this run. */
2606       /* it will be done when the buffer gets chomped down using a rule. */
2607       parseoutput(sreadl,output[k]);
2608       /* check, and handle the direct stop variable. */
2609       IF(!SNCC(swrite,NS_STOP,SL(NS_STOP))){
2610        /* changes buffer to dump the variable.  for later display. */
2611        truncateoutput(SL(NS_STOP));
2612        /* update the new clean buffer. */
2613        parseoutput(sreadl,swrite);
2614        /* no possibility of format bug, pe() handles like text. */
2615        IF(!noshowp)
2616         pe(SL(swrite)?swrite:"ruleset defined ruleset stop",0);
2617        stoprules=1;
2618       }
2619       /* check, and handle the direct restart variable, even without stop. */
2620       EI(!SNCC(swrite,NS_START,SL(NS_START))){
2621        /* changes buffer to dump the variable.  for later display. */
2622        truncateoutput(SL(NS_START));
2623        /* update the new clean buffer. */
2624        parseoutput(sreadl,swrite);
2625        /* no possibility of format bug, pe() handles like text. */
2626        IF(!noshowp)
2627         pe(SL(swrite)?swrite:"ruleset defined ruleset start",0);
2628        stoprules=0;
2629       }
2630       /* check, and handle for the direct halt variable. */
2631       EI(!SNCC(swrite,NS_HALT,SL(NS_HALT))){
2632        /* changes buffer to dump the variable.  for later display. */
2633        truncateoutput(SL(NS_HALT));
2634        /* update the new clean buffer. */
2635        parseoutput(sreadl,swrite);
2636        /* no possibility of format bug, pe() handles like text. */
2637        IF(!noshowp)
2638         pe(SL(swrite)?swrite:"ruleset defined halt from continuing",0);
2639        stoprules=2;
2640       }
2641       /* check, and handle for the direct quit variable. */
2642       EI(!SNCC(swrite,NS_QUIT,SL(NS_QUIT))){
2643        /* changes buffer to dump the variable.  for later display. */
2644        truncateoutput(SL(NS_QUIT));
2645        /* update the new clean buffer. */
2646        parseoutput(sreadl,swrite);
2647        /* no possibility of format bug, pe() handles like text. */
2648        IF(!noshowp)
2649         pe(SL(swrite)?swrite:"ruleset defined socket kill",0);
2650        closesocket(0);
2651        R;
2652       }
2653       /* check, and handle the direct ask variable. */
2654       EI(!SNCC(swrite,NS_ASK,SL(NS_ASK))){
2655        /* can not exactly do this if it is backgrounded. */
2656        IF(isbga)
2657         R;
2658        /* changes buffer to dump the variable.  for later display. */
2659        truncateoutput(SL(NS_ASK));
2660        /* update the new clean buffer. */
2661        parseoutput(sreadl,swrite);
2662        /* gui version of the request. */
2663 #ifdef GTK
2664        IF(isgui){
2665         IF(isguiwait)
2666          R;
2667         E{
2668          nsprint("input request: %s.\n",SL(swrite)?swrite:"enter response");
2669          /* only if non-generic. */
2670          IF(!isbgui){
2671           GTE();
2672           /* make sure focus is on the entry box. */
2673           GWGF(gen);
2674           /* show the entry box. */
2675           GWS(gen);
2676           GTL();
2677          }
2678          isguiwait=1;
2679          W(isguiwait)
2680           USLP(250000);
2681         }
2682        }
2683        /* typical version of the request. */
2684        E{
2685 #endif
2686         IF(!(ifd=FO(ttyn,"r")))
2687          pe("could not open standard input for read",0);
2688         E{
2689          IF(!noshowp)
2690           pe("ruleset defined user input, incoming data suspended",0);
2691          /* show default, or reason prompt, if not in raw mode. */
2692          IF(!tnetraw)
2693           nsprint("%s: ",SL(swrite)?swrite:"enter response");
2694          B(iwrite,(BASE_BUFFER*4+1));
2695 #ifdef NCURSES
2696          IF(isncurses)
2697           wgetnstr(nw3,iwrite,(SO(iwrite)-1));
2698          E
2699 #endif
2700          IF(FS(iwrite,(SO(iwrite)-1),ifd))
2701           F(o=0;o<SL(iwrite);o++)
2702            IF(iwrite[o]==0x0A)
2703             iwrite[o]=0x0;
2704          IF(!noshowp)
2705           pe("input received, incoming data resumed",0);
2706          IF(!nossend)
2707           pd(iwrite,0,columns);
2708          wro(iwrite,SL(iwrite),0);
2709          wro("\n",1,0);
2710          IF(islog&&!tnetraw)
2711           logdata(iwrite,0);
2712          FC(ifd);
2713         }
2714 #ifdef GTK
2715        }
2716 #endif
2717       }
2718       /* check, and handle the remove/replace variable. */
2719       EI(!SNCC(swrite,NS_TRUNC,SL(NS_TRUNC))){
2720        /* changes buffer to dump the variable.  for later use. */
2721        truncateoutput(SL(NS_TRUNC));
2722        /* update the new clean buffer. */
2723        parseoutput(sreadl,swrite);
2724        /* has to have at least one character to remove. */
2725        IF(SL(swrite)==1){
2726         F(l=0;l<SL(sreadl);l++)
2727          IF(sreadl[l]==swrite[0]){
2728           /* push the rest of the line back. */
2729           F(m=(l+1);m<SL(sreadl);m++){
2730            sreadl[(m-1)]=sreadl[m];
2731           }
2732           /* remove the leftover byte. */
2733           sreadl[(m-1)]=0x0;
2734           /* possibly a new character is here. */
2735           l--;
2736          }
2737        }
2738        /* two, or more replaces.  instead of removal. */
2739        EI(SL(swrite)>1)
2740         F(l=0;l<SL(sreadl);l++)
2741          IF(sreadl[l]==swrite[0])
2742           sreadl[l]=swrite[1];
2743       }
2744       EI(!SNCC(swrite,NS_TOKENL,SL(NS_TOKENL))){
2745        /* changes buffer to dump the variable.  for later use. */
2746        truncateoutput(SL(NS_TOKENL));
2747        /* update the new clean buffer. */
2748        parseoutput(sreadl,swrite);
2749        IF(SL(swrite)>0)
2750         /* using the int again here. */
2751         F(l=0;l<SL(sreadl);l++)
2752          IF(sreadl[l]==swrite[0])
2753           sreadl[l]=0x0;
2754       }
2755       EI(!SNCC(swrite,NS_TOKENR,SL(NS_TOKENR))){
2756        /* changes buffer to dump the variable.  for later use. */
2757        truncateoutput(SL(NS_TOKENR));
2758        /* update the new clean buffer. */
2759        parseoutput(sreadl,swrite);
2760        IF(SL(swrite)>0){
2761         /* using the int(s) again here. */
2762         F(m=l=0;l<SL(sreadl);l++){
2763          IF(m)
2764           sreadl[(l-m)]=sreadl[l];
2765          IF(sreadl[l]==swrite[0]&&!m)
2766           m=(l+1);
2767         }
2768         IF(m)
2769          sreadl[(l-m)]=0x0;
2770        }
2771       }
2772       /* check, and handle the display variable. */
2773       EI(!SNCC(swrite,NS_STR,SL(NS_STR))){
2774        /* changes buffer to dump the variable.  for later use. */
2775        truncateoutput(SL(NS_STR));
2776        /* update the new clean buffer. */
2777        parseoutput(sreadl,swrite);
2778        /* check for the comma with data, so atoi() will not fault. */
2779        IF(!parameter(swrite,0,0x2C))
2780         left=AI(parm);
2781        /* only happens if the variable is by itself. */
2782        E
2783         left=0;
2784        IF(!parameter(swrite,1,0x2C))
2785         right=AI(parm);
2786        /* also, only happens if the variable is by itself. */
2787        E
2788         right=-1;
2789        /* can not be less than zero.  or, should not be.  */
2790        IF(left<0)
2791         left=0;
2792        /* commonly thought that negative values equal to the end of the */
2793        /* line.  agree with the standard. */
2794        IF(right<0||right>SL(sreadl))
2795         right=SL(sreadl);
2796        F(r=q=0;q<SL(sreadl);q++){
2797         /* starts at point(left).  but, stops before point(right). */
2798         IF(q>=left&&q<right)
2799          sreadl[r++]=sreadl[q];
2800        }
2801        sreadl[r]=0x0;
2802       }
2803       /* check, and handle the format variable. */
2804       EI(!SNCC(swrite,NS_FMT,SL(NS_FMT))){
2805        /* changes buffer to dump the variable.  for later formatting. */
2806        truncateoutput(SL(NS_FMT));
2807        /* update the new clean buffer. */
2808        parseoutput(sreadl,swrite);
2809        /* clean it out. */
2810        B(sreadl,(BASE_BUFFER*16+1));
2811        /* byte-by-byte transfer/check. */
2812        F(p=0;((p<(SO(sreadl)-1))&&(p<(SL(swrite))));p++)
2813         sreadl[p]=swrite[p];
2814        sreadl[p]=0x0;
2815       }
2816       /* check, and handle the display variable. */
2817       EI(!SNCC(swrite,NS_ECHO,SL(NS_ECHO))){
2818        /* changes buffer to dump the variable.  for later display. */
2819        truncateoutput(SL(NS_ECHO));
2820        /* update the new clean buffer. */
2821        parseoutput(sreadl,swrite);
2822        /* no possibility of format bug, pe() handles like text. */
2823        /* ruleset defined this, so -C will not cut this off. */
2824        pe(SL(swrite)?swrite:"ruleset defined an empty display rule",0);
2825       }
2826       /* check, and handle the no return write (raw) variable. */
2827       /* shows up like a standard write out. */
2828       EI(!SNCC(swrite,NS_RAW,SL(NS_RAW))){
2829        /* changes buffer to dump the variable.  for later display. */
2830        truncateoutput(SL(NS_RAW));
2831        /* update the new clean buffer. */
2832        parseoutput(sreadl,swrite);
2833        IF(!nossend)
2834         pd(swrite,0,columns);
2835        wro(swrite,SL(swrite),0);
2836       }
2837       /* check, and handle the disable rule variable. */
2838       EI(!SNCC(swrite,NS_DISABLE,SL(NS_DISABLE))){
2839        /* changes buffer to dump the variable.  for later display. */
2840        truncateoutput(SL(NS_DISABLE));
2841        /* update the new clean buffer. */
2842        parseoutput(sreadl,swrite);
2843        IF(SL(swrite)){
2844         l=AI(swrite);
2845         IF(l<tot_i){
2846          IF(!noshowp)
2847           pe("ruleset defined a rule to be disabled",0);
2848          rs_dynamic[l]=1;
2849          /* if the value is two.  so, it will get reset every connection. */
2850          /* will be three if its already set to go off. */
2851          IF(rs_static[l]<=1)
2852           rs_static[l]+=2;
2853         }
2854         E
2855          IF(!noshowp)
2856           pe("ruleset defined a non-existent rule to be disabled",0);
2857        }
2858       }
2859       /* check, and handle the file dump variable. */
2860       EI(!SNCC(swrite,NS_DUMP,SL(NS_DUMP))){
2861        IF(isprivileged)
2862         pe("can not read/dump data from a file with privileged access",0);
2863        E{
2864         /* changes buffer to dump the variable.  for later display. */
2865         truncateoutput(SL(NS_DUMP));
2866         /* update the new clean buffer. */
2867         parseoutput(sreadl,swrite);
2868 #ifndef DISABLE_SYSLOG
2869         wrso("%d-%d id: %lu-%u.%u.%u.%u read: %s",slnum_t,(slnum_s++),cpid,
2870         GU(),GEU(),GG(),GEG(),swrite);
2871 #endif
2872         IF(AC(swrite,R_OK))
2873          pe("could not access the file requested to dump in the ruleset",0);
2874         E{
2875          IF(!(dfd=FO(swrite,"r")))
2876           pe("file requested by ruleset does not appear to exist, or is not re"
2877           "adable",0);
2878          E{
2879           B(dread,(BASE_BUFFER*4+1));
2880           /* no need to parse the data that comes from this file, instead it */
2881           /* directly dumps the file data.  single byte writing for all */
2882           /* character types. */
2883           IF(!noshowp)
2884            pe("ruleset requested a file dump to the remote host",0);
2885           W((n=FG(dfd))!=EOF){
2886            sb[0]=n;
2887            wro(sb,1,0);
2888           }
2889           IF(!noshowp)
2890            pe("ruleset requested file dump was successful",0);
2891          }
2892          FC(dfd);
2893         }
2894        }
2895       }
2896       /* check, and handle the write/append variable.  checks for append */
2897       /* first, beacuse if one variable is going to be larger it will be */
2898       /* the apppend variable. */
2899       EI(!SNCC(swrite,NS_WRITE,SL(NS_WRITE))||!SNCC(swrite,NS_APPEND,
2900       SL(NS_APPEND))){
2901        IF(isprivileged)
2902         pe("can not write data to a file with privileged access",0);
2903        E{
2904         /* find out which variable it is, two in one function here. */
2905         IF(!SNCC(swrite,NS_APPEND,SL(NS_APPEND))){
2906          n=SL(NS_APPEND);
2907          /* append type, fopen(). */
2908          sb[0]=0x61;
2909         }
2910         E{
2911          n=SL(NS_WRITE);
2912          /* write type, fopen(). */
2913          sb[0]=0x77;
2914         }
2915         /* changes buffer to dump the variable.  for later display. */
2916         truncateoutput(n);
2917         /* update the new clean buffer. */
2918         parseoutput(sreadl,swrite);
2919 #ifndef DISABLE_SYSLOG
2920         wrso("%d-%d id: %lu-%u.%u.%u.%u write: %s",slnum_t,(slnum_s++),cpid,
2921         GU(),GEU(),GG(),GEG(),swrite);
2922 #endif
2923         /* check for existence with non-writability. */
2924         IF(!AC(swrite,F_OK)&&AC(swrite,W_OK))
2925          pe("could not access the file requested to write to in the ruleset",
2926          0);
2927         E{
2928          IF(!(dfd=FO(swrite,sb)))
2929           pe("file requested to write to could not be opened properly",0);
2930          E{
2931           FP(dfd,"%s\n",sreadl);
2932           IF(!noshowp)
2933            pe("ruleset requested write out was successful",0);
2934          }
2935          FC(dfd);
2936         }
2937        }
2938       }
2939       /* check, and handle the chdir variable. */
2940       EI(!SNCC(swrite,NS_CHDIR,SL(NS_CHDIR))){
2941        /* changes buffer to dump the variable.  for later display. */
2942        truncateoutput(SL(NS_CHDIR));
2943        /* update the new clean buffer. */
2944        parseoutput(sreadl,swrite);
2945        IF(SL(swrite)){
2946         IF(CD(swrite)){
2947          IF(!noshowp)
2948           pe("ruleset requested directory change failed",0);
2949         }
2950         E{
2951          IF(!noshowp)
2952           pe("ruleset requested directory change was successful",0);
2953         }
2954        }
2955       }
2956       /* check, and handle the (send to) route host variable. */
2957       EI(!SNCC(swrite,NS_ROUTE,SL(NS_ROUTE))){
2958        /* changes buffer to dump the variable.  for later display. */
2959        truncateoutput(SL(NS_ROUTE));
2960        /* update the new clean buffer. */
2961        parseoutput(sreadl,swrite);
2962        IF(SL(swrite)){
2963         IF(rsock==-1){
2964          IF(!noshowp)
2965           pe("rulset requested route write failed, no (open) route socket",0);
2966         }
2967         E{
2968          wro(swrite,SL(swrite),2);
2969          wro("\n",1,2);
2970          IF(!noshowp)
2971           pe("ruleset requested route write was successful",0);
2972         }
2973        }
2974       }
2975       /* check, and handle the time passed (send) variable. */
2976       EI(!SNCC(swrite,NS_TIMED,SL(NS_TIMED))){
2977        /* set the current time to check the value, compared to the */
2978        /* connection value. */
2979        TM(&ctm);
2980        /* changes buffer to dump the variable.  for later display. */
2981        truncateoutput(SL(NS_TIMED));
2982        /* update the new clean buffer. */
2983        parseoutput(sreadl,swrite);
2984        parameter(swrite,0,0x2C);
2985        IF(wischeck(parm,1)&&(rtm+AI(parm))<ctm){
2986         IF(SL(swrite)>(SL(parm)+1)){
2987          truncateoutput(SL(parm)+1);
2988          IF(!nossend)
2989           pd(swrite,0,columns);
2990          wro(swrite,SL(swrite),0);
2991          wro("\n",1,0);
2992         }
2993        }
2994       }
2995       /* check, and handle the execution dump/formatting variables. */
2996       EI(!SNCC(swrite,NS_EXEC,SL(NS_EXEC))||!SNCC(swrite,NS_EXECF,SL(NS_EXECF))
2997       ){
2998        /* will reuse this int again, and again. */
2999        p=(!SNCC(swrite,NS_EXEC,SL(NS_EXEC))?0:1);
3000        /* changes buffer to dump the variable.  for later display. */
3001        truncateoutput(p?SL(NS_EXECF):SL(NS_EXEC));
3002        /* update the new clean buffer. */
3003        parseoutput(sreadl,swrite);
3004        IF(!noshowp&&!p)
3005         pe("ruleset requested a local program execution",0);
3006        /* privileged checking occurs with this function, since its used */
3007        /* elsewhere. */
3008        dumpexec(swrite,p);
3009        IF(p&&SL(execformat)){
3010         /* byte-by-byte transfer/check. (reused int p) */
3011         F(p=0;((p<(SO(sreadl)-1))&&(p<(SL(execformat))));p++)
3012          sreadl[p]=execformat[p];
3013         sreadl[p]=0x0;
3014        }
3015       }
3016       /* not required to check every slot for a byte.  but, i do. */
3017       EI(swrite[0]&&swrite[1]&&swrite[2]&&swrite[3]&&swrite[4]&&swrite[0]==
3018       PARAMETER_VAR_CHAR&&swrite[1]==0x7B&&ID((U I)swrite[2])&&swrite[3]==0x7D
3019       &&swrite[4]==0x3D){
3020        /* store the number before chomping it down. */
3021        s=(swrite[2]-0x30);
3022        /* do not overwrite the statically set variables. */
3023        IF(dynamicvarset[s]!=2){
3024         /* changes buffer to dump the variable.  for later display. */
3025         truncateoutput(5);
3026         /* update the new clean buffer. */
3027         parseoutput(sreadl,swrite);
3028         IF(dynamicvarset[s]==1)
3029          FR(dynamicvar[s]);
3030         IF(!(dynamicvar[s]=(C *)SDU(swrite)))
3031          pe("parsesocket(): duplication of memory error",1);
3032         dynamicvarset[s]=1;
3033        }
3034       }
3035       E{
3036        IF(!nossend)
3037         pd(swrite,0,columns);
3038        wro(swrite,SL(swrite),0);
3039        wro("\n",1,0);
3040        /* add the input to the log, if enabled. (-l option) */
3041        IF(islog&&!tnetraw)
3042         logdata(swrite,0);
3043       }
3044      }
3045     }
3046     B(sreadl,(BASE_BUFFER*16+1));
3047     j=0;
3048    }
3049    E
3050     /* do not print the telnet options, no one wants to see that. */
3051     IF(tnet&&truetnet&&sread[i]==0xFF&&(sread[i+1]==0xFE||sread[i+1]==0xFD||
3052     sread[i+1]==0xFC||sread[i+1]==0xFB))
3053      i+=2;
3054     /* for reading of printable characters only.  meaning non-printable */
3055     /* characters will not make it to ruleset processing.  but, the telnet */
3056     /* protocol handling is processed before this point.  so, it will not be */
3057     /* effected. (-P option).  also, omits defined characters from them -o */
3058     /* option. */
3059     EI((!printonly||IP((U I)sread[i]))&&(!omitchars||!STC(ochars,sread[i]))){
3060      /* check the buffer that is filling until a completed line, making sure */
3061      /* not to exceed bounds.  if it does the buffer is cleared. */
3062      IF(j>=SO(sreadl)){
3063       B(sreadl,(BASE_BUFFER*16+1));
3064       j=0;
3065      }
3066      /* write the byte if nothing before this option wanted to stop it. */
3067      E{
3068       /* check, and use the ns_incoming_char() symbol, it passes the byte to */
3069       /* be added to the buffer. (int) */
3070 #ifndef DISABLE_MODULES
3071       IF(vmodule)
3072        (*incoming_char_function)(sread[i]);
3073 #endif
3074       sreadl[j++]=sread[i];
3075      }
3076     }
3077   }
3078  }
3079  /* once more.  better safe than sorry, do not want fds to fill up. */
3080  closesocket(0);
3081  R;
3082 }
3083 /* for display types of version information. */
showinfo(U SH type)3084 V showinfo(U SH type){
3085  C *timebuf;
3086  T tm;
3087  IF(type==1){
3088   /* left without uname (verbose display) information. */
3089   nsprint("[%lu] * Version: netscript/v%s!%s. -- License: %s.\n"
3090   "[%lu] * Id data: %s\n"
3091   "[%lu] * Mod: %s -- Src: %s -- Arp: %s -- Gui: %s -- Slg: %s -- Ncr: %s.\n"
3092   "[%lu] * Author: %s.%s\n",cpid,VERSION,COMPTYPE,license,cpid,id,cpid,
3093   (defined[0]?"on":"off"),(defined[1]?"on":"off"),(defined[2]?"on":"off"),
3094   (defined[3]?"on":"off"),(defined[4]?"on":"off"),(defined[5]?"on":"off"),
3095   cpid,author,isprivileged?" (privileged)":"");
3096  }
3097  EI(type==2){
3098   TM(&tm);
3099   IF(!(timebuf=(C *)SDU(CT(&tm))))
3100    pe("showinfo(): duplication of memory error",1);
3101   IF(timebuf[(SL(timebuf)-1)]==0x0A)
3102   timebuf[(SL(timebuf)-1)]=0x0;
3103   nsprint("[ netscript: (version: v%s!%s - launchtime: %s) ]\n",VERSION,
3104   COMPTYPE,timebuf);
3105   FR(timebuf);
3106  }
3107  R;
3108 }
3109 /* this function will handle the prompted version of netscript. */
iface(C * base)3110 V iface(C *base){
3111  U SH r=0;
3112  U SH s=0;
3113  U I i=0;
3114  U I j=0;
3115  U I k=0;
3116  C **tmpname;
3117  C *tmptime;
3118  U C icwd[(BASE_BUFFER*4+1)];
3119  U C iread[(BASE_BUFFER*4+1)];
3120  FL *ifd;
3121  PT fp;
3122  T tm;
3123  S group *gent;
3124  S passwd *pent;
3125  /* no user aborts in this mode, will reset at the end of the function. */
3126  SG(SIGINT,SIG_IGN);
3127  /* no reading of (non-ruleset) files when privileged.  this is silent. */
3128  IF(!isprivileged){
3129   IF(!(ifd=FO(rcfile,"r")))
3130    s=0;
3131   E
3132    s=1;
3133  }
3134  W(!r){
3135   IF(!s)
3136    nsprint("%s",base);
3137   IF(!s&&!(ifd=FO(ttyn,"r")))
3138    pe("could not open standard input for read",1);
3139   E{
3140    B(iread,(BASE_BUFFER*4+1));
3141    IF(FS(iread,(SO(iread)-1),ifd)){
3142     F(i=0;i<SL(iread);i++){
3143      IF(iread[i]==0x0A||iread[i]==0x0D)
3144       iread[i]=0x0;
3145      /* apply question marks to unprintable characters. */
3146      IF(iread[i]&&!isprint(iread[i]))
3147       iread[i]=0x3F;
3148     }
3149    }
3150    /* will close the stream below, now that its finished. */
3151    EI(s)
3152     s=0;
3153   }
3154   IF(!s)
3155    FC(ifd);
3156   /* command handling. */
3157   IF(!SNCC(iread,"anotify",7)){
3158    noshowa=(noshowa?0:1);
3159    nsprint("anotify: %sabled\n",(noshowa?"en":"dis"));
3160   }
3161   EI(!SNCC(iread,"background",10)){
3162    isbg=(isbg?0:1);
3163    nsprint("background: %sabled\n",(isbg?"en":"dis"));
3164   }
3165   EI(!SNCC(iread,"bind",4)){
3166    IF(sethost)
3167     nsprint("bind: there are hostname(s) defined to connect to, can not define"
3168     ".\n");
3169    E{
3170     bindmode=(bindmode?0:1);
3171     nsprint("bind: %sabled\n",(bindmode?"en":"dis"));
3172    }
3173   }
3174   EI(!SNCC(iread,"chdir",5)){
3175    IF(!parameter(iread,1,0x20)){
3176     IF(setcdir)
3177      FR(cdir);
3178     parsecmdline(parm);
3179     IF(!(cdir=(C *)SDU(parsedline)))
3180      pe("iface(): duplication of memory error",1);
3181     setcdir=1;
3182    }
3183    nsprint("chdir: %s\n",(setcdir?cdir:IFACE_UNSET));
3184   }
3185   EI(!SNCC(iread,"chroot",6)){
3186    IF(!parameter(iread,1,0x20)){
3187     IF(setrdir)
3188      FR(rdir);
3189     parsecmdline(parm);
3190     IF(!(rdir=(C *)SDU(parsedline)))
3191      pe("iface(): duplication of memory error",1);
3192     setrdir=1;
3193    }
3194    nsprint("chroot: %s\n",(setrdir?rdir:IFACE_UNSET));
3195   }
3196   EI(!SNCC(iread,"cnotify",7)){
3197    noshowc=(noshowc?0:1);
3198    nsprint("cnotify: %sabled\n",(noshowc?"en":"dis"));
3199   }
3200   EI(!SNCC(iread,"disparrows",10)){
3201    nofrom=(nofrom?0:1);
3202    nsprint("disparrows: %sabled\n",(nofrom?"en":"dis"));
3203   }
3204   EI(!SNCC(iread,"dispincoming",12)){
3205    nosrecv=(nosrecv?0:1);
3206    nsprint("dispincoming: %sabled\n",(nosrecv?"en":"dis"));
3207   }
3208   EI(!SNCC(iread,"dispoutgoing",12)){
3209    nossend=(nossend?0:1);
3210    nsprint("dispoutgoing: %sabled\n",(nossend?"en":"dis"));
3211   }
3212   EI(!SNCC(iread,"disptype",8)){
3213    IF(displaytype++>1)
3214     displaytype=0;
3215    nsprint("disptype: %s\n",(!displaytype?"disabled":(displaytype==1?"hex":
3216    "dec")));
3217   }
3218   EI(!SNCC(iread,"execexit",8)){
3219    runexit=(runexit?0:1);
3220    nsprint("execexit: %sabled\n",(runexit?"en":"dis"));
3221   }
3222   EI(!SNCC(iread,"execfile",8)){
3223    IF(isprivileged)
3224     nsprint("execfile: can not log data to a file with privileged access.\n");
3225    E{
3226     IF(!parameter(iread,1,0x20)){
3227      IF(runcmd)
3228       FR(execfile);
3229      parsecmdline(parm);
3230      IF(!(execfile=(C *)SDU(parsedline)))
3231       pe("iface(): duplication of memory error",1);
3232      runcmd=1;
3233     }
3234     nsprint("execfile: %s\n",(runcmd?execfile:IFACE_UNSET));
3235    }
3236   }
3237   EI(!SNCC(iread,"execinteractive",15)){
3238    isiexec=(isiexec?0:1);
3239    nsprint("execinteractive: %sabled\n",(isiexec?"en":"dis"));
3240   }
3241   EI(!SNCC(iread,"execpre",7)){
3242    IF(!parameter(iread,1,0x20)){
3243     IF(runpre)
3244      FR(execpre);
3245     parsecmdline(parm);
3246     IF(!(execpre=(C *)SDU(parsedline)))
3247      pe("iface(): duplication of memory error",1);
3248     runpre=1;
3249    }
3250    nsprint("execpre: %s\n",(runpre?execpre:IFACE_UNSET));
3251   }
3252   EI(!SNCC(iread,"execshell",9)){
3253    IF(!parameter(iread,1,0x20)){
3254     parsecmdline(parm);
3255     IF(AC(parsedline,X_OK))
3256      nsprint("execshell: argument1 is not a valid file, or is not executable."
3257      "\n");
3258     E{
3259      IF(setshell)
3260       FR(eshell);
3261      IF(!(eshell=(C *)SDU(parsedline)))
3262       pe("iface(): duplication of memory error",1);
3263      setshell=1;
3264     }
3265    }
3266    nsprint("execshell: %s\n",(setshell?eshell:IFACE_UNSET));
3267   }
3268   EI(!SNCC(iread,"execwait",8)){
3269    IF(!parameter(iread,1,0x20)){
3270     IF(AI(parm)<0)
3271      nsprint("execwait: argument1 must be a positive integer, can not define."
3272      "\n");
3273     E
3274      xalrm=AI(parm);
3275    }
3276    nsprint("execwait: %d\n",xalrm);
3277   }
3278   EI(!SNCC(iread,"forever",7)){
3279    forever=(forever?0:1);
3280    nsprint("forever: %sabled\n",(forever?"en":"dis"));
3281   }
3282 #ifdef GTK
3283   EI(!SNCC(iread,"guicolor",8)){
3284    IF(!parameter(iread,1,0x20)){
3285     parsecmdline(parm);
3286     IF(SL(parsedline)==6){
3287      B((V *)guic,SO(guic));
3288      F(isguic=i=0;i<6;i+=2){
3289       IF(IL((U I)parsedline[i]))
3290        j=(TL(parsedline[i])-0x56);
3291       E
3292        j=(parsedline[i]-0x2F);
3293       j*=16;
3294       IF(IL((U I)parsedline[i+1]))
3295        j+=(TL(parsedline[i+1])-0x56);
3296       E
3297        j+=(parsedline[i+1]-0x2F);
3298       j-=17;
3299       IF(j>=0&&j<256)
3300        guic[isguic]=(j*257);
3301       isguic++;
3302      }
3303     }
3304    }
3305    nsprint("guicolor: %.2x%.2x%.2x\n",(guic[0]/257),(guic[1]/257),(guic[2]/257)
3306    );
3307   }
3308   EI(!SNCC(iread,"guilabel",8)){
3309    IF(!parameter(iread,1,0x20)){
3310     IF(isguil){
3311      F(k=0;k<isguil;k++)
3312       FR(gblabel[k]);
3313      isguil=0;
3314     }
3315     parsecmdline(parm);
3316     W(!parameter(parsedline,isguil,0x3A)&&isguil<3){
3317      IF(!(gblabel[isguil++]=(C *)SDU(SL(parm)?parm:"nolabel")))
3318       pe("iface(): duplication of memory error",1);
3319     }
3320    }
3321    nsprint("guititle: %s%s\n",(isguil?gblabel[0]:IFACE_UNSET),(isguil>1?
3322    " <...>":""));
3323   }
3324   EI(!SNCC(iread,"guipdlen",8)){
3325    IF(!parameter(iread,1,0x20)){
3326     IF(AI(parm)<0)
3327      nsprint("guipdlen: argument1 must be a positive integer, can not define."
3328      "\n");
3329     E
3330      guio=(AI(parm)>GUI_MAXLEN?GUI_MAXLEN:AI(parm));
3331    }
3332    nsprint("guipdlen: %d\n",guio);
3333   }
3334   EI(!SNCC(iread,"guipd",5)){
3335    isguis=(isguis?0:1);
3336    nsprint("guipd: %sabled\n",(isguis?"en":"dis"));
3337   }
3338   EI(!SNCC(iread,"guititle",8)){
3339    IF(!parameter(iread,1,0x20)){
3340     IF(isguititle)
3341      FR(guititle);
3342     parsecmdline(parm);
3343     IF(!(guititle=(C *)SDU(parsedline)))
3344      pe("iface(): duplication of memory error",1);
3345     isguititle=1;
3346    }
3347    nsprint("guititle: %s\n",(isguititle?guititle:IFACE_UNSET));
3348   }
3349   EI(!SNCC(iread,"gui",3)){
3350    IF(isprivileged)
3351     nsprint("gui: the gui frontend can not be used when netscript is privilege"
3352     "d.\n");
3353    E{
3354     IF(isgui){
3355      IF(isbgui)
3356       isbgui=isgui=0;
3357      E
3358       isbgui=1;
3359     }
3360     E
3361      isgui=1;
3362     nsprint("gui: %s\n",(!isgui?"disabled":(isbgui==1?"generic":"normal")));
3363    }
3364   }
3365 #endif
3366   EI(!SNCC(iread,"host",4)){
3367    IF(bindmode)
3368     nsprint("host: bind mode is already defined, can not define.\n");
3369    E{
3370     IF(!parameter(iread,1,0x20)){
3371      IF(sethost){
3372       F(k=0;k<tshs;k++)
3373        FR(shost[k]);
3374       tshs=0;
3375      }
3376      parsecmdline(parm);
3377      W(!parameter(parsedline,tshs,0x2C)){
3378       IF(!(shost[tshs++]=(C *)SDU(SL(parm)?parm:"0")))
3379        pe("iface(): duplication of memory error",1);
3380       IF(tshs>=MAX_ARGS)
3381        pe("too many slots to store in memory",1);
3382      }
3383      sethost=1;
3384     }
3385     nsprint("host: %s%s\n",(sethost?shost[0]:IFACE_UNSET),(tshs>1?" <...>":
3386     ""));
3387    }
3388   }
3389   EI(!SNCC(iread,"initial",7)){
3390    IF(!parameter(iread,1,0x20)){
3391     IF(initsend)
3392      FR(iswrite);
3393     parsecmdline(parm);
3394     IF(!(iswrite=(C *)SDU(parsedline)))
3395      pe("iface(): duplication of memory error",1);
3396     initsend=1;
3397    }
3398    nsprint("initial: %s\n",(initsend?iswrite:IFACE_UNSET));
3399   }
3400   EI(!SNCC(iread,"logfile",7)){
3401    IF(isprivileged)
3402     nsprint("logfile: can not log data to a file with privileged access.\n");
3403    E{
3404     IF(!parameter(iread,1,0x20)){
3405      IF(islog)
3406       FR(logfile);
3407      parsecmdline(parm);
3408      IF(!(logfile=(C *)SDU(parsedline)))
3409       pe("iface(): duplication of memory error",1);
3410      islog=1;
3411     }
3412     nsprint("logfile: %s\n",(islog?logfile:IFACE_UNSET));
3413    }
3414   }
3415 #ifdef NCURSES
3416   EI(!SNCC(iread,"ncurseslabel",12)){
3417    IF(!parameter(iread,1,0x20)){
3418     IF(isncursesl){
3419      F(k=0;k<isncursesl;k++)
3420       FR(nclabel[k]);
3421      isncursesl=0;
3422     }
3423     parsecmdline(parm);
3424     W(!parameter(parsedline,isncursesl,0x3A)&&isncursesl<2){
3425      IF(!(nclabel[isncursesl++]=(C *)SDU(SL(parm)?parm:"nolabel")))
3426       pe("iface(): duplication of memory error",1);
3427     }
3428    }
3429    nsprint("ncurseslabel: %s%s\n",(isncursesl?nclabel[0]:IFACE_UNSET),
3430    (isncursesl>1?" <...>":""));
3431   }
3432   EI(!SNCC(iread,"ncurses",7)){
3433    isncursesa=(isncursesa?0:1);
3434    nsprint("ncurses: %sabled\n",(isncursesa?"en":"dis"));
3435   }
3436 #endif
3437   EI(!SNCC(iread,"nonprintables",13)){
3438    printonly=(printonly?0:1);
3439    nsprint("nonprintables: %sabled\n",(printonly?"en":"dis"));
3440   }
3441   EI(!SNCC(iread,"notelnetshowopt",15)){
3442    notnetopt=(notnetopt?0:1);
3443    nsprint("notelnetshowopt: %sabled\n",(notnetopt?"en":"dis"));
3444   }
3445   EI(!SNCC(iread,"nowordwrap",10)){
3446    nowrap=(nowrap?0:1);
3447    nsprint("nowordwrap: %sabled\n",(nowrap?"en":"dis"));
3448   }
3449   EI(!SNCC(iread,"omit",4)){
3450    IF(!parameter(iread,1,0x20)){
3451     IF(omitchars)
3452      FR(ochars);
3453     parsecmdline(parm);
3454     IF(!(ochars=(C *)SDU(parsedline)))
3455      pe("iface(): duplication of memory error",1);
3456     omitchars=1;
3457    }
3458    nsprint("omit: %s\n",(omitchars?ochars:IFACE_UNSET));
3459   }
3460   EI(!SNCC(iread,"perm",4)){
3461    IF(!parameter(iread,1,0x20)){
3462     IF(!setperms){
3463      parsecmdline(parm);
3464      setpermissions(parsedline,0);
3465      setperms=1;
3466     }
3467     E
3468      nsprint("perm: permissions are already defined, can not re-define.\n");
3469    }
3470    nsprint("perm: %u.%u <%s>\n",nuid,ngid,(setperms?"set":"unset"));
3471   }
3472   EI(!SNCC(iread,"pnotify",7)){
3473    noshowp=(noshowp?0:1);
3474    nsprint("pnotify: %sabled\n",(noshowp?"en":"dis"));
3475   }
3476   EI(!SNCC(iread,"port",4)){
3477    IF(!parameter(iread,1,0x20))
3478     sport=portentry(parm);
3479    nsprint("port: %d\n",sport);
3480   }
3481   EI(!SNCC(iread,"routehost",9)){
3482    IF(!parameter(iread,1,0x20)){
3483     IF(setroute)
3484      FR(rhost);
3485     parsecmdline(parm);
3486     IF(!(rhost=(C *)SDU(parsedline)))
3487      pe("iface(): duplication of memory error",1);
3488     setroute=1;
3489    }
3490    nsprint("routehost: %s\n",(setroute?rhost:IFACE_UNSET));
3491   }
3492   EI(!SNCC(iread,"routenoincoming",15)){
3493    norrecv=(norrecv?0:1);
3494    nsprint("routenoincoming: %sabled\n",(norrecv?"en":"dis"));
3495   }
3496   EI(!SNCC(iread,"routenooutgoing",15)){
3497    norsend=(norsend?0:1);
3498    nsprint("routenooutgoing: %sabled\n",(norsend?"en":"dis"));
3499   }
3500   EI(!SNCC(iread,"routeport",9)){
3501    IF(!parameter(iread,1,0x20)){
3502     IF(AI(parm)<0)
3503      nsprint("routeport: argument1 must be a positive integer, can not define."
3504      "\n");
3505     E
3506      rport=AI(parm);
3507    }
3508    nsprint("routeport: %d\n",rport);
3509   }
3510   EI(!SNCC(iread,"routeudp",8)){
3511    isudpr=(isudpr?0:1);
3512    nsprint("routeudp: %sabled\n",(isudpr?"en":"dis"));
3513   }
3514   EI(!SNCC(iread,"rulesetedit",11)){
3515    editrules=(editrules?0:1);
3516    nsprint("rulesetedit: %sabled\n",(editrules?"en":"dis"));
3517   }
3518   EI(!SNCC(iread,"rulesetinput",12)){
3519    IF(setfile)
3520     nsprint("rulesetinput: there is a ruleset file defined to use, can not def"
3521     "ine.\n");
3522    E{
3523     inputrules=(inputrules?0:1);
3524     nsprint("rulesetinput: %sabled\n",(inputrules?"en":"dis"));
3525    }
3526   }
3527   EI(!SNCC(iread,"ruleset",7)){
3528    IF(inputrules)
3529     nsprint("ruleset: ruleset input is already defined, can not define.\n");
3530    E{
3531     IF(!parameter(iread,1,0x20)){
3532      IF(setfile)
3533       FR(rulesfile);
3534      parsecmdline(parm);
3535      IF(!(rulesfile=(C *)SDU(parsedline)))
3536       pe("iface(): duplication of memory error",1);
3537      setfile=1;
3538     }
3539     nsprint("ruleset: %s\n",(setfile?rulesfile:IFACE_UNSET));
3540    }
3541   }
3542   EI(!SNCC(iread,"sdelay",5)){
3543    IF(!parameter(iread,1,0x20)){
3544     IF(AI(parm)<0)
3545      nsprint("sdelay: argument1 must be a positive integer, can not define."
3546      "\n");
3547     E
3548      sdelay=AI(parm);
3549    }
3550    nsprint("sdelay: %d\n",sdelay);
3551   }
3552   EI(!SNCC(iread,"showlines",10)){
3553    lnum=(lnum?0:1);
3554    IF(lnum)
3555     lnum=lnum_i=lnum_o=nowrap=1;
3556    nsprint("showlines: %sabled\n",(lnum?"en":"dis"));
3557   }
3558   EI(!SNCC(iread,"showversion",11)){
3559    showv=(showv?0:2);
3560    nsprint("showversion: %sabled\n",(showv?"en":"dis"));
3561   }
3562   EI(!SNCC(iread,"socketopts",10)){
3563    IF(!parameter(iread,1,0x20)){
3564     IF(soptions)
3565      FR(sopts);
3566     parsecmdline(parm);
3567     IF(!(sopts=(C *)SDU(parsedline)))
3568      pe("iface(): duplication of memory error",1);
3569     soptions=1;
3570    }
3571    nsprint("socketopts: %s\n",(soptions?sopts:IFACE_UNSET));
3572   }
3573 #ifndef DISABLE_SYSLOG
3574   EI(!SNCC(iread,"syslog",6)){
3575    slog=(slog?0:1);
3576    nsprint("syslog: %sabled\n",(slog?"en":"dis"));
3577   }
3578 #endif
3579   EI(!SNCC(iread,"telnettype",10)){
3580    IF(tnetraw++>1)
3581     tnetraw=0;
3582    nsprint("telnettype: %s\n",(!tnetraw?"disabled":(tnetraw==1?"stderr":
3583    "stdout")));
3584   }
3585   EI(!SNCC(iread,"telnet",6)){
3586    tnet=(tnet?0:1);
3587    nsprint("telnet: %sabled\n",(tnet?"en":"dis"));
3588   }
3589   EI(!SNCC(iread,"timedexit",9)){
3590    IF(!parameter(iread,1,0x20)){
3591     IF(AI(parm)<0)
3592      nsprint("timedexit: argument1 must be a positive integer, can not define."
3593      "\n");
3594     E
3595      alrm=AI(parm);
3596    }
3597    nsprint("timedexit: %d\n",alrm);
3598   }
3599   EI(!SNCC(iread,"udpmode",7)){
3600    isudp=(isudp?0:1);
3601    nsprint("udpmode: %sabled\n",(isudp?"en":"dis"));
3602   }
3603   EI(!SNCC(iread,"udelay",5)){
3604    IF(!parameter(iread,1,0x20)){
3605     IF(AI(parm)<0)
3606      nsprint("udelay: argument1 must be a positive integer, can not define."
3607      "\n");
3608     E
3609      sudelay=AI(parm);
3610    }
3611    nsprint("udelay: %d\n",sudelay);
3612   }
3613   EI(!SNCC(iread,"var",3)){
3614    IF(!parameter(iread,1,0x20)){
3615     IF(ID((U I)parm[0])){
3616      j=(parm[0]-0x30);
3617      IF(dynamicvarset[j]!=2)
3618       FR(dynamicvar[j]);
3619      IF(!parameter(iread,2,0x20)){
3620       parsecmdline(parm);
3621       IF(!(dynamicvar[j]=(C *)SDU(parsedline)))
3622        pe("iface(): duplication of memory error",1);
3623       dynamicvarset[j]=2;
3624      }
3625      nsprint("var(%d): %s\n",j,(dynamicvarset[j]==2?dynamicvar[j]:
3626      IFACE_UNSET));
3627     }
3628     E
3629      nsprint("var(*): parameter1 is not a value between 0 and 9.\n");
3630    }
3631    E
3632     nsprint("var(syntax): var <0-9> <data>\n");
3633   }
3634   EI(!SNCC(iread,"vhost",5)){
3635    IF(!parameter(iread,1,0x20)){
3636     IF(isvhost)
3637      FR(vhost);
3638     parsecmdline(parm);
3639     IF(!(vhost=(C *)SDU(parsedline)))
3640      pe("iface(): duplication of memory error",1);
3641     isvhost=1;
3642    }
3643    nsprint("vhost: %s\n",(isvhost?vhost:IFACE_UNSET));
3644   }
3645   EI(!SNCC(iread,"exit",4)||!SNCC(iread,"quit",4))
3646    nsexit(0,0);
3647   EI(!SNCC(iread,"run",3)||!SNCC(iread,"launch",6))
3648    r=1;
3649   EI(!SNCC(iread,"&cwd",4)){
3650    IF(!parameter(iread,1,0x20)){
3651     parsecmdline(parm);
3652     CD(parm);
3653    }
3654    B(icwd,(BASE_BUFFER*4+1));
3655    GWD(icwd,(BASE_BUFFER*4+1));
3656    nsprint("&cwd: %s\n",icwd);
3657   }
3658   EI(!SNCC(iread,"&id",3)){
3659    IF(!(tmpname=(C **)M(5*(SO(C *)))))
3660     pe("iface(): allocation of memory error",1);
3661    B((V *)tmpname,SO(tmpname));
3662    IF((pent=GPU(GU()))&&SL(pent->pw_name)){
3663     IF(!(tmpname[0]=(C *)SDU(pent->pw_name)))
3664      pe("iface(): duplication of memory error",1);
3665    }
3666    E{
3667     IF(!(tmpname[0]=(C *)SDU("unknown")))
3668      pe("iface(): duplication of memory error",1);
3669    }
3670    IF((pent=GPU(GEU()))&&SL(pent->pw_name)){
3671     IF(!(tmpname[1]=(C *)SDU(pent->pw_name)))
3672      pe("iface(): duplication of memory error",1);
3673    }
3674    E{
3675     IF(!(tmpname[1]=(C *)SDU("unknown")))
3676      pe("iface(): duplication of memory error",1);
3677    }
3678    IF((gent=GGG(GG()))&&SL(gent->gr_name)){
3679     IF(!(tmpname[2]=(C *)SDU(gent->gr_name)))
3680      pe("iface(): duplication of memory error",1);
3681    }
3682    E{
3683     IF(!(tmpname[2]=(C *)SDU("unknown")))
3684      pe("iface(): duplication of memory error",1);
3685    }
3686    IF((gent=GGG(GEG()))&&SL(gent->gr_name)){
3687     IF(!(tmpname[3]=(C *)SDU(gent->gr_name)))
3688      pe("iface(): duplication of memory error",1);
3689    }
3690    E{
3691     IF(!(tmpname[3]=(C *)SDU("unknown")))
3692      pe("iface(): duplication of memory error",1);
3693    }
3694    nsprint("&id: uid=%u(%s) euid=%u(%s) gid=%u(%s) egid=%u(%s)\n",GU(),
3695    tmpname[0],GEU(),tmpname[1],GG(),tmpname[2],GEG(),tmpname[3]);
3696    FR(tmpname);
3697   }
3698   EI(!SNCC(iread,"&pid",4))
3699    nsprint("&pid: %lu (parent=%lu)\n",cpid,GPPD());
3700   EI(!SNCC(iread,"&time",6)){
3701    TM(&tm);
3702    IF(!(tmptime=(C *)SDU(CT(&tm))))
3703     pe("iface(): duplication of memory error",1);
3704    IF(tmptime[(SL(tmptime)-1)]==0x0A)
3705     tmptime[(SL(tmptime)-1)]=0x0;
3706    nsprint("&time: %s (value=%d)\n",tmptime,tm);
3707    FR(tmptime);
3708   }
3709   EI(SL(iread)&&iread[0]==0x21){
3710    IF(isprivileged)
3711     nsprint("!: can not execute third party programs with privileged access."
3712     "\n");
3713    E{
3714     F(i=1;i<SL(iread);i++)
3715      iread[(i-1)]=iread[i];
3716     iread[(i-1)]=0x0;
3717     SW(fp=FK()){
3718      CS -1:
3719       nsprint("!: fork() failed.\n");
3720       BR;
3721      CS 0:
3722       /* allow aborts to be handled, since its passed over to the program. */
3723       SG(SIGINT,SIG_DFL);
3724       EL(eshell,eshell,(SL(iread)?"-c":0),(SL(iread)?iread:0),0);
3725       _exit(1);
3726       BR;
3727     default:
3728      /* wait up. */
3729      WP(fp,0,0);
3730      BR;
3731     }
3732    }
3733   }
3734   EI(!SNCC(iread,"help",4)){
3735    nsprint("anotify\t\t\t\t- disables display of all netscript comments.\n"
3736    "background\t\t\t- sends netscript to the background.\n"
3737    "bind\t\t\t\t- binds to the supplied port.\n"
3738    "chdir\t\t<directory>\t- changes the working directory of netscript.\n"
3739    "chroot\t\t<directory>\t- changes the root directory of netscript.\n"
3740    "cnotify\t\t\t\t- disables display of connection notifications.\n"
3741    "disparrows\t\t\t- disables display of arrow precursors.\n"
3742    "dispincoming\t\t\t- disables display of incoming data.\n"
3743    "dispoutgoing\t\t\t- disables display of outgoing data.\n"
3744    "disptype\t\t\t- displays hex/dec values.\n"
3745    "execexit\t\t\t- kills netscript after the first dump.\n"
3746    "execfile\t<file>\t\t- dumps the program data to the socket.\n"
3747    "execinteractive\t\t\t- will allow interactive use of programs.\n"
3748    "execpre\t\t<data>\t\t- precurse data to attach for each line dumped.\n"
3749    "execshell\t<file>\t\t- will use an alternate shell for executions.\n"
3750    "execwait\t<second(s)>\t- kills the program if the program dump hangs.\n"
3751    "forever\t\t\t\t- when disconnected.  reconnect, or rebind.\n"
3752 #ifdef GTK
3753    "gui\t\t\t\t- enables the gui frontend. (to normal/generic)\n"
3754    "guicolor\t<ffffff>\t- sets a text foreground color for the gui.\n"
3755    "guilabel\t<l1:l2:l3>\t- defines button labels for the gui.\n"
3756    "guipd\t\t\t\t- automatically start pulled down. (non-generic)\n"
3757    "guipdlen\t<size>\t\t- increase the length of the gui. (non-generic)\n"
3758    "guititle\t<title>\t\t- displays as the title for the gui.\n"
3759 #endif
3760    "host\t\t<host,host,...>\t- remote host (or ip) to connect to.\n"
3761    "initial\t\t<data>\t\t- send initial data once connected. (\"?\"=dyn)\n"
3762    "logfile\t\t<file>\t\t- turns input/output logging on.\n"
3763 #ifdef NCURSES
3764    "ncurses\t\t\t\t- switch console to ncurses visualization.\n"
3765    "ncurseslabel\t<l1:l2>\t\t- defines tab labels for the ncurses.\n"
3766 #endif
3767    "nonprintables\t\t\t- disables reading of non-printable characters.\n"
3768    "notelnetshowopt\t\t\t- disables display of verbose telnetd-opts.\n"
3769    "nowordwrap\t\t\t- disables wordwrap for in/out displaying.\n"
3770    "omit\t\t<charlist>\t- will omit socket reading of the charlist.\n"
3771    "perm\t\t<user[.group]>\t- changes netscript id permissions.\n"
3772    "pnotify\t\t\t\t- disables display of unimportant ruleset info.\n"
3773    "port\t\t<port>\t\t- remote port to connect to, or bind to.\n"
3774    "routehost\t<host>\t\t- will set a host, to route socket data to.\n"
3775    "routenoincoming\t\t\t- disable routed sending of incoming data.\n"
3776    "routenooutgoing\t\t\t- disable routed sending of outgoing data.\n"
3777    "routeport\t<port>\t\t- will set a port to connect on the route host.\n"
3778    "routeudp\t\t\t- switches the route host to the UDP protocol.\n"
3779    "ruleset\t\t<file>\t\t- input/output (ruleset) file.\n"
3780    "rulesetedit\t\t\t- edit the temporary/ruleset with an editor.\n"
3781    "rulesetinput\t\t\t- input/output ruleset, via input.\n"
3782    "sdelay\t\t<second(s)>\t- delay before processing incoming data. \n"
3783    "showlines\t\t\t- displays the value of each line.\n"
3784    "showversion\t\t\t- displays the version info of netscript.\n"
3785    "socketopts\t<#,#,#:...>\t- sets socket option(s) inside netscript.\n"
3786 #ifndef DISABLE_SYSLOG
3787    "syslog\t\t\t\t- enables system logging.\n"
3788 #endif
3789    "telnet\t\t\t\t- attempt to interpret the telnet protocol.\n"
3790    "telnettype\t\t\t- dump raw socket data. (to stderr/stdout)\n"
3791    "timedexit\t<second(s)>\t- closes the connection after alloted time.\n"
3792    "udpmode\t\t\t\t- switches netscript to the UDP protocol.\n"
3793    "udelay\t\t<usecond(s)>\t- delay before processing incoming data.\n"
3794    "var\t\t<0-9> <data>\t- will statically define the dynamic variable.\n"
3795    "vhost\t\t<host>\t\t- will define a virtual host to use, or bind to.\n"
3796    "&cwd AND &id AND &pid AND &time\t- local (only) interactive display comman"
3797    "ds.\n"
3798    "![command]\t\t\t- shell out of interactive netscript.\n"
3799    "run AND launch\t\t\t- execute the provided information.\n"
3800    "exit AND quit\t\t\t- exit netscript.\n"
3801    "help\t\t\t\t- this screen, displays interactive commands.\n");
3802   }
3803   EI(SL(iread)&&iread[0]!=0x23)
3804    nsprint("unknown command: %s (try \'help\' for a command list)\n",iread);
3805  }
3806  SG(SIGINT,sighandler);
3807  R;
3808 }
3809 /* display of variable uses, the -d argument.  finally went for \t's */
displayv(V)3810 V displayv(V){
3811  nsprint("Defined ruleset match, and replacement variables used by netscript:"
3812  "\n"
3813  "IN/OUT\tTYPE\t\tDOES/ACTION\t\t\t\tVARIABLE\n"
3814  "I/O\treplace\t\twill replace with the in/out used above\t\"%s\"\n"
3815  "O\tpre-data\tstops use of the ruleset\t\t\"%s\"\n"
3816  "O\tpre-data\trestarts use of the ruleset\t\t\"%s\"\n"
3817  "O\tpre-data\tstops the ruleset reading cycle\t\t\"%s\"\n"
3818  "O\tpre-data\tcloses the socket\t\t\t\"%s\"\n"
3819  "O\tpre-data\tasks for input response to send\t\t\"%s\"\n"
3820  "O\tpre-data\ttruncates characters from server data\t\"%s\"\n"
3821  "O\tpre-data\ttruncates tokens from server data (l)\t\"%s\"\n"
3822  "O\tpre-data\ttruncates tokens from server data (r)\t\"%s\"\n"
3823  "O\tpre-data\ttruncates strings from server data\t\"%s\"\n"
3824  "O\tpre-data\tformats the received input data\t\t\"%s\"\n"
3825  "O\tpre-data\tdisplays the supplied data\t\t\"%s\"\n"
3826  "O\tpre-data\twrites the supplied data without a CR\t\"%s\"\n"
3827  "O\tpre-data\tuses rule only one time (requires data)\t\"%s\"\n"
3828  "O\tpre-data\tdisables a rule from the ruleset\t\"%s\"\n"
3829  "O\tpre-data\tdumps the file used after variable\t\"%s\"\n"
3830  "O\tpre-data\twrites to the file used after variable\t\"%s\"\n"
3831  "O\tpre-data\tappends to the file used after variable\t\"%s\"\n"
3832  "O\tpre-data\tchange to the dir used after variable\t\"%s\"\n"
3833  "O\tpre-data\tsends supplied data to the route host\t\"%s\"\n"
3834  "O\tpre-data\tonly sends data if time has passed\t\"%s\"\n"
3835  "O\tpre-data\texecutes the file used after variable\t\"%s\"\n"
3836  "O\tpre-data\texecutes the file to be used in rules\t\"%s\"\n"
3837  "I\tpre-data\tcheck for a reverse/negative match\t\"%s\"\n"
3838  "I\twildcard\tanything after point\t\t\t\"%s\"\n"
3839  "I\twildcard\tanything that is a value\t\t\"%s\"\n"
3840  "I\twildcard\tanything that is alphabetical\t\t\"%s\"\n"
3841  "I\twildcard\tanything that is numerical\t\t\"%s\"\n"
3842  "I\twildcard\tanything that is alphabetical|numerical\t\"%s\"\n"
3843  "I\twildcard\tanything that is upper case\t\t\"%s\"\n"
3844  "I\twildcard\tanything that is lower case\t\t\"%s\"\n"
3845  "I\twildcard\tanything that is punctuated\t\t\"%s\"\n"
3846  "I\twildcard\tanything that is a control word\t\t\"%s\"\n"
3847  "I\twildcard\tanything that is a printable word\t\"%s\"\n"
3848  "I\twildcard\t<\"%c####\" anything that is equal to length, #=num>\n"
3849  "O\tend-data\t<\"%c#####\" delay in secs before processing rule, #=num>\n"
3850  "O\treplace\t\t<\"%c#\" will replace with the argument from input, #=num>\n"
3851  "I/O\treplace\t\t<\"%c{#}\" will replace with stored dynamic data, #=num>\n"
3852  "I/O\treplace\t\t<\"%c##\" will replace with hex->chr value, ##=01-FF>\n"
3853  "I/O\treplace\t\t<\"%c###\" will replace with dec->chr value, ###=001-255>\n"
3854  "I/O\treplace\t\t<\"%c&\" will replace with a random letter>\n"
3855  "I/O\treplace\t\t<\"%c#\" will replace with a random number, #=#>\n"
3856  "\nDefined environmental variables used by netscript:\n"
3857  "DOES/ACTION\t\t\t\t\t\t\tVARIABLE\n"
3858  "treated as a command line\t\t\t\t\t\"$%s\"\n"
3859  "treated as a connection timeout time\t\t\t\t\"$%s\"\n"
3860 #ifndef DISABLE_MODULES
3861  "treated as a file to use for module support\t\t\t\"$%s\"\n"
3862 #endif
3863  "treated as a virtual host to use\t\t\t\t\"$%s\"\n"
3864  "treated as a backlog used for binding\t\t\t\t\"$%s\"\n"
3865  "treated as a maximum limit of text per line\t\t\t\"$%s\"\n"
3866  "treated as a shell to execute third party programs\t\t\"$%s\"\n"
3867  "treated as a text editor to make/edit (temporary) rulesets\t\"$%s\"\n\n"
3868  "Note: variables surrounded by <>'s are static, and unchangeable variables.\n"
3869  "      consult documentation for more definitions on variables.\n",NS_REPEAT,
3870  NS_STOP,NS_START,NS_HALT,NS_QUIT,NS_ASK,NS_TRUNC,NS_TOKENL,NS_TOKENR,NS_STR,
3871  NS_FMT,NS_ECHO,NS_RAW,NS_ONCE,NS_DISABLE,NS_DUMP,NS_WRITE,NS_APPEND,NS_CHDIR,
3872  NS_ROUTE,NS_TIMED,NS_EXEC,NS_EXECF,NS_NMATCH,NS_ALL,NS_ANY,NS_ALPHA,NS_DIGIT,
3873  NS_ALNUM,NS_UPPER,NS_LOWER,NS_PUNCT,NS_CNTRL,NS_PRINT,PARAMETER_VAR_CHAR,
3874  PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,
3875  PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,PARAMETER_VAR_CHAR,ENV_CMDLINE,
3876  ENV_TIMEOUT,
3877 #ifndef DISABLE_MODULES
3878  ENV_MODULE,
3879 #endif
3880  ENV_VHOST,ENV_BACKLOG,ENV_COLUMNS,ENV_SHELL,
3881  ENV_EDITOR);
3882  nsexit(0,0);
3883 }
3884 /* stated in displayv().  also, finally went for the \t's here too. */
usage(U SH extended)3885 V usage(U SH extended){
3886  nsprint("Usage: %s [extended options...] -s|-r file -b|-h host -p port\n"
3887  "Usage: %s file (must be a +rx internal argument supplied ruleset file)\n"
3888  "Usage: %s --list [path:path:...] (must be used by command line only)\n"
3889  "Usage: %s --hist [#]|[clear] (must be used by command line only)\n"
3890  "Usage: %s [--interactive] (will enter interactive prompted mode)\n",
3891  progname,progname,progname,progname,progname);
3892  IF(extended)
3893   nsprint("\n  -r <file>\t\tinput/output (ruleset) file. (required, or -s)\n"
3894   "  -h <host>\t\tremote host (or ip) to connect to. (required, or -b)\n"
3895   "  -p <port>\t\tremote port to connect to, or bind to. (required)\n"
3896   "  -# <data>\t\twill statically define the dynamic variable. (#=0-9)\n"
3897   "  -i <data>\t\tsend initial data once connected. (\"?\" for dynamic)\n"
3898   "  -m <path>\t\twill change the working directory of netscript.\n"
3899   "  -M <path>\t\twill change the root directory of netscript. (superuser)\n"
3900   "  -R <host>\t\twill set a host, to route socket data to.\n"
3901   "  -k <port>\t\twill set a port to connect to on the route host. (-R)\n"
3902   "  -u <data>\t\tchanges netscript id permissions. (\"user[.group]\" style)\n"
3903   "  -q <host>\t\twill define a virtual host to use, or bind to.\n"
3904   "  -o <data>\t\twill omit socket reading of the supplied character(s).\n"
3905   "  -S <time>\t\tdelay before processing incoming data. (seconds)\n"
3906   "  -U <time>\t\tdelay before processing incoming data. (useconds)\n"
3907   "  -t <time>\t\tclose the connection after alloted time.\n"
3908   "  -Q <data>\t\tsets local socket option(s). (\"#,#,#:#,#,#:...\" style)\n"
3909   "  -l <file>\t\tturns input/output logging on, writes to the file.\n"
3910 #ifdef GTK
3911   "  -G <name>\t\tdisplays the name as the title for the gui. (-g)\n"
3912   "  -+ <size>\t\tchanges the length of the pulldown. (non-generic) (-g)\n"
3913   "  -# <data>\t\tsets foreground color for the gui. (\"ffffff\" style) (-g)\n"
3914   "  -K <data>\t\tsets button labels for the gui. (\"l1:l2:l3\" style) (-g)\n"
3915 #endif
3916 #ifdef NCURSES
3917   "  -= <data>\t\tsets tab labels for ncurses. (\"l1:l2\" style) (-_)\n"
3918 #endif
3919   "  -e <prog>\t\tdumps the program data to the socket.\n"
3920   "  -E <data>\t\tprecurse data to attach for each line dumped. (-e)\n"
3921   "  -O <prog>\t\twill use an alternate shell for executions. (-e)\n"
3922   "  -x <time>\t\tkills the program if the program dump hangs. (-e)\n"
3923   "  -X\t\t\tkills netscript after the program has been dumped. (-e)\n"
3924   "  -a\t\t\twill allow interactive use of programs. (-e)\n"
3925   "  -f\t\t\twill run a third party edtior to define the ruleset.\n"
3926   "  -@\t\t\twill switch netscript to the UDP protocol.\n"
3927   "  -^\t\t\twill switch the route host to the UDP protocol.\n"
3928   "  -B\t\t\tsends netscript to the background.\n"
3929   "  -n\t\t\tdisables display of outgoing data.\n"
3930   "  -N\t\t\tdisables display of incoming data.\n"
3931   "  -j\t\t\tdisable routed sending of outgoing data. (-R)\n"
3932   "  -J\t\t\tdisable routed sending of incoming data. (-R)\n"
3933   "  -F\t\t\tdisables display of arrow precursors.\n"
3934   "  -I\t\t\twhen disconnected.  reconnect, or rebind.\n"
3935   "  -s\t\t\ttakes the ruleset from standard input instead of a file.\n"
3936   "  -b\t\t\tbinds to the supplied port, instead of connecting out.\n"
3937 #ifdef GTK
3938   "  -g\t\t\tuses the gui frontend. (use twice for generic version)\n"
3939   "  -W\t\t\tautomatically starts pulled down. (non-generic) (-g)\n"
3940 #endif
3941 #ifdef NCURSES
3942   "  -_\t\t\tswitch console display to ncurses visualization.\n"
3943 #endif
3944 #ifndef DISABLE_SYSLOG
3945   "  -Z\t\t\tuses system logging. (if syslog is accessible)\n"
3946 #endif
3947   "  -T\t\t\tattempts to interpret the telnet protocol.\n"
3948   "  -y\t\t\twill dump raw socket data to standard error. (-T)\n"
3949   "  -Y\t\t\twill dump raw socket data to standard output. (-T)\n"
3950   "  -z\t\t\tdisables display of verbose telnetd-opt input/output.\n"
3951   "  -L\t\t\tdisplays the value of each line as a precursor.\n"
3952   "  -H\t\t\tdisplays hex values, instead of character values. (ff)\n"
3953   "  -D\t\t\tdisplays dec values, instead of character values. (255)\n"
3954   "  -w\t\t\tdisables wordwrap for in/out displaying.\n"
3955   "  -P\t\t\tdisables reading of non-printable characters.\n"
3956   "  -c\t\t\tdisables display of connection notifications.\n"
3957   "  -C\t\t\tdisables display of ruleset info that is not required.\n"
3958   "  -A\t\t\tdisables display of all prompted netscript comments.\n"
3959   "  -d\t\t\tdisplays the variables used by the ruleset, and environ.\n"
3960   "  -v\t\t\tdisplays the version info of netscript, and exits.\n"
3961   "  -V\t\t\tdisplays the version info of netscript, and continues.\n"
3962   "\nAuthor: %s. [ihadnihn]\n",author);
3963  nsexit(0,0);
3964 }
3965 /* any global exit routines can be placed here, your choice. */
nsexit(SH i,U SH type)3966 V nsexit(SH i,U SH type){
3967  /* clear the screen for ncurses. */
3968 #ifdef NCURSES
3969  IF(isncurses)
3970   endwin();
3971 #endif
3972 /* just idle out until really closed. */
3973 #ifdef GTK
3974  IF(isgui&&isgui!=3&&isagui){
3975   pe("all processing finished, awaiting exit request",0);
3976   isgui=2;
3977   W(isgui!=3)
3978    USLP(250000);
3979  }
3980 #endif
3981 #ifndef DISABLE_SYSLOG
3982  /* only if something happened, note this one. */
3983  IF(!(!slnum_s&&!slnum_t))
3984   wrso("%d-%d id: %lu-%u.%u.%u.%u exit: %s (%s)",slnum_t,slnum_s,cpid,GU(),
3985   GEU(),GG(),GEG(),(i?"abnormal":"normal"),(cpid==GPD()?"main":"branch"));
3986 #endif
3987  /* check, and use the ns_exit() symbol, it passes the exit value, and exit */
3988  /* type(main/branch). (short, unsigned short) */
3989 #ifndef DISABLE_MODULES
3990  IF(vmodule){
3991   (*exit_function)(i,type);
3992   /* added clean-up for the module file here, since it is going to exit. */
3993   dlclose(dyn);
3994  }
3995 #endif
3996  /* clean up a possible build up with raw telnet on exit. */
3997  IF(tnetraw&&truetnet){
3998   nsprint("\n");
3999   /* same goes for logging. */
4000   IF(islog)
4001    logdata("\n",3);
4002  }
4003  closesocket(0);
4004  closesocket(1);
4005  IF(type)
4006   _exit(i);
4007  E
4008   exit(i);
4009 }
4010 /* the following function is only for the ncurses mode. */
4011 #ifdef NCURSES
ncursesinit(V)4012 V ncursesinit(V) {
4013  U I i=0;
4014  initscr();
4015  cbreak();
4016  nonl();
4017  keypad(stdscr,TRUE);
4018  /* reset columns to ncurses information. */
4019  columns=(COLS-1);
4020  /* no need for anything larger, unless you are trying to bother memory. */
4021  IF(1024<columns){
4022   pe("COLS is too large",0);
4023   columns=DFL_COLUMNS;
4024  }
4025  /* the prompt itself must be counted in the most minimal of cases. */
4026  IF((1>columns&&nofrom)||(4>columns&&!nofrom)){
4027   pe("COLS is too small",0);
4028   columns=DFL_COLUMNS;
4029  }
4030  /* setup tab labels. */
4031  F(i=0;i<COLS;i++)
4032   NWV(stdscr,((LINES-3-1)/2),i,'-');
4033  F(i=0;i<COLS;i++)
4034   NWV(stdscr,(LINES-3),i,'-');
4035  NMW(((LINES-3-1)/2),0,"[-<");
4036  NMW(((LINES-3-1)/2),3,(isncursesl?nclabel[0]:"Output stream"));
4037  NMW(((LINES-3-1)/2),(isncursesl?(SL(nclabel[0])+3):16),">");
4038  NMW(((LINES-3-1)/2),(COLS-1),"]");
4039  NMW((LINES-3),0,"[-<");
4040  NMW((LINES-3),3,(isncursesl>1?nclabel[1]:"Input stream"));
4041  NMW((LINES-3),(isncursesl>1?(SL(nclabel[1])+3):15),">");
4042  NMW((LINES-3),(COLS-1),"]");
4043  move((LINES-3+1),0);
4044  NR();
4045  /* make (ncurses) windows. */
4046  nw1=NSW(stdscr,((LINES-3-1)/2),COLS,0,0);
4047  NSO(nw1,1);
4048  nw2=NSW(stdscr,((LINES-3-1)/2),COLS,((LINES-3-1)/2)+1,0);
4049  NSO(nw2,1);
4050  nw3=NSW(stdscr,(3-1),COLS,((LINES-3)+1),0);
4051  NSO(nw3,1);
4052  touchwin(stdscr);
4053  NR();
4054  /* straighten up. */
4055  NE(nw1);
4056  NRE(nw1);
4057  NE(nw2);
4058  NRE(nw2);
4059  NE(nw3);
4060  NRE(nw3);
4061  /* nsprint() defaultly goes to the main (ncurses) window. */
4062  nfocus=nw3;
4063  /* ready to go. */
4064  isncurses=1;
4065  R;
4066 }
4067 #endif
4068 /* the following functions are only for the gui mode. */
4069 #ifdef GTK
4070 /* function triggered when return is pressed for an entry. (gui mode) */
gtkec(GW * gw,GW * ge)4071 V gtkec(GW *gw,GW *ge){
4072  GC *et;
4073  et=gtk_entry_get_text(GTK_ENTRY(ge));
4074  IF(SL(et)&&isgui==1){
4075   IF(isguiwait){
4076    /* write the response to the socket. */
4077    wro(et,SL(et),0);
4078    wro("\n",1,0);
4079    /* log if requested. */
4080    IF(islog)
4081     logdata(et,0);
4082    /* reset waiting loop. */
4083    isguiwait=0;
4084    gtk_entry_set_text(GTK_ENTRY(ge),"");
4085    /* only for non-generic gui. */
4086    IF(!isbgui){
4087     /* away you go. */
4088     GWH(gen);
4089     /* window refresh. */
4090     GWSU(giw,guiw,guih);
4091     /* refocus on the last button made, which is the exit button. */
4092     GWGF(gbu);
4093    }
4094   }
4095  }
4096  R;
4097 }
4098 /* function to clear the screen. (gui mode) */
gtkcl(GW * gw,GPT gd)4099 V gtkcl(GW *gw,GPT gd){
4100  IF(gtk_text_get_length(GTK_TEXT(gte)))
4101   gtk_text_backward_delete(GTK_TEXT(gte),gtk_text_get_length(GTK_TEXT(gte)));
4102  R;
4103 }
4104 /* function to pull down the gui, using 300 as a general/default value. */
4105 /* (non-generic gui mode) */
gtkpd(GW * gw,GPT gd)4106 V gtkpd(GW *gw,GPT gd){
4107  IF(GTK_TOGGLE_BUTTON(gpd)->active==TRUE)
4108   guih+=(guio?guio:300);
4109  E
4110   guih-=(guio?guio:300);
4111  /* set the new position. */
4112  GWSU(giw,guiw,guih);
4113  R;
4114 }
4115 /* function that is triggered to close the program. (gui mode) */
gtkca(GW * gw,GPT gd)4116 V gtkca(GW *gw,GPT gd){
4117  gtk_main_quit();
4118  /* finalize the close. */
4119  isgui=3;
4120  /* just incase netscript is waiting anywheres else. */
4121  nsexit(0,0);
4122 }
4123 /* create, and launch the display. (gui mode) */
gtkrun(C * dispname)4124 V gtkrun(C *dispname){
4125  C *disptitle;
4126  /* check for normal, non-generic font. */
4127  IF(!isbgui&&!(GFL(GUI_FONT)))
4128   pe("error loading font, use the -g option twice for generic mode",1);
4129  /* set up the soon-to-be titlebar. */
4130  IF(!(disptitle=(C *)M((isguititle?SL(guititle):SL(dispname))+SL(VERSION)+33+1)
4131  ))
4132   pe("gtkrun(): allocation of memory error",1);
4133  B(disptitle,((isguititle?SL(guititle):SL(dispname))+SL(VERSION)+33+1));
4134  SP(disptitle,"Netscript/v%s(%.3s)-Xvisualization: %s",VERSION,COMPTYPE,
4135  (isguititle?guititle:dispname));
4136  /* setup the window. */
4137  giw=gtk_window_new(GTK_WINDOW_TOPLEVEL);
4138  GWSU(giw,(isbgui?520:(guiw=440)),(isbgui?200:(guih=150)));
4139  /* defined to not be allowed to make too small, does not look so hot. */
4140  gtk_window_set_policy(GTK_WINDOW(giw),FALSE,(isbgui?TRUE:FALSE),FALSE);
4141  GSC(GTK_OBJECT(giw),"destroy",GTK_SIGNAL_FUNC(gtkca),0);
4142  gtk_window_set_title(GTK_WINDOW(giw),disptitle);
4143  /* done with title buffer. */
4144  FR(disptitle);
4145  GCSBW(GTK_CONTAINER(giw),0);
4146  gb1=GVN(FALSE,0);
4147  gtk_container_add(GTK_CONTAINER(giw),gb1);
4148  GWS(gb1);
4149  gb2=GVN(FALSE,0);
4150  GCSBW(GTK_CONTAINER(gb2),5);
4151  GBPS(GTK_BOX(gb1),gb2,TRUE,TRUE,0);
4152  GWS(gb2);
4153  gta=gtk_table_new(2,2,FALSE);
4154  GBPS(GTK_BOX(gb2),gta,TRUE,TRUE,0);
4155  GWS(gta);
4156  /* text widget, vertical bar gets added on next. */
4157  gte=gtk_text_new(0,0);
4158  gtk_text_set_editable(GTK_TEXT(gte),FALSE);
4159  gtk_text_set_word_wrap(GTK_TEXT(gte),FALSE);
4160  GTA(GTK_TABLE(gta),gte,0,1,0,1,GTK_EXPAND|GTK_SHRINK|GTK_FILL,GTK_EXPAND|
4161  GTK_SHRINK|GTK_FILL,0,0);
4162  GWS(gte);
4163  /* vertical scrollbar, for the text widget. */
4164  gvs=gtk_vscrollbar_new(GTK_TEXT(gte)->vadj);
4165  GTA(GTK_TABLE(gta),gvs,1,2,0,1,GTK_FILL,GTK_EXPAND|GTK_SHRINK|GTK_FILL,0,0);
4166  GWS(gvs);
4167  gtk_widget_realize(gte);
4168  gtk_text_freeze(GTK_TEXT(gte));
4169  gtk_text_thaw(GTK_TEXT(gte));
4170  gvn=GVN(TRUE,0);
4171  GBPS(GTK_BOX(gb2),gvn,FALSE,FALSE,0);
4172  GWS(gvn);
4173  /* entry box. (do not show until needed, unless generic mode is on) */
4174  gen=gtk_entry_new_with_max_length(BASE_BUFFER);
4175  GSC(GTK_OBJECT(gen),"activate",GTK_SIGNAL_FUNC(gtkec),gen);
4176  GBPS(GTK_BOX(gvn),gen,FALSE,FALSE,0);
4177  IF(isbgui)
4178   GWS(gen);
4179  /* pulldown/up button/box. (only in non-generic gui mode) */
4180  IF(!isbgui){
4181   /* button box. */
4182   gpb=GHN(TRUE,0);
4183   GBPS(GTK_BOX(gvn),gpb,FALSE,FALSE,0);
4184   GWS(gpb);
4185   /* check button. */
4186   gpd=gtk_check_button_new_with_label(isguil>2?gblabel[2]:"Pulldown");
4187   GSC(GTK_OBJECT(gpd),"clicked",GTK_SIGNAL_FUNC(gtkpd),0);
4188   GBPS(GTK_BOX(gpb),gpd,TRUE,TRUE,0);
4189   GTK_WIDGET_SET_FLAGS(gpd,GTK_CAN_DEFAULT);
4190   GWS(gpd);
4191  }
4192  /* button box. */
4193  ghb=GHN(TRUE,0);
4194  GBPS((isbgui?GTK_BOX(gvn):GTK_BOX(gpb)),ghb,FALSE,TRUE,0);
4195  GWS(ghb);
4196  /* clear button. */
4197  gbu=gtk_button_new_with_label(isguil>1?gblabel[1]:"Clear");
4198  GSC(GTK_OBJECT(gbu),"clicked",GTK_SIGNAL_FUNC(gtkcl),0);
4199  GBPS(GTK_BOX(ghb),gbu,TRUE,TRUE,0);
4200  GTK_WIDGET_SET_FLAGS(gbu,GTK_CAN_DEFAULT);
4201  GWS(gbu);
4202  /* exit button. */
4203  gbu=gtk_button_new_with_label(isguil?gblabel[0]:"Exit");
4204  GSC(GTK_OBJECT(gbu),"clicked",GTK_SIGNAL_FUNC(gtkca),0);
4205  GBPS(GTK_BOX(ghb),gbu,TRUE,TRUE,0);
4206  GTK_WIDGET_SET_FLAGS(gbu,GTK_CAN_DEFAULT);
4207  GWS(gbu);
4208  /* focus on the entry/exit button. (depending if generic mode is on) */
4209  GWGF(isbgui?gen:gbu);
4210  /* pulldown on start. (-W option) */
4211  IF(!isbgui&&isguis)
4212   gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(gpd),TRUE);
4213  /* show the window. */
4214  GWS(giw);
4215  /* allow output/display use. */
4216  isagui=1;
4217  /* update the gui. */
4218  GTE();
4219  gtk_main();
4220  GTL();
4221  /* netscript is done. */
4222  pthread_exit(0);
4223  R;
4224 }
4225 #endif
4226 /* this function is to check for the reverse wildcard check.  if it does */
4227 /* not occur it gets passed normally along to wordmatch(). */
prewordmatch(C * wildcard,C * in)4228 U SH prewordmatch(C *wildcard,C *in){
4229  U SH r=0;
4230  U I i=0;
4231  C *tmpwildcard;
4232  IF(!(tmpwildcard=(C *)SDU(wildcard)))
4233   pe("prewordmatch(): duplication of memory error",1);
4234  /* check for the negative/reverse match rule. */
4235  IF(SL(tmpwildcard)>SL(NS_NMATCH)&&!SNCC(tmpwildcard,NS_NMATCH,SL(NS_NMATCH))){
4236   F(i=SL(NS_NMATCH);i<SL(tmpwildcard);i++)
4237    tmpwildcard[(i-SL(NS_NMATCH))]=tmpwildcard[i];
4238   tmpwildcard[(i-SL(NS_NMATCH))]=0x0;
4239   r=wordmatch(tmpwildcard,in);
4240   /* done with that. */
4241   FR(tmpwildcard);
4242   /* reverse it, the idea of this pre-function. */
4243   R(r?0:1);
4244  }
4245  /* otherwise, just like normal. */
4246  E
4247   R wordmatch(wildcard,in);
4248 }
4249 /* for the real wildcard match checking. */
wordmatch(C * wildcard,C * in)4250 U SH wordmatch(C *wildcard,C *in){
4251  U I i=0;
4252  U I j=0;
4253  U I k=0;
4254  U I r=0;
4255  U I tmp=0;
4256  C *tmpbuf;
4257  /* handles the dynamic variables. (${0-9}) */
4258  parsedynamic(wildcard);
4259  /* remove back-to-back spaces for parsing with the remote data. */
4260  F(j=0;j<SL(in);j++){
4261   IF(!(in[j+1]&&in[j]==0x20&&in[j+1]==0x20))
4262    in[k++]=in[j];
4263  }
4264  in[k]=0x0;
4265  /* remove back-to-back spaces for parsing with the ruleset. */
4266  F(k=j=0;j<SL(parseddynamic);j++)
4267   IF(!(parseddynamic[j+1]&&parseddynamic[j]==0x20&&parseddynamic[j+1]==0x20))
4268    parseddynamic[k++]=parseddynamic[j];
4269  parseddynamic[k]=0x0;
4270  /* quick exact match check. */
4271  IF(!SC(parseddynamic,in))
4272   R(0);
4273  W(!parameter(parseddynamic,i,0x20)){
4274   IF(!(tmpbuf=(C *)SDU(parm)))
4275    pe("wordmatch(): duplication of memory error",1);
4276   /* checks for a wildcard match for anything after that point.  before */
4277   /* checking the next parameter. */
4278   IF(SC(tmpbuf,NS_ALL)){
4279    /* gets the input parameter, to check for the rest of the wildcards, or */
4280    /* possible perfect matches.  if no more parameters, returns failure. */
4281    /* also increases the word for the next loop run. */
4282    IF(parameter(in,i++,0x20)){
4283     FR(tmpbuf);
4284     R(1);
4285    }
4286    /* checking for all wildcard word matches. (length wildcard is next) */
4287    IF(!SC(tmpbuf,parm)||!SCC(tmpbuf,NS_ANY)||(!SCC(tmpbuf,NS_ALPHA)&&wischeck(
4288    parm,0))||(!SCC(tmpbuf,NS_DIGIT)&&wischeck(parm,1))||(!SCC(tmpbuf,NS_ALNUM)
4289    &&wischeck(parm,2))||(!SCC(tmpbuf,NS_UPPER)&&wischeck(parm,3))||(!SCC(
4290    tmpbuf,NS_LOWER)&&wischeck(parm,4))||(!SCC(tmpbuf,NS_PUNCT)&&wischeck(parm,
4291    5))||(!SCC(tmpbuf,NS_CNTRL)&&wischeck(parm,6))||(!SCC(tmpbuf,NS_PRINT)&&
4292    wischeck(parm,7)))
4293     r=0;
4294    /* the length wildcard, must be four digits long, and then will be */
4295    /* processed accordingly. */
4296    EI(SL(tmpbuf)==5&&tmpbuf[0]==PARAMETER_VAR_CHAR&&ID((U I)tmpbuf[1])&&
4297    ID((U I)tmpbuf[2])&&ID((U I)tmpbuf[3])&&ID((U I)tmpbuf[4])){
4298     tmp=(((tmpbuf[1]-0x30)*1000)+((tmpbuf[2]-0x30)*100)+((tmpbuf[3]-0x30)*10)+
4299     (tmpbuf[4]-0x30));
4300     /* match. */
4301     IF(SL(parm)==tmp)
4302      r=0;
4303     /* did not match. */
4304     E
4305      r=1;
4306    }
4307    E
4308     r=1;
4309    IF(r){
4310     FR(tmpbuf);
4311     R(r);
4312    }
4313   }
4314   E{
4315    FR(tmpbuf);
4316    R(r);
4317   }
4318   FR(tmpbuf);
4319  }
4320  /* leftover data does not count as a match.  just using int i again for the */
4321  /* loop.  checks to see if uneven arguments.  1 = failed, 0 = success. */
4322  i=0;
4323  W(!parameter(parseddynamic,i,0x20))
4324   i++;
4325  IF(!parameter(in,i,0x20))
4326   /* un-even. */
4327   r=1;
4328  E
4329   /* even. */
4330   r=0;
4331  R(r);
4332 }
4333 /* this is meant to pluck a word out of a sentence, then duplicated it to */
4334 /* the character string "parm".  kind of like a strtok() without tokenizing. */
parameter(C * string,I i,U I sep)4335 U SH parameter(C *string,I i,U I sep){
4336  U I j=0;
4337  U I k=0;
4338  U I r=0;
4339  /* no comparison. */
4340  C *buf;
4341  IF(!(buf=(C *)M(SL(string)+1)))
4342   pe("parameter(): allocation of memory error",1);
4343  B(buf,(SL(string)+1));
4344  IF(i<0)
4345   r=1;
4346  E
4347   F(j=0;j<SL(string);j++){
4348    IF(string[j]==sep)
4349     i--;
4350    EI(!i)
4351     buf[k++]=string[j];
4352    IF(string[j]==0x0A||string[j]==0x0)
4353     j=(SL(string)+1);
4354   }
4355  IF(i>0)
4356   r=1;
4357  FR(parm);
4358  IF(!(parm=(C *)SDU(buf)))
4359   pe("parameter(): duplication of memory error",1);
4360  FR(buf);
4361  R(r);
4362 }
4363 /* this function checks word format of their counterpart, instead of a */
4364 /* single character.  for some reason i like using strlen() instead of *buf */
4365 /* to check for use, old habit i suppose. */
wischeck(C * word,U I type)4366 U SH wischeck(C *word,U I type){
4367  U I i=0;
4368  IF(!SL(word))
4369   R(0);
4370  F(i=0;i<SL(word);i++)
4371   IF((!IL((U I)word[i])&&type==0)||(!ID((U I)word[i])&&type==1)||(!isalnum(
4372   (U I)word[i])&&type==2)||(!isupper((U I)word[i])&&type==3)||(!islower((U I)
4373   word[i])&&type==4)||(!ispunct((U I)word[i])&&type==5)||(!iscntrl((U I)
4374   word[i])&&type==6)||(!IP((U I)word[i])&&type==7))
4375    R(0);
4376  R(1);
4377 }
4378 /* this function handles the --list command line argument. */
usefilelist(C * path)4379 U SH usefilelist(C *path){
4380  U SH r=0;
4381  U I i=0;
4382  C *tmppath;
4383  C lread[(BASE_BUFFER*4+1)];
4384  FL *lfd;
4385  glob_t gb;
4386  gb.gl_offs=0;
4387  F(i=0;!parameter(path,i,0x3A);i++){
4388   IF(SL(parm)){
4389    IF(!(tmppath=(C *)M(SL(parm)+3)))
4390     pe("usefilelist(): allocation of memory error",1);
4391    B(tmppath,(SL(parm)+3));
4392    SP(tmppath,"%s/*",parm);
4393    GB(tmppath,(i==0?GLOB_DOOFFS:(GLOB_DOOFFS|GLOB_APPEND)),0,&gb);
4394    FR(tmppath);
4395   }
4396  }
4397  F(i=0;(i<gb.gl_pathc&&i<1000);i++)
4398   nsprint("%.3d\t%.64s%s\n",i,gb.gl_pathv[i],(SL(gb.gl_pathv[i])>64?"...":""));
4399  IF(!i){
4400   pe("no files found to list",1);
4401   r=0;
4402  }
4403  E{
4404   nsprint("enter list value to use(0-%d): ",(i-1));
4405   IF(!(lfd=FO(ttyn,"r")))
4406    pe("could not open standard input for read",1);
4407   E{
4408    B(lread,(BASE_BUFFER*4+1));
4409    IF(FS(lread,(SO(lread)-1),lfd))
4410     F(i=0;i<SL(lread);i++)
4411      IF(lread[i]==0x0A)
4412       lread[i]=0x0;
4413   }
4414   FC(lfd);
4415   IF(!SL(lread)||!wischeck(lread,1))
4416    r=0;
4417   E{
4418    IF(gb.gl_pathc<=AI(lread)||0>AI(lread))
4419     r=0;
4420    E{
4421     IF(!(tofile=(C *)SDU(gb.gl_pathv[AI(lread)])))
4422      pe("usefilelist(): duplication of memory error",1);
4423     r=1;
4424    }
4425   }
4426  }
4427  GBF(&gb);
4428  R(r);
4429 }
4430 /* this function is for using the stored history file(~/.nshistory) to */
4431 /* quickly activate netscript.  (most) output stderr, for this function. */
usehistory(C * preread,U SH type)4432 U SH usehistory(C *preread,U SH type){
4433  U I i=0;
4434  U I j=0;
4435  U I k=0;
4436  U C hread[(BASE_BUFFER*4+1)];
4437  FL *hfd;
4438  IF(!type){
4439   IF(!(hfd=FO(histfile,"r")))
4440    pe("history file does not appear to exist, or is not readable",1);
4441   E{
4442    B(hread,(BASE_BUFFER*4+1));
4443    W(FS(hread,(SO(hread)-1),hfd)&&j<1000){
4444     F(i=0;i<SL(hread);i++)
4445      IF(hread[i]==0x0A)
4446       hread[i]=0x0;
4447     nsprint("%.3d\t%.64s%s\n",j++,hread,(SL(hread)>64?"...":""));
4448    }
4449   }
4450   FC(hfd);
4451   IF(j==0)
4452    pe("history file does not contain any data",1);
4453   nsprint("enter history value to use(0-%d/clear): ",(j-1));
4454   IF(!(hfd=FO(ttyn,"r")))
4455    pe("could not open standard input for read",1);
4456   E{
4457    B(hread,(BASE_BUFFER*4+1));
4458    IF(FS(hread,(SO(hread)-1),hfd))
4459     F(i=0;i<SL(hread);i++)
4460      IF(hread[i]==0x0A)
4461       hread[i]=0x0;
4462   }
4463   FC(hfd);
4464   IF(!SNC(hread,"clear",5))
4465    nsexit(delhistory(histfile),0);
4466   IF(!SL(hread)||!wischeck(hread,1))
4467    R(0);
4468   k=AI(hread);
4469  }
4470  E{
4471   IF(!SL(preread)||!wischeck(preread,1))
4472    R(0);
4473   k=AI(preread);
4474  }
4475  j=0;
4476  IF(!(hfd=FO(histfile,"r")))
4477   pe("history file does not appear to exist, or is not readable",1);
4478  E{
4479   B(hread,(BASE_BUFFER*4+1));
4480   W(FS(hread,(SO(hread)-1),hfd)){
4481    IF(j==k){
4482     F(i=0;i<SL(hread);i++)
4483      IF(hread[i]==0x0A)
4484       hread[i]=0x0;
4485     IF(!(toenv=(C *)M(SL(hread)+1)))
4486      pe("usehistory(): allocation of memory error",1);
4487     B(toenv,(SL(hread)+1));
4488     /* memory compatibility issue.  so, instead, allocate+copy. */
4489     SCP(toenv,hread);
4490     FC(hfd);
4491     R(1);
4492    }
4493    E
4494     j++;
4495   }
4496  }
4497  FC(hfd);
4498  R(0);
4499 }
4500 /* funcation to delete the history file. */
delhistory(C * file)4501 U SH delhistory(C *file){
4502  /* check for existence, and write access. */
4503  IF(AC(file,F_OK)&&AC(file,W_OK)){
4504   pe("could not access the history file to delete",0);
4505   R(1);
4506  }
4507  /* no errors above, attempt to delete. */
4508  EI(UN(file)){
4509   pe("could not delete the history file",0);
4510   R(1);
4511  }
4512  /* deleted without a problem. */
4513  pe("successfully removed the history file",0);
4514  R(0);
4515 }
4516 /* gets arguments out of +x files, if no arguments it will return false, and */
4517 /* not continue. */
getexecargs(C * ruleset)4518 U SH getexecargs(C *ruleset){
4519  U I i=0;
4520  U I j=0;
4521  /* if it is bigger than that someone is just trying to be evil. */
4522  U C rread[(BASE_BUFFER*4+1)];
4523  FL *fd;
4524  IF(!(fd=FO(ruleset,"r")))
4525   pe("ruleset file does not appear to exist, or is not readable",1);
4526  E{
4527   B(rread,(BASE_BUFFER*4+1));
4528   /* only need to read the first two lines for the arguments. */
4529   W(FS(rread,(SO(rread)-1),fd)&&j<2){
4530    IF(SL(rread)>2&&!SNC(rread,"#?",2)){
4531     /* ?(args) + -2("#?") + ?(ruleset) + 4(-r,space,space) + 1(extra). */
4532     IF(!(toenv=(C *)M(SL(rread)-2+SL(ruleset)+4+1)))
4533      pe("getexecargs(): allocation of memory error",1);
4534     B(toenv,(SL(rread)-2+SL(ruleset)+4+1));
4535     SP(toenv,"-r %s ",ruleset);
4536     F(i=2;i<SL(rread);i++){
4537      /* finish true, and append 0x0. */
4538      IF(rread[i]==0x0A){
4539       toenv[SL(toenv)]=0x0;
4540       FC(fd);
4541       R(1);
4542      }
4543      toenv[SL(toenv)]=rread[i];
4544     }
4545    }
4546    j++;
4547   }
4548  }
4549  FC(fd);
4550  R(0);
4551 }
4552 /* function to read /etc/services in conjunction with the -p option to */
4553 /* support services in the form of a string.  for example: "finger". */
4554 /* port should really be a short instead of an int.  but, i wanted error */
4555 /* checking.  so, i used int. */
portentry(C * service)4556 U I portentry(C *service){
4557  S servent *se;
4558  IF(!(se=GS(service,(isudp?"udp":"tcp"))))
4559   R(AI(service));
4560  E
4561   /* convert back from the network byte order that the function does. */
4562   R(NHS(se->s_port));
4563  /* will never really make it here. */
4564  R(0);
4565 }
4566 /* program initializes here.  gets things started. */
main(I ac,C ** av)4567 I main(I ac,C **av){
4568  U SH sethist=0;
4569  U SH setlist=0;
4570  U I i=0;
4571  U I j=0;
4572  U I k=0;
4573  U I l=0;
4574  U I m=0;
4575  U I n=0;
4576  /* the pid of the background process. */
4577  PT bgpid=0;
4578  C *avo;
4579  C *envcmd;
4580  C *histline;
4581  /* threads are only needed for the gui. */
4582 #ifdef GTK
4583  pthread_t pt;
4584 #endif
4585  /* set the static pid value. (for display) */
4586  cpid=GPD();
4587  /* set the program name.  this is kind of like rindex()/strrchr().  but, */
4588  /* slightly different. */
4589  F(i=SL(av[0]);(av[0][i]!=0x2F&&i>0);i--)
4590   j++;
4591  IF(i<=0){
4592   IF(!(progname=(C *)SDU(av[0])))
4593    pe("main(): duplication of memory error",1);
4594  }
4595  E{
4596   /* do not add extra zero'd byte, it is already there at this point. */
4597   IF(!(progname=(C *)M(j)))
4598    pe("main(): allocation of memory error",1);
4599   B(progname,j);
4600   F(i=SL(av[0]);j;i--){
4601    j--;
4602    progname[j]=av[0][i];
4603   }
4604  }
4605  /* ctrl-c. */
4606  SG(SIGINT,sighandler);
4607  /* segmentation fault, hope not to see that. */
4608  SG(SIGSEGV,sighandler);
4609  /* kill, or terminate signal. */
4610  SG(SIGTERM,sighandler);
4611  /* used for timed killing of netscript. */
4612  SG(SIGALRM,sighandler);
4613  /* other signals to catch, for clean up. (not defined in the handler) */
4614  SG(SIGILL,sighandler);
4615  SG(SIGTRAP,sighandler);
4616  SG(SIGBUS,sighandler);
4617  SG(SIGQUIT,sighandler);
4618  /* ignored for binding(with -I).  do not want to exit due to it. */
4619  SG(SIGPIPE,SIG_IGN);
4620  /* make global non-other, and non-group permissions for files made by */
4621  /* netscript. */
4622  UM(077);
4623  /* using this method for global knowledge that if netscript was started */
4624  /* privileged, or not.  any other way the -u option could change the */
4625  /* effects of checking.  since this gets processed first, it will know. */
4626  /* just in the rare case netscript would need to be set*id.  disables */
4627  /* modules, file reading/writing, and third party execution support.  if */
4628  /* started set*id. (or could use stored values for later checking.  but, i */
4629  /* like this method) */
4630  IF(GU()!=GEU()||GG()!=GEG())
4631   isprivileged=1;
4632  E
4633   isprivileged=0;
4634  /* set*id = sete*id.  (mainly for proper permission changes) */
4635  SUD(GEU());
4636  SGD(GEG());
4637  /* write to the array of the defined options. (when compiled) */
4638  setdefined();
4639  /* only time this should be used. */
4640  IF(!isprivileged){
4641   setrc(RCFILE);
4642   sethistory(HISTFILE);
4643  }
4644  /* take care of the modules environmental variable first. */
4645 #ifndef DISABLE_MODULES
4646  IF(G(ENV_MODULE)){
4647   IF(isprivileged)
4648    pe("environmental variable module file ignored with privileged access",0);
4649   E
4650    modhandler((C *)G(ENV_MODULE));
4651  }
4652  /* check, and use the ns_init() symbol, it passes the number of command */
4653  /* line arguments, and the arguments. (int, char **) */
4654  IF(vmodule)
4655   (*init_function)(ac,av);
4656 #endif
4657  /* set the shell for executing third party programs.  make sure it is */
4658  /* executable. */
4659  IF(G(ENV_SHELL)&&!AC((C *)G(ENV_SHELL),X_OK)){
4660   IF(!(eshell=(C *)SDU((C *)G(ENV_SHELL))))
4661    pe("main(): duplication of memory error",1);
4662  }
4663  /* if all else fails.  set default, and hope. */
4664  E{
4665   IF(!(eshell=(C *)SDU(SHPATH)))
4666    pe("main(): duplication of memory error",1);
4667  }
4668  /* set up the display name. */
4669  setdname();
4670  /* set up the tty name. */
4671  IF(!AC(TN(0),R_OK)){
4672   IF(!(ttyn=(C *)SDU(TN(0))))
4673    pe("main(): duplication of memory error",1);
4674  }
4675  E{
4676   IF(!(ttyn=(C *)SDU(INPUTPATH)))
4677    pe("main(): duplication of memory error",1);
4678  }
4679  /* made sure the usage is seen. */
4680  IF(ac>=2&&!SNC(av[1],"--help",6))
4681   usage(1);
4682  /* generalized support for the --hist[ory] option to read ~/.nshistory. */
4683  IF(ac>=2&&!SNC(av[1],"--hist",6)){
4684   IF(isprivileged)
4685    pe("can not use \"--hist\" while in privileged mode",1);
4686   E{
4687    IF(ac>=3&&!SNC(av[2],"clear",5))
4688     nsexit(delhistory(histfile),0);
4689    E{
4690     k=usehistory((ac>=3?av[2]:0),(ac>=3?1:0));
4691     IF(!k)
4692      pe("invalid history value",1);
4693     E
4694      sethist=1;
4695    }
4696   }
4697  }
4698  IF(G(ENV_PATH)||(ac>=2&&!SNC(av[1],"--list",6))){
4699   IF(isprivileged)
4700    pe("can not use \"--list\" while in privileged mode",1);
4701   E{
4702    /* handle the list, environmental variable overrides command line. */
4703    setlist=usefilelist(G(ENV_PATH)?(C *)G(ENV_PATH):(ac>=3?av[2]:"."));
4704    IF(!setlist)
4705     pe("invalid list value",1);
4706   }
4707  }
4708  /* +x ruleset file support, generalized support. (or modified) */
4709  IF(((av[1]&&!av[2])||setlist)&&!AC((setlist?tofile:av[1]),R_OK)&&!AC((setlist?
4710  tofile:av[1]),X_OK))
4711   k=getexecargs(setlist?tofile:av[1]);
4712  /* last use of --list, then everything is passed over. */
4713  IF(setlist){
4714   FR(tofile);
4715   IF(!k)
4716    pe("not a valid (internal argument supplied) netscript ruleset",1);
4717  }
4718  /* check the environment for the command line override variable.  or, take */
4719  /* +x file arguments as env controller, all in one deal. */
4720  IF(G(ENV_CMDLINE)||k){
4721   /* priority 1 is +x files, priority 2 is env var, and priority 3 is the */
4722   /* normal command line. */
4723   IF(k){
4724    IF(!(envcmd=(C *)M(SL(toenv)+SL(av[0])+2)))
4725     pe("main(): allocation of memory error",1);
4726    B(envcmd,(SL(toenv)+SL(av[0])+2));
4727   }
4728   E{
4729    IF(!(envcmd=(C *)M(SL((C *)G(ENV_CMDLINE))+SL(av[0])+2)))
4730     pe("main(): allocation of memory error",1);
4731    B(envcmd,(SL((C *)G(ENV_CMDLINE))+SL(av[0])+2));
4732   }
4733   IF(k){
4734    SP(envcmd,"%s %s",av[0],toenv);
4735    /* done with that buffer. */
4736    FR(toenv);
4737   }
4738   E
4739    SP(envcmd,"%s %s",av[0],(C *)G(ENV_CMDLINE));
4740   /* used this method to make a fresh argument list. */
4741   /* finding out how many elements are needed.  then, nulling the loop */
4742   /* routine since it was all done in the process itself. */
4743   F(ac=0;!parameter(envcmd,ac,0x20);ac++);
4744   /* creates the argument array.  also, added an extra slot for argv[0], */
4745   /* which will remain unused.  but, getopt() expects it. */
4746   IF(!(av=(C **)M((ac+1)*(SO(C *)))))
4747    pe("main(): allocation of memory error",1);
4748   /* fill the array with the data from the env var, or +x file. */
4749   /* (ENV_CMDLINE|+x) */
4750   F(ac=0;!parameter(envcmd,ac,0x20);ac++){
4751    IF(!(av[ac]=(C *)SDU(parm)))
4752     pe("main(): duplication of memory error",1);
4753   }
4754   FR(envcmd);
4755  }
4756  /* add the -g option automatically, if it is linked by "gnetscript". */
4757 #ifdef GTK
4758  IF((!SC(((C *)RI(progname,0x2F)?(C *)RI(progname,0x2F):"0"),"/gnetscript")||
4759  !strcmp(progname,"gnetscript"))&&!isprivileged)
4760   isgui=1;
4761 #endif
4762  /* add the -_ option automatically, if it is linked by "nnetscript". */
4763 #ifdef NCURSES
4764  IF((!SC(((C *)RI(progname,0x2F)?(C *)RI(progname,0x2F):"0"),"/nnetscript")||
4765  !strcmp(progname,"nnetscript")))
4766   isncursesa=1;
4767 #endif
4768  IF(ac>1&&SNC(av[1],"--interactive",13)){
4769   /* set up, and build the (get) option list. */
4770   n=89;
4771 #ifdef GTK
4772   n+=10;
4773 #endif
4774 #ifdef NCURSES
4775   n+=3;
4776 #endif
4777 #ifndef DISABLE_SYSLOG
4778   n+=1;
4779 #endif
4780   IF(!(avo=(C *)M(n+1)))
4781    pe("main(): allocation of memory error",1);
4782   B(avo,(n+1));
4783   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"
4784   "NjJFIsbTyYzLHDwPcCAdvV");
4785 #ifdef GTK
4786   SCA(avo,"G:+:#:K:gW");
4787 #endif
4788 #ifdef NCURSES
4789   SCA(avo,"_=:");
4790 #endif
4791 #ifndef DISABLE_SYSLOG
4792   SCA(avo,"Z");
4793 #endif
4794   /* interpret out the arguments supplied. */
4795   /* i changed a method here, due to me using shorts for most of these */
4796   /* options.  i did not want a possible loop over bug to occur if someone */
4797   /* was trying to break netscript with repeated arguments. (65536) */
4798   W((i=getopt(ac,av,avo))!=EOF){
4799    SW(i){
4800     /* does not matter if a user has privileged access, and loads a ruleset. */
4801     /* because, it never gets relayed verbose. (unless someone knows a rule, */
4802     /* or is traced back/memory) no major concern. */
4803     CS 'r':
4804      /* can not have both. */
4805      IF(!inputrules&&!setfile){
4806       /* does both parsedynamic(), and parsecharvars().  gets used often. */
4807       parsecmdline(optarg);
4808       IF(!(rulesfile=(C *)SDU(parsedline)))
4809        pe("main(): duplication of memory error",1);
4810       setfile=1;
4811      }
4812      BR;
4813     CS 'h':
4814      IF(!bindmode&&!sethost){
4815       W(!parameter(optarg,tshs,0x2C)){
4816        parsecmdline(parm);
4817        IF(!(shost[tshs++]=(C *)SDU(SL(parsedline)?parsedline:"0")))
4818         pe("main(): duplication of memory error",1);
4819        IF(tshs>=MAX_ARGS)
4820         pe("too many slots to store in memory",1);
4821       }
4822       sethost=1;
4823      }
4824      BR;
4825     CS 'p':
4826      IF(!sport)
4827       sport=portentry(optarg);
4828      BR;
4829     /* not very pretty.  but, it will do.  all of these will be handled the */
4830     /* same way.  the statically set dynamic variable options. */
4831     CS '0':
4832     CS '1':
4833     CS '2':
4834     CS '3':
4835     CS '4':
4836     CS '5':
4837     CS '6':
4838     CS '7':
4839     CS '8':
4840     CS '9':
4841      /* do not reset the variable, could cause memory problems. */
4842      IF(dynamicvarset[(i-0x30)]!=2){
4843       parsecmdline(optarg);
4844       IF(!(dynamicvar[(i-0x30)]=(C *)SDU(parsedline)))
4845        pe("main(): duplication of memory error",1);
4846       /* define it not to be changed, or reset. */
4847       dynamicvarset[(i-0x30)]=2;
4848      }
4849      BR;
4850     CS 'i':
4851      IF(!initsend){
4852       parsecmdline(optarg);
4853       IF(!(iswrite=(C *)SDU(parsedline)))
4854        pe("main(): duplication of memory error",1);
4855       initsend=1;
4856      }
4857      BR;
4858     CS 'm':
4859      IF(!setcdir){
4860       parsecmdline(optarg);
4861       IF(!(cdir=(C *)SDU(parsedline)))
4862        pe("main(): duplication of memory error",1);
4863       setcdir=1;
4864      }
4865      BR;
4866     CS 'M':
4867      IF(!setrdir){
4868       parsecmdline(optarg);
4869       IF(!(rdir=(C *)SDU(parsedline)))
4870        pe("main(): duplication of memory error",1);
4871       setrdir=1;
4872      }
4873      BR;
4874     CS 'R':
4875      IF(!setroute){
4876       parsecmdline(optarg);
4877       IF(!(rhost=(C *)SDU(parsedline)))
4878        pe("main(): duplication of memory error",1);
4879       setroute=1;
4880      }
4881      BR;
4882     CS 'k':
4883      IF(AI(optarg)>0&&!rport)
4884       rport=AI(optarg);
4885      BR;
4886     CS 'u':
4887      IF(!setperms){
4888       setpermissions(optarg,0);
4889       setperms=1;
4890      }
4891      BR;
4892     CS 'q':
4893      IF(!isvhost){
4894       IF(!(vhost=(C *)SDU(optarg)))
4895        pe("main(): duplication of memory error",1);
4896       isvhost=1;
4897      }
4898      BR;
4899     CS 'o':
4900      IF(!omitchars){
4901       parsecmdline(optarg);
4902       IF(!(ochars=(C *)SDU(parsedline)))
4903        pe("main(): duplication of memory error",1);
4904       omitchars=1;
4905      }
4906      BR;
4907     CS 'S':
4908      IF(AI(optarg)>0&&!sdelay)
4909       sdelay=AI(optarg);
4910      BR;
4911     CS 'U':
4912      IF(AL(optarg)>0&&!sudelay)
4913       sudelay=AL(optarg);
4914      BR;
4915     CS 't':
4916      IF(AI(optarg)>0&&!alrm)
4917       alrm=AI(optarg);
4918      BR;
4919     CS 'Q':
4920      IF(!soptions){
4921       parsecmdline(optarg);
4922       IF(!(sopts=(C *)SDU(parsedline)))
4923        pe("main(): duplication of memory error",1);
4924       soptions=1;
4925      }
4926      BR;
4927     CS 'l':
4928      IF(isprivileged)
4929       pe("can not log data to a file with privileged access",0);
4930      E
4931       IF(!islog){
4932        parsecmdline(optarg);
4933        IF(!(logfile=(C *)SDU(parsedline)))
4934         pe("main(): duplication of memory error",1);
4935        islog=1;
4936       }
4937      BR;
4938 #ifdef GTK
4939     CS 'G':
4940      IF(!isguititle){
4941       parsecmdline(optarg);
4942       IF(!(guititle=(C *)SDU(parsedline)))
4943        pe("main(): duplication of memory error",1);
4944       isguititle=1;
4945      }
4946      BR;
4947     CS '+':
4948      IF(AI(optarg)>0&&!guio)
4949       guio=(AI(optarg)>GUI_MAXLEN?GUI_MAXLEN:AI(optarg));
4950      BR;
4951     CS '#':
4952      IF(!isguic){
4953       parsecmdline(optarg);
4954       IF(SL(parsedline)==6){
4955        B((V *)guic,SO(guic));
4956        F(isguic=i=0;i<6;i+=2){
4957         IF(IL((U I)parsedline[i]))
4958          j=(TL(parsedline[i])-0x56);
4959         E
4960          j=(parsedline[i]-0x2F);
4961         j*=16;
4962         IF(IL((U I)parsedline[i+1]))
4963          j+=(TL(parsedline[i+1])-0x56);
4964         E
4965          j+=(parsedline[i+1]-0x2F);
4966         j-=17;
4967         IF(j>=0&&j<256)
4968          guic[isguic]=(j*257);
4969         isguic++;
4970        }
4971       }
4972      }
4973      BR;
4974     CS 'K':
4975      IF(!isguil){
4976       parsecmdline(optarg);
4977       W(!parameter(parsedline,isguil,0x3A)&&isguil<3){
4978        IF(!(gblabel[isguil++]=(C *)SDU(SL(parm)?parm:"nolabel")))
4979         pe("main(): duplication of memory error",1);
4980       }
4981      }
4982      BR;
4983 #endif
4984     CS 'e':
4985      IF(isprivileged)
4986       pe("third party programs can not be executed with privileged access",0);
4987      E
4988       IF(!runcmd){
4989        parsecmdline(optarg);
4990        IF(!(execfile=(C *)SDU(parsedline)))
4991         pe("main(): duplication of memory error",1);
4992        runcmd=1;
4993       }
4994      BR;
4995     CS 'E':
4996      IF(!runpre){
4997       parsecmdline(optarg);
4998       IF(!(execpre=(C *)SDU(parsedline)))
4999        pe("main(): duplication of memory error",1);
5000       runpre=1;
5001      }
5002      BR;
5003     CS 'O':
5004      IF(!setshell){
5005       parsecmdline(optarg);
5006       /* make sure it is executable. */
5007       IF(!AC(parsedline,X_OK)){
5008        /* was set by the environment, or default earlier.  free it. */
5009        FR(eshell);
5010        IF(!(eshell=(C *)SDU(parsedline)))
5011         pe("main(): duplication of memory error",1);
5012        setshell=1;
5013       }
5014      }
5015      BR;
5016     CS 'x':
5017      IF(AI(optarg)>0&&!xalrm)
5018       xalrm=AI(optarg);
5019      BR;
5020     CS 'X':
5021      runexit=1;
5022      BR;
5023     CS 'a':
5024      isiexec=1;
5025      BR;
5026     CS 'f':
5027      editrules=1;
5028      BR;
5029     CS '@':
5030      isudp=1;
5031      BR;
5032     CS '^':
5033      isudpr=1;
5034      BR;
5035     CS 'B':
5036      isbg=1;
5037      BR;
5038     CS 'n':
5039      nossend=1;
5040      BR;
5041     CS 'N':
5042      nosrecv=1;
5043      BR;
5044     CS 'j':
5045      norsend=1;
5046      BR;
5047     CS 'J':
5048      norrecv=1;
5049      BR;
5050     CS 'F':
5051      nofrom=1;
5052      BR;
5053     CS 'I':
5054      forever=1;
5055      BR;
5056     CS 's':
5057      /* can not have both. */
5058      IF(!setfile)
5059       inputrules=1;
5060      BR;
5061     CS 'b':
5062      /* can not have both. */
5063      IF(!sethost)
5064       bindmode=1;
5065      BR;
5066 #ifdef GTK
5067     CS 'g':
5068      IF(!isgui){
5069       IF(!isprivileged)
5070        isgui=1;
5071       E
5072        pe("the gui frontend can not be used when netscript is privileged",0);
5073      }
5074      E
5075       isbgui=1;
5076      BR;
5077     CS 'W':
5078      isguis=1;
5079      BR;
5080 #endif
5081 #ifdef NCURSES
5082     CS '_':
5083      isncursesa=1;
5084      BR;
5085     CS '=':
5086      IF(!isncursesl){
5087       parsecmdline(optarg);
5088       W(!parameter(parsedline,isncursesl,0x3A)&&isncursesl<2){
5089        IF(!(nclabel[isncursesl++]=(C *)SDU(SL(parm)?parm:"nolabel")))
5090         pe("main(): duplication of memory error",1);
5091       }
5092      }
5093 #endif
5094 #ifndef DISABLE_SYSLOG
5095     CS 'Z':
5096      slog=1;
5097      BR;
5098 #endif
5099     CS 'T':
5100      tnet=1;
5101      BR;
5102     CS 'y':
5103      tnetraw=1;
5104      BR;
5105     CS 'Y':
5106      tnetraw=2;
5107      BR;
5108     CS 'z':
5109      notnetopt=1;
5110      BR;
5111     CS 'L':
5112      /* set option, and force the no wrapping option. (-w option) */
5113      lnum=lnum_i=lnum_o=nowrap=1;
5114      BR;
5115     CS 'H':
5116      /* 0 = character, 1 = hex, 2 = decimal. */
5117      displaytype=1;
5118      BR;
5119     CS 'D':
5120      /* 0 = character, 1 = hex, 2 = decimal. */
5121      displaytype=2;
5122      BR;
5123     CS 'w':
5124      nowrap=1;
5125      BR;
5126     CS 'P':
5127      printonly=1;
5128      BR;
5129     CS 'c':
5130      noshowc=1;
5131      BR;
5132     CS 'C':
5133      noshowp=1;
5134      BR;
5135     CS 'A':
5136      noshowa=1;
5137      BR;
5138     CS 'd':
5139      displayv();
5140      BR;
5141     CS 'v':
5142      showinfo(1);
5143      nsexit(0,0);
5144      BR;
5145     CS 'V':
5146      showv=2;
5147      BR;
5148     default:
5149      usage(0);
5150      BR;
5151    }
5152   }
5153   /* done with buffer forever. */
5154   FR(avo);
5155  }
5156  E
5157   iface(IFACE_PREFIX);
5158  /* if chroot, handle first. */
5159  IF(setrdir){
5160   CR(rdir);
5161   FR(rdir);
5162  }
5163  /* if chdir, handle second. */
5164  IF(setcdir){
5165   CD(cdir);
5166   FR(cdir);
5167  }
5168  /* check for -r|s|f, -h|b, and -p(int->short style) options. */
5169  IF((!setfile&&!inputrules&&!editrules)||(!sethost&&!bindmode)||(1>sport||
5170  65535<sport)){
5171   pe("no ruleset option, host|bind option, and/or port option defined",0);
5172   IF(ac>1)
5173    usage(1);
5174   E
5175    nsexit(0,0);
5176  }
5177  /* default if invalid, or non-existent. */
5178  IF(1>rport||65535<rport)
5179   rport=sport;
5180  /* ruleset editor. (-f option) */
5181  IF(editrules&&!inputrules){
5182   IF(setfile)
5183    editrules=2;
5184   ruleedit(setfile,(setfile?rulesfile:0));
5185  }
5186  /* make, and define the ruleset. */
5187  makelists(rulesfile);
5188  /* remove temporary ruleset, only if a temporary file. (no verbose) */
5189  IF(editrules==1)
5190   UN(rulesfile);
5191  /* if gui mode is on, disable certain option(s). */
5192 #ifdef GTK
5193  /* can not do both, at least making sense. */
5194  IF(isbg)
5195   isgui=0;
5196  EI(isgui&&tnetraw){
5197   tnetraw=0;
5198   tnet=1;
5199  }
5200 #endif
5201  /* if one of the telnet fix options is supplied, fix conflicting option(s). */
5202  /* also, forces telnet mode. (-y, and -Y options) */
5203  IF(tnetraw)
5204   tnet=noshowa=nossend=nosrecv=1;
5205 #ifdef GTK
5206  IF(isgui){
5207   g_thread_init(0);
5208   /* gtk initialization, passes arguments for gtk to handle. */
5209   gtk_init(&ac,&av);
5210   /* get things going.  if it fails for some reason, exit. */
5211   IF(pthread_create(&pt,0,(V *)*gtkrun,(inputrules?"(standard input)":rulesfile
5212   )))
5213    pe("could not create pthread, for the gui",1);
5214   /* time to catch up. */
5215   W(!isagui)
5216    USLP(250000);
5217  }
5218 #endif
5219  /* main argument checking done, continuing on. */
5220  IF(showv)
5221   showinfo(showv);
5222  /* check for non-dfl columns, for the pd() display function with wordwrap. */
5223  /* do this before using the pd() function at all. */
5224  IF(G(ENV_COLUMNS)){
5225   columns=AI((C *)G(ENV_COLUMNS));
5226   /* no need for anything larger, unless you are trying to bother memory. */
5227   IF(1024<columns){
5228    pe("ENV_COLUMNS environmental variable is too large",0);
5229    columns=DFL_COLUMNS;
5230   }
5231   /* the prompt itself must be counted in the most minimal of cases. */
5232   IF((1>columns&&nofrom)||(4>columns&&!nofrom)){
5233    pe("ENV_COLUMNS environmental variable is too small",0);
5234    columns=DFL_COLUMNS;
5235   }
5236  }
5237  E
5238   columns=DFL_COLUMNS;
5239  /* same idea as above.  except a different kind of checking. */
5240  IF(G(ENV_BACKLOG)){
5241   blog=AI((C *)G(ENV_BACKLOG));
5242   IF(128<blog){
5243    pe("ENV_BACKLOG environmental variable is too large",0);
5244    blog=DFL_BACKLOG;
5245   }
5246   IF(1>blog){
5247    pe("ENV_BACKLOG environmental variable is too small",0);
5248    blog=DFL_BACKLOG;
5249   }
5250  }
5251  E
5252   blog=DFL_BACKLOG;
5253  /* command line is a priority. */
5254  IF(!isvhost&&G(ENV_VHOST)){
5255   IF(!(vhost=(C *)SDU((C *)G(ENV_VHOST))))
5256    pe("main(): duplication of memory error",1);
5257   isvhost=1;
5258  }
5259  /* there would atleast have been one argument to have made it this far. */
5260  F(j=1;j<ac;j++)
5261   /* +1 for the space. (CR) */
5262   m+=(SL(av[j])+1);
5263  IF(!(histline=(C *)M(m+1)))
5264   pe("main(): allocation of memory error",1);
5265  B(histline,(m+1));
5266  F(j=1;j<ac;j++){
5267   SCA(histline,av[j]);
5268   IF((j+1)!=ac)
5269    SCA(histline," ");
5270  }
5271 #ifndef DISABLE_SYSLOG
5272  wrso("%d-%d id: %lu-%u.%u.%u.%u init: %s",slnum_t,(slnum_s++),cpid,GU(),GEU(),
5273  GG(),GEG(),(SL(histline)?histline:"<no command line>"));
5274 #endif
5275  /* no need to re-write history. (sethist) */
5276  IF(!isprivileged&&!sethist&&SL(histline))
5277   addhistory(histline);
5278  /* done with this, forever. */
5279  FR(histline);
5280  SW(isbg?(bgpid=FK()):0){
5281   CS -1:
5282    pe("could not fork into the background",1);
5283    BR;
5284   CS 0:
5285    /* only if really backgrounding. */
5286    IF(isbg){
5287     /* no more output now.  close up shop, just to make sure nothing is */
5288     /* outputed. */
5289     CL(0);
5290     CL(1);
5291     CL(2);
5292     isbga=1;
5293    }
5294    /* initialize ncurses, after everything is ready to go. (compiled option) */
5295 #ifdef NCURSES
5296    IF(!(!isncursesa||isbg||tnetraw))
5297 #ifdef GTK
5298    IF(!isgui)
5299 #endif
5300     ncursesinit();
5301 #endif
5302    /* infinite connecting/binding. (-I option) */
5303    IF(forever){
5304     W(1){
5305      /* either stops after all those hosts, to get reset.  or, stays binded */
5306      /* forever. */
5307      W(l<tshs||bindmode){
5308       parsesocket(bindmode?0:shost[l++],sport);
5309 #ifndef DISABLE_SYSLOG
5310       /* should only log closings, if is a multi-remote run.  otherwise, it */
5311       /* would show the static close, and exit everytime.  a waste of space. */
5312       wrso("%d-%d id: %lu-%u.%u.%u.%u closed: %d",slnum_t,slnum_s,cpid,GU(),
5313       GEU(),GG(),GEG(),slnum_t);
5314       /* reset system log counter. */
5315       slnum_s=0;
5316       /* +1 the total. */
5317       slnum_t++;
5318 #endif
5319       /* better safe than sorry, do not want fds to fill up. */
5320       closesocket(0);
5321       SLP(1);
5322      }
5323      l=0;
5324     }
5325    }
5326    E{
5327     W(l<tshs||bindmode){
5328      parsesocket(bindmode?0:shost[l++],sport);
5329      /* turn bindmode off to leave this loop, and exit. (if bindmode) */
5330      bindmode=0;
5331      /* better safe than sorry, do not want fds to fill up. */
5332      closesocket(0);
5333      SLP(1);
5334     }
5335    }
5336    /* for backgrounding only. */
5337    IF(isbga)
5338     nsexit(0,1);
5339    BR;
5340   default:
5341    nsprint("PID: [%lu@%s]\n",bgpid,nname);
5342    BR;
5343  }
5344  nsexit(0,0);
5345  /* never will actually make it to this point.  but, will shut up warnings. */
5346  exit(0);
5347 }
5348 /* EOF */
5349