int read_data(char* fname) { FILE * fp = NULL; line_num = 0; char* data = NULL; size_t len; ssize_t readsz; int i; const int memory_block = 1024*1024; int lines_allocated = memory_block; fp = fopen(fname, "r"); if (fp == NULL) { die_with_message("read data file error"); } lines = (Line**)malloc(lines_allocated * sizeof(Line*)); if (lines == NULL){ die_with_message("out of memory"); } for (i=0;1;i++) { if ((readsz = getline(&data, &len, fp)) == -1) { break; } Line* pline = (Line*)malloc(sizeof(Line)); if (pline == NULL){ die_with_message("out of memory"); } pline->len = readsz; pline->data = data; pline->line_no = i; /*remove "/r/n" */ for(data = pline->data+readsz-1; *data=='\n'||*data=='\r'; data--, pline->len--); *(data+1) = '\0'; /*add 10 more for the line no*/ pline->buf = malloc(pline->len + 10); pline->buf_len = 0; if (i >= lines_allocated) { int new_size = lines_allocated + memory_block; lines = (Line**)realloc(lines, new_size * sizeof(Line*)); if (lines == NULL){ die_with_message("out of memory"); } lines_allocated = new_size; } lines[i] = pline; data = NULL; line_num++; } return 0; }
void preprocess_token_list(token_t* tokenlist) { script_t* newscript; token_t* me; char* cp; me = tokenlist; while(me) { if(memcmp(me->buf, open_tag, 2)) { me->tag = HTML; } else { me->tag = NOOP; me->buf[me->len] = '\0'; cp = me->buf + 2; if(memcmp(cp, g_tag[ECHO], 1) == 0) { me->tag = ECHO; me->buf = find_whitespace(me->buf); me->len = strlen(me->buf); } else if(memcmp(cp, g_tag[TRANSLATE], 1) == 0) { me->tag = TRANSLATE; me->buf = find_whitespace(me->buf); me->len = strlen(me->buf); } if(isspace(*cp)) { me->tag = RUN; me->buf = cp; } if(me->tag == NOOP) { die_with_message(me->script, cp, g_err_msg[E_NO_OP]); } me->len = strlen(me->buf); } me = me->next; } }
/* * realloc memory, or die xmalloc style. */ void * xrealloc (void *buf, size_t size) { if ((buf = realloc (buf, size)) == NULL) { die_with_message (NULL, NULL, g_err_msg[E_MALLOC_FAIL]); } return buf; }
static void vdiec(int eval, int code, const char *fmt, va_list ap) { char buf[4096], msg[4096]; vsnprintf(buf, array_sizeof(buf), fmt, ap); snprintf(msg, array_sizeof(msg), "%s: %s", buf, strerror(code)); die_with_message(eval, msg); /* NOTREACHED */ }
token_t* build_token_list(script_t* scriptbuf, token_t* tokenlist) { char* start; char* end; char* curpos; char* endpos; token_t* curtoken; token_t* firsttoken; curtoken = tokenlist; firsttoken = tokenlist; curpos = scriptbuf->buf + scriptbuf->curpos; endpos = scriptbuf->buf + scriptbuf->size; while(curpos < endpos) { start = strstr(curpos, open_tag); end = strstr(curpos, close_tag); if(start && !end) { die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]); } if((start > end) || (!start && end)) { die_with_message(scriptbuf, end, g_err_msg[E_END_BEFORE_BEGIN], open_tag[1], open_tag[1]); } if(start && (strstr(start + 1, open_tag) && (strstr (start + 1, open_tag) < end))) die_with_message(scriptbuf, start, g_err_msg[E_NO_END_MARKER], open_tag[1]); if(end) { curtoken = push_token_on_list(curtoken, scriptbuf, curpos, start - curpos); if(firsttoken == NULL) { firsttoken = curtoken; } curtoken = push_token_on_list(curtoken, scriptbuf, start, end - start); if(firsttoken == NULL) { firsttoken = curtoken; } curpos = end + 2; } else { curtoken = push_token_on_list(curtoken, scriptbuf, curpos, endpos - curpos); if(firsttoken == NULL) { firsttoken = curtoken; } curpos = endpos; } } return firsttoken; }
void subshell_setup (char* shell, list_t* env) { int retcode = 0; int count; argv_t* argv; char* av[20]; list_t* next; if(shell == NULL) { return; } retcode = pipe(&subshell_pipe[PARENT_IN]); if(retcode == 0) { subshell_pid = fork(); if(subshell_pid == -1) { die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } if(subshell_pid == 0) { dup2(subshell_pipe[PARENT_IN], STDIN_FILENO); close(subshell_pipe[PARENT_IN]); close(subshell_pipe[PARENT_OUT]); count = argc_argv(shell, &argv); if(count > 19) { av[19] = "\0"; count = 18; } while(count >= 0) { av[count] = argv[count].string; count--; } while(env) { next = env->next; putenv(env->buf); env = next; } execv(argv[0].string, av); free(argv); die_with_message(NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } else { close(subshell_pipe[PARENT_IN]); } } }
void __die_for_assertion(const char *filename, int lineno, const char *expr) { size_t msgsize; const char *fmt = "assertion at %s:%u for %s: %s"; char msg[8192]; msgsize = sizeof(msg); snprintf(msg, msgsize, fmt, filename, lineno, expr, asserting_message); die_with_message(128, msg); }
void diex(int eval, const char *fmt, ...) { va_list ap; char buf[4096]; va_start(ap, fmt); vsnprintf(buf, array_sizeof(buf), fmt, ap); va_end(ap); die_with_message(eval, buf); }
/* * allocate memory or die, busybox style. */ void * xmalloc (size_t size) { void *buf; if ((buf = malloc (size)) == NULL) { die_with_message (NULL, NULL, g_err_msg[E_MALLOC_FAIL]); } memset (buf, 0, size); return buf; }
void lua_doscript (buffer_t * script, char *name) { int status; /* force the string to be null terminated */ buffer_add (script, "\0", 1); status = luaL_loadbuffer (lua_vm, (char *) script->data, strlen ((char *) script->data), name) || lua_pcall (lua_vm, 0, LUA_MULTRET, 0); if (status && !lua_isnil (lua_vm, -1)) { const char *msg = lua_tostring (lua_vm, -1); if (msg == NULL) msg = "(error object is not a string)"; die_with_message (NULL, NULL, msg); } }
script_t* load_script(char* filename, script_t* scriptlist) { script_t* scriptbuf; int scriptfp; struct stat filestat; scriptfp = open(filename, O_NONBLOCK + O_RDONLY); if(scriptfp == -1) { die_with_message(NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], filename); } fstat(scriptfp, &filestat); scriptbuf = (script_t *) xmalloc(sizeof (script_t)); scriptbuf->name = (char *) xmalloc(strlen (filename) + 1); scriptbuf->buf = (char *) xmalloc(filestat.st_size + 1); memset(scriptbuf->name, 0, strlen(filename) + 1); memcpy(scriptbuf->name, filename, strlen(filename)); memset(scriptbuf->buf, 0, filestat.st_size + 1); read(scriptfp, scriptbuf->buf, filestat.st_size); scriptbuf->size = filestat.st_size; scriptbuf->uid = filestat.st_uid; scriptbuf->gid = filestat.st_gid; scriptbuf->curpos = 0; scriptbuf->next = NULL; if(scriptlist != NULL) { while(scriptlist->next) { scriptlist = scriptlist->next; } scriptlist->next = scriptbuf; } if(memcmp(scriptbuf->buf, "#!", 2) == 0) { while((scriptbuf->curpos < scriptbuf->size) && ((char) scriptbuf->buf[scriptbuf->curpos] != '\n')) { (scriptbuf->curpos)++; } (scriptbuf->curpos)++; } close(scriptfp); return scriptbuf; }
int rfc2388_handler (list_t * env) { enum mime_state_t { DISCARD, BOUNDARY, HEADER, CONTENT }; int state; int i, x; unsigned long max_len, content_length; sliding_buffer_t sbuf; char *crlf = "\r\n"; char *boundary; char *str; buffer_t buf; mime_var_t var; /* get the boundary info */ str = getenv ("CONTENT_TYPE"); i = strlen (str) - 9; while ((i >= 0) && (memcmp ("boundary=", str + i, 9))) { i--; } if (i == -1) { empty_stdin (); die_with_message (NULL, NULL, "No Mime Boundary Information Found"); } i = i + 9; if (str[i] == '"') i++; boundary = xmalloc (strlen (str + i) + 5); /* \r\n-- + NULL */ memcpy (boundary, crlf, 2); memcpy (boundary + 2, "--", 2); memcpy (boundary + 4, str + i, strlen (str + i) + 1); if ((i > 0) && (str[i - 1] == '"')) { while ((boundary[i]) && (boundary[i] != '"')) i++; boundary[i] = '\0'; } /* Allow 2MB content, unless they have a global upload set */ max_len = ((global.uploadkb == 0) ? 2048 : global.uploadkb) *1024; content_length = 0; /* initialize a 128K sliding buffer */ s_buffer_init (&sbuf, 1024 * 128); sbuf.fh = STDIN; if (getenv ("CONTENT_LENGTH")) { sbuf.maxread = strtoul (getenv ("CONTENT_LENGTH"), NULL, 10); } /* initialize the buffer, and make sure it doesn't point to null */ buffer_init (&buf); buffer_add (&buf, "", 1); buffer_reset (&buf); state = DISCARD; str = boundary + 2; /* skip the leading crlf */ do { /* x is true if this token ends with a matchstr or is at the end of stream */ x = s_buffer_read (&sbuf, str); content_length += sbuf.len; if (content_length >= max_len) { empty_stdin (); free (boundary); s_buffer_destroy (&sbuf); buffer_destroy (&buf); if (var.name) { mime_var_destroy (&var); } die_with_message (NULL, NULL, "Attempted to send content larger than allowed limits."); } switch (state) { case DISCARD: /* discard any text - used for first mime boundary */ if (x) { state = BOUNDARY; str = crlf; buffer_reset (&buf); /* reinitializes the buffer */ } break; case BOUNDARY: if (!x) { buffer_add (&buf, sbuf.segment, sbuf.len); } if (x) { buffer_add (&buf, sbuf.segment, sbuf.len); if (!memcmp (buf.data, boundary + 2, 2)) { /* "--" */ /* all done... what does that mean? */ str = boundary + 2; state = DISCARD; } else { buffer_reset (&buf); mime_var_init (&var); state = HEADER; str = crlf; } } break; case HEADER: buffer_add (&buf, sbuf.segment, sbuf.len); if (x) { if (sbuf.len == 0) { /* blank line */ buffer_reset (&buf); state = CONTENT; str = boundary; } else { buffer_add (&buf, "", 1); mime_tag_add (&var, (char *) buf.data); buffer_reset (&buf); } } break; case CONTENT: /* write to writer process, regardless */ mime_var_writer (&var, (char *) sbuf.segment, sbuf.len); if (x) { buffer_reset (&buf); mime_var_putenv (env, &var); mime_var_destroy (&var); state = BOUNDARY; str = crlf; } break; } /* end switch */ } while (!sbuf.eof); free (boundary); s_buffer_destroy (&sbuf); buffer_destroy (&buf); return (0); }
void mime_var_open_target (mime_var_t * obj) { char *tmpname; token_t *curtoken; curtoken = global.uploadlist; int ok; /* if upload_limit is zero, we die right here */ if (global.uploadkb == 0) { empty_stdin (); die_with_message (NULL, NULL, "File uploads are not allowed."); } ok = -1; tmpname = xmalloc (strlen (global.uploaddir) + 8); strcpy (tmpname, global.uploaddir); strcat (tmpname, "/XXXXXX"); obj->fh = mkstemp (tmpname); if (obj->fh == -1) { ok = 0; } /* reuse the name as a fifo if we have a handler. We do this * because tempnam uses TEMPDIR if defined, among other bugs */ if ((ok) && global.uploadhandler) { /* I have a handler */ close (obj->fh); unlink (tmpname); if (mkfifo (tmpname, 0600)) ok = 0; /* you must open the fifo for reading before writing * on non linux systems */ if (ok) { mime_exec (obj, tmpname); obj->fh = open (tmpname, O_WRONLY); } if (obj->fh == -1) ok = 0; } else { buffer_add (&(obj->value), tmpname, strlen (tmpname)); } if (!ok) { empty_stdin (); die_with_message (NULL, NULL, g_err_msg[E_FILE_OPEN_FAIL], tmpname); } curtoken = push_token_on_list (curtoken, NULL, tmpname, strlen (tmpname) + 1); if (global.uploadlist == NULL) { global.uploadlist = curtoken; } }
void mime_exec (mime_var_t * obj, char *fifo) { int pid; char *av[4]; char *type, *filename, *name; char *c; int fh; pid = fork (); if (pid == -1) { empty_stdin (); die_with_message (NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } if (pid == 0) { /* store the content type, filename, and form name */ /* we do not use global.var_prefix because it could be lua or shell * or something else, and we are only shell here */ if (obj->type) { type = xmalloc (13 + strlen (obj->type) + 1); sprintf (type, "CONTENT_TYPE=%s", obj->type); putenv (type); } if (obj->filename) { filename = xmalloc (9 + strlen (obj->filename) + 1); sprintf (filename, "FILENAME=%s", obj->filename); putenv (filename); } if (obj->name) { name = xmalloc (5 + strlen (obj->name) + 1); sprintf (name, "NAME=%s", obj->name); putenv (name); } av[0] = global.uploadhandler; av[1] = fifo; av[2] = NULL; execv (av[0], av); /* if we get here, we had a failure. Not much we can do. * We are the child, so we can't even warn the parent */ fh = open (fifo, O_RDONLY); while (read (fh, &c, 1)) { } exit (-1); } else { /* I'm parent */ } /* control should get to this point only in the parent. */ } /* end mime_exec */
void bash_setup (char *shell, list_t * env) { int retcode = 0; int count; argv_t *argv; char *av[20]; list_t *next; if (shell == NULL) return; retcode = pipe (&subshell_pipe[PARENT_IN]); if (retcode == 0) { #ifdef EMBED subshell_pid = vfork (); #else subshell_pid = fork (); #endif if (subshell_pid == -1) { die_with_message (NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } if (subshell_pid == 0) { /* I'm the child, connect stdin to the parent */ dup2 (subshell_pipe[PARENT_IN], STDIN_FILENO); close (subshell_pipe[PARENT_IN]); close (subshell_pipe[PARENT_OUT]); count = argc_argv (shell, &argv, ""); if (count > 19) { /* over 20 command line args, silently truncate */ av[19] = "\0"; count = 18; } while (count >= 0) { av[count] = argv[count].string; count--; } /* populate the environment */ while (env) { next = env->next; putenv (env->buf); env = next; } execv (argv[0].string, av); free (argv); /* if we get here, we had a failure */ die_with_message (NULL, NULL, g_err_msg[E_SUBSHELL_FAIL]); } else { /* I'm parent, move along please */ close (subshell_pipe[PARENT_IN]); } } /* control should get to this point only in the parent. */ }
int main (int argc, char *argv[]) { #ifndef JUST_LUACSHELL token_t *tokenchain = NULL; buffer_t script_text; #endif script_t *scriptchain; int retval = 0; char *filename = NULL; argv_t *av = NULL; char **av2 = argv; int av2c = argc; int command; int count; list_t *env = NULL; assignGlobalStartupValues (); #ifndef JUST_LUACSHELL haserl_buffer_init (&script_text); #endif /* if more than argv[1] and argv[1] is not a file */ switch (argc) { case 1: /* we were run, instead of called as a shell script */ puts ("This is " PACKAGE_NAME " version " PACKAGE_VERSION "\n" "This program runs as a cgi interpeter, not interactively\n" "Please see: http://haserl.sourceforge.net\n" #ifdef USE_LUA "This version includes Lua (precompiled" #ifdef INCLUDE_LUASHELL " and interpreted" #endif ")\n" #endif #ifdef BASHEXTENSIONS "Unsupported bash extensions supplied by simnux enabled\n" #endif ); return (0); break; default: /* more than one */ /* split combined #! args - linux bundles them as one */ command = argc_argv (argv[1], &av, ""); if (command > 1) { /* rebuild argv into new av2 */ av2c = argc - 1 + command; av2 = xmalloc (sizeof (char *) * av2c); av2[0] = argv[0]; for (count = 1; count <= command; count++) { av2[count] = av[count - 1].string; } for (; count < av2c; count++) { av2[count] = argv[count - command + 1]; } } parseCommandLine (av2c, av2); free (av); if (av2 != argv) free (av2); if (optind < av2c) { filename = av2[optind]; } else { die_with_message (NULL, NULL, "No script file specified"); } break; } if (av2[0] != NULL && command == 1) { //prevents argument reconstruction (update.sh & reboot.sh) unsigned int prg_len=strlen(av2[0]); if (memcmp(av2[0]+prg_len-4, "i18n", 4) == 0) { if (global.translationKV_map == NULL) { buildTranslationMap (); } lookup_key (NULL, av2[optind], HASERL_SHELL_SYMBOLIC_LINK); buffer_destroy (&script_text); unsigned long num_destroyed; destroy_string_map(global.translationKV_map, DESTROY_MODE_IGNORE_VALUES, &num_destroyed); return (0); } } scriptchain = load_script (filename, NULL); /* drop permissions */ BecomeUser (scriptchain->uid, scriptchain->gid); /* populate the function pointers based on the shell selected */ if (strcmp (global.shell, "lua") && strcmp (global.shell, "luac")) /* default to "bash" */ { #ifdef INCLUDE_BASHSHELL shell_exec = &bash_exec; shell_echo = &bash_echo; shell_eval = &bash_eval; shell_setup = &bash_setup; shell_doscript = &bash_doscript; shell_destroy = &bash_destroy; #ifdef BASHEXTENSIONS shell_if = &bash_if; shell_elif = &bash_elif; shell_else = &bash_else; shell_endif = &bash_endif; shell_case = &bash_case; shell_when = &bash_when; shell_otherwise = &bash_otherwise; shell_endcase = &bash_endcase; shell_while = &bash_while; shell_endwhile = &bash_endwhile; shell_until = &bash_until; shell_enduntil = &bash_enduntil; shell_for = &bash_for; shell_endfor = &bash_endfor; shell_unless = &bash_unless; shell_elun = &bash_elun; shell_unelse = &bash_unelse; shell_endunless = &bash_endunless; #endif #else die_with_message (NULL, NULL, "Bash shell is not enabled."); #endif } else { #ifdef USE_LUA shell_setup = &lua_common_setup; shell_destroy = &lua_common_destroy; global.var_prefix = "FORM."; global.nul_prefix = "ENV."; if (global.shell[3] == 'c') /* luac only */ #ifdef INCLUDE_LUACSHELL shell_doscript = &luac_doscript; #else die_with_message (NULL, NULL, "Compiled Lua shell is not enabled."); #endif else { #ifdef INCLUDE_LUASHELL shell_exec = &lua_exec; shell_echo = &lua_echo; shell_eval = &lua_eval; shell_doscript = &lua_doscript; #else die_with_message (NULL, NULL, "Standard Lua shell is not enabled."); #endif } #else die_with_message (NULL, NULL, "Lua shells are not enabled."); #endif }
int ReadCGIPOSTValues (list_t * env) { size_t content_length = 0; size_t max_len; size_t i, j, x; sliding_buffer_t sbuf; buffer_t token; unsigned char *data; const char *CONTENT_LENGTH = "CONTENT_LENGTH"; if ((getenv (CONTENT_LENGTH) == NULL) || (strtoul (getenv (CONTENT_LENGTH), NULL, 10) == 0)) return (0); if (getenv ("CONTENT_TYPE")) { if (strncasecmp (getenv ("CONTENT_TYPE"), "multipart/form-data", 19) == 0) { /* This is a mime request, we need to go to the mime handler */ i = rfc2388_handler (env); return (i); } } s_buffer_init (&sbuf, 32768); sbuf.fh = STDIN; if (getenv (CONTENT_LENGTH)) { sbuf.maxread = strtoul (getenv (CONTENT_LENGTH), NULL, 10); } haserl_buffer_init (&token); /* Allow 2MB content, unless they have a global upload set */ max_len = ((global.uploadkb == 0) ? 2048 : global.uploadkb) *1024; do { /* x is true if this token ends with a matchstr or is at the end of stream */ x = s_buffer_read (&sbuf, "&"); content_length += sbuf.len; if (content_length > max_len) { die_with_message (NULL, NULL, "Attempted to send content larger than allowed limits."); } if ((x == 0) || (token.data)) { buffer_add (&token, (char *) sbuf.segment, sbuf.len); } if (x) { data = sbuf.segment; sbuf.segment[sbuf.len] = '\0'; if (token.data) { /* add the ASCIIZ */ buffer_add (&token, sbuf.segment + sbuf.len, 1); data = token.data; } /* change plusses into spaces */ j = strlen ((char *) data); for (i = 0; i <= j; i++) { if (data[i] == '+') { data[i] = ' '; } } unescape_url ((char *) data); myputenv (env, (char *) data, global.var_prefix); myputenv (env, (char *) data, global.post_prefix); if (token.data) { buffer_reset (&token); } } } while (!sbuf.eof); s_buffer_destroy (&sbuf); buffer_destroy (&token); return (0); }
int main (int argc, char *argv[]) { #ifndef JUST_LUACSHELL token_t *tokenchain = NULL; buffer_t script_text; #endif script_t *scriptchain; int retval = 0; char *filename = NULL; argv_t *av = NULL; char **av2; int command; int count; list_t *env = NULL; assignGlobalStartupValues(); #ifndef JUST_LUACSHELL buffer_init (&script_text); #endif /* if more than argv[1] and argv[1] is not a file */ switch (argc) { case 1: /* we were run, instead of called as a shell script */ puts ("This is " PACKAGE_NAME " version " PACKAGE_VERSION "\n" "This program runs as a cgi interpeter, not interactively\n" "Please see: http://haserl.sourceforge.net"); return (0); break; case 2: filename = argv[1]; break; default: /* more than two */ command = argc_argv (argv[1], &av, ""); /* and we need to add the original argv[0] command for optarg to work */ av2 = xmalloc (sizeof (char *) * (command + 2)); av2[0] = argv[0]; for (count = 0; count < command; count++) { av2[count + 1] = av[count].string; } parseCommandLine (command + 1, av2); argv[1] = av[1].string; free (av); free (av2); filename = argv[2]; break; /* we silently ignore 3,4,etc. */ } scriptchain = load_script (filename, NULL); /* drop permissions */ BecomeUser (scriptchain->uid, scriptchain->gid); /* populate the function pointers based on the shell selected */ if (strcmp(global.shell, "lua") && strcmp(global.shell, "luac")) /* default to "bash" */ { #ifdef INCLUDE_BASHSHELL shell_exec = &bash_exec; shell_echo = &bash_echo; shell_eval = &bash_eval; shell_setup = &bash_setup; shell_doscript = &bash_doscript; shell_destroy = &bash_destroy; #else die_with_message (NULL, NULL, "Bash shell is not enabled."); #endif } else { #ifdef USE_LUA shell_setup = &lua_common_setup; shell_destroy = &lua_common_destroy; global.var_prefix = "FORM."; global.nul_prefix = "ENV."; if(global.shell[3] == 'c') /* compiled Lua specific function ptr... */ #ifdef INCLUDE_LUACSHELL shell_doscript = &luac_doscript; #else die_with_message (NULL, NULL, "Compiled Lua shell is not enabled."); #endif else { #ifdef INCLUDE_LUASHELL shell_exec = &lua_exec; shell_echo = &lua_echo; shell_eval = &lua_eval; shell_doscript = &lua_doscript; #else die_with_message (NULL, NULL, "Standard Lua shell is not enabled."); #endif } #else die_with_message (NULL, NULL, "Lua shells are not enabled."); #endif }