/* slower, but we get clean output */ cStr *read_file(filec_t * file) { register char *p, *s; register int len; cStr *str; if (feof(file->fp)) THROWN((eof_id, "End of file.")) str = fgetstring(file->fp); if (!str) THROWN((eof_id, "End of file.")) /* ok, munch meta-characters */ p = s = string_chars(str); len = string_length(str); while (len-- && *s) { if (ISPRINT(*s)) { *p = *s; p++; } else if (*s == '\t') { *p = ' '; p++; } s++; } *p = '\0'; str->len = p - string_chars(str); return str; }
/* // match the encrypted string, use SHS (default for crypt()) if // 'encrypted' begins with "$2$" (FreeBSD standard); otherwise // pass back to the OS crypt() */ Int match_crypted(cStr * encrypted, cStr * possible) { uChar * ep, * pp, *sp, salt[9]; char p_buf[SHS_OUTPUT_SIZE]; Int sl, el, pl, x; ep = (uChar *) string_chars(encrypted); el = string_length(encrypted); pp = (uChar *) string_chars(possible); pl = string_length(possible); if (el < 3) { cthrow(type_id, "Invalid password format"); return -1; } if (ep[0] == '$' && ep[1] == '2' && ep[2] == '$') { sp = ep + 3; for (x=0; x < 8 && sp[x] != '$'; x++) salt[x] = sp[x]; salt[x] = 0; sp = salt; sl = strlen((char *) sp); shs_crypt((uChar *) pp, pl, sp, sl, p_buf); return (!strcmp((char *) ep, p_buf)); } else { #ifdef USE_OS_CRYPT #ifdef sys_freebsd sp = ep; #else /* assume ancient DES format, with the first two chars as salt */ salt[0] = ep[0]; salt[1] = ep[1]; salt[2] = 0; sp = salt; #endif return (!strcmp((char *) ep, (char *) crypt((char *) pp, (char *) sp))); #else cthrow(type_id, "Driver was not compiled with OS crypt() support."); return -1; #endif } }
// writes the given headers and sets the Content-Length void write_header(int socket_fd, char *head, long content_len) { STRING *header = new_string(255); string_add(header, head); string_add(header, "\nContent-Length: "); char cl[10]; // 100Mb = 104,857,600 bytes snprintf(cl, 10, "%ld", content_len); string_add(header, cl); string_add(header, "\r\n\r\n"); #ifndef SO_NOSIGPIPE send(socket_fd, string_chars(header), header->used_bytes-1, MSG_NOSIGNAL); #else write(socket_fd, string_chars(header), header->used_bytes-1); #endif string_free(header); }
// receives a number, returns the current CPU use void send_cpu_response(struct hitArgs *args, char *path, char *request_body) { char tmp[4]; if (args->form_value_counter==1 && !strncmp(form_name(args, 0), "counter", strlen(form_name(args, 0)))) { STRING *response = new_string(32); string_add(response, "["); for (int p=0; p<max_cpu; p++) { sprintf(tmp, "%d", usages[p]); string_add(response, tmp); if (p < max_cpu-1) { string_add(response, ","); } } string_add(response, "]"); int c = atoi(form_value(args, 0)); if (c > max_cpu) c=0; // TODO: use c if needed ok_200(args, "\nContent-Type: application/json", string_chars(response), path); string_free(response); } else { forbidden_403(args, "Bad request"); } }
cStr *decode(cStr * str) { char *s = string_chars(str), *n = s, h, l; register Int len = string_length(str); for (; len > 0; len--, s++, n++) { switch (*s) { case '+': *n = ' '; break; case '%': h = *++s; l = *++s; len -= 2; *n = tochar(h, l); break; default: *n = *s; } } *n = '\0'; str->len = (n - str->s); return str; }
void pretty_print(env_t *env, VALUE v, int i) { if (VALUE_IS_ERROR(v)) { printf("<error>\n"); } else if (IS_LIST(v)) { printf("(\n"); int j; for (j = 0; j < list_len(v); j++) { indent(i + 1); pretty_print(env, list_get(v, j), i + 1); } indent(i); printf(")\n"); } else { if (VALUE_IS_INT(v)) { printf("%lld\n", INTVAL(v)); } else if (VALUE_IS_BOOL(v)) { printf("#%c\n", BOOLVAL(v) ? 't' : 'f'); } else if (VALUE_IS_NIL(v)) { printf("#nil\n"); } else if (VALUE_IS_IDENT(v)) { printf("%s\n", intern_table_get_str(&env->intern, IDENT(v))); } else if (VALUE_IS_ATOM(v)) { printf(":%s\n", intern_table_get_str(&env->intern, ATOM(v))); } else if (IS_STRING(v)) { printf("\"%s\"\n", string_chars(v)); } else { printf("<unknown %p>\n", v); } } }
/* Look for an object with the given name in the named file and return a callable "<c-function>" object for it. */ obj_t find_c_function(obj_t /* <string> */ symbol, obj_t lookup) { const char *string = string_chars(symbol); struct symtab *syms; int sym_count, i; obj_t retval = obj_False; if (lookup == obj_Unbound) { if (mindy_dynamic_syms == NULL) mindy_dynamic_syms = load_program_file(); return find_c_function(symbol, mindy_dynamic_syms); } else if (lookup == obj_False) return obj_False; else if (!instancep(lookup, obj_ForeignFileClass)) { error("Keyword file: is not a <foreign-file>: %=", lookup); return retval; /* make lint happy */ } else if (instancep(lookup, obj_SharedFileClass)) { shl_t *files = obj_ptr(struct shared_file *, lookup)->handles; int file_count = obj_ptr(struct shared_file *, lookup)->file_count; void *ptr; for (i = 0; i < file_count; i++) if (shl_findsym(&files[i], string, &ptr) == 0) return(make_c_function(make_byte_string(string), ptr)); return retval; } else {
static obj_t file_write_date(obj_t path) { struct stat buf; if (stat(string_chars(path), &buf) < 0) return obj_False; else return make_fixnum(buf.st_mtime); }
static void fd_open(obj_t self, struct thread *thread, obj_t *args) { obj_t path = args[0]; obj_t flags = args[1]; int res; res = mindy_open(string_chars(path), fixnum_value(flags), 0666); results(thread, args-1, res, make_fixnum(res)); }
void send_file_response(struct hitArgs *args, char *path, char *request_body, int path_length) { STRING *response = new_string(1024); string_add(response, "HTTP/1.1 200 OK\n"); string_add(response, "Connection: close\n"); string_add(response, "Content-Type: "); if (!strcmp(path, "") || path_ends_with(path, "index.html")) { string_add(response, "text/html"); write_header(args->socketfd, string_chars(response), index_html_len); write(args->socketfd, index_html, index_html_len); } else if (path_ends_with(path, "code.js")) { string_add(response, "text/javascript"); write_header(args->socketfd, string_chars(response), code_js_len); write(args->socketfd, code_js, code_js_len); } else if (path_ends_with(path, "jquery-2-1-0-min.js")) { string_add(response, "text/javascript"); write_header(args->socketfd, string_chars(response), jquery_2_1_0_min_js_len); write(args->socketfd, jquery_2_1_0_min_js, jquery_2_1_0_min_js_len); } else if (path_ends_with(path, "flot.js")) { string_add(response, "text/javascript"); write_header(args->socketfd, string_chars(response), flot_js_len); write(args->socketfd, flot_js, flot_js_len); } else { notfound_404(args, "no such file"); } string_free(response); // allow socket to drain before closing sleep(1); }
void ok_200(struct hitArgs *args, char *custom_headers, char *html, char *path) { STRING *headers = new_string(255); string_add(headers, "HTTP/1.1 200 OK\nServer: dweb\nCache-Control: no-cache\nPragma: no-cache"); if (custom_headers != NULL) { string_add(headers, custom_headers); } write_html(args->socketfd, string_chars(headers), html); string_free(headers); args->logger_function(LOG, "200 OK", path, args->socketfd); }
/* // Encrypt a string. The salt can be NULL--force SHS encryption, // match_crypted() will handle older DES passwords */ cStr * strcrypt(cStr * key, cStr * salt) { char pwd_buf[SHS_OUTPUT_SIZE]; /* output buffer for the password */ uChar * pp, * sp, rsalt[9]; /* 8 chars of salt, one NULL */ Int x, pl, sl; if (!salt) { random_salt: for (x=0; x < 8; x++) rsalt[x] = ascii64[random_number(64)]; rsalt[8] = 0; sp = rsalt; sl = 8; } else { sp = (uChar *) string_chars(salt); if (sp[0] == '$' && sp[1] == '2' && sp[2] == '$') { sp += 3; for (x=0; x < 8 && sp[x] != '$'; x++) rsalt[x] = sp[x]; rsalt[x] = 0; sp = rsalt; sl = strlen((char *) sp); if (!sl) goto random_salt; } else { sl = string_length(salt); } } pp = (uChar *) string_chars(key); pl = string_length(key); shs_crypt(pp, pl, sp, sl, pwd_buf); return string_from_chars(pwd_buf, strlen(pwd_buf)); }
cStr *encode_full(cStr * in) { register char *s = string_chars(in); cStr *str = string_new(string_length(in)); for (; *s != '\0'; s++) { if (*s == ' ') str = string_addc(str, '+'); else if (*s > ' ' && *s <= '~') { if ((*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z')) str = string_addc(str, *s); else str = string_add_chars(str, tohex(*s), 3); } } return str; }
// receives a number, returns the current CPU temperature void send_temp_response(struct hitArgs *args, char *path, char *request_body) { char tmp[13]; STRING *response = new_string(32); if (temp >= 0) { sprintf(tmp, "%6.2f", temp); } else { sprintf(tmp, "?"); } string_add(response, tmp); ok_200(args, "\nContent-Type: text/plain", string_chars(response), path); string_free(response); }
static void fd_exec(obj_t self, struct thread *thread, obj_t *args) { obj_t *oldargs; oldargs = args - 1; thread->sp = args + 1; { PROCESS_INFORMATION piProcInfo; STARTUPINFO siStartInfo; SECURITY_ATTRIBUTES saAttr; int inpipes[2], outpipes[2]; HANDLE old_handles[2]; const char *command_line = string_chars(args[0]); siStartInfo.cb = sizeof(STARTUPINFO); siStartInfo.lpReserved = NULL; siStartInfo.lpReserved2 = NULL; siStartInfo.cbReserved2 = 0; siStartInfo.lpDesktop = NULL; /* pipe_setup initializes the rest of siStartInfo */ saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); saAttr.bInheritHandle = true; saAttr.lpSecurityDescriptor = NULL; pipe_setup(&siStartInfo, inpipes, outpipes, old_handles); if (! CreateProcess(NULL, command_line, NULL, NULL, true, 0, NULL, NULL, &siStartInfo, &piProcInfo)) { DWORD debug_info = GetLastError(); oldargs[0] = obj_False; oldargs[1] = obj_False; } else { oldargs[0] = make_fixnum(inpipes[1]); /* fd we can write to */ oldargs[1] = make_fixnum(outpipes[0]); /* fd we can read from */ setup_input_checker(outpipes[0]); } pipe_cleanup(inpipes, outpipes, old_handles); } do_return(thread, oldargs, oldargs); }
cStr *encode_partial(cStr * in) { register char *s = string_chars(in); cStr *str = string_new(string_length(in)); for (; *s != '\0'; s++) { if (*s == ' ') str = string_addc(str, '+'); else if (*s > ' ' && *s <= '~') { if ((*s >= '0' && *s <= '9') || (*s >= 'A' && *s <= 'Z') || (*s >= 'a' && *s <= 'z') || memchr(DONT_ESCAPE, *s, DONT_ESCAPE_LEN) != NULL) str = string_addc(str, *s); else str = string_add_chars(str, tohex(*s), 3); } } return str; }
/* Links the named object files for dynamic loading, reads it in, and returns a "foreign_file" object which allows access to its symbols. If names is a non-empty list (of byte-strings), then make ld "undefine" these names so that they will show up in the linked version. */ obj_t load_c_file(obj_t /* list */ c_files, obj_t /* list */ names) { int i; obj_t retval = obj_False; struct shared_file *ret; shl_t handle; retval = alloc(obj_SharedFileClass, sizeof(struct shared_file) + ((length(c_files) - 1) * sizeof(shl_t))); ret = obj_ptr(struct shared_file *, retval); ret->file_count = length(c_files); for (i = 0; c_files != obj_Nil; i++, c_files = TAIL(c_files)) { handle = shl_load(string_chars(HEAD(c_files))); if (handle == NULL) { error("Can't load shared library %s.", HEAD(c_files)); }; ret->handles[i] = handle; ret->file_name = HEAD(c_files); } return retval; }
cStr *html_escape(cStr * in) { register char *s; register int len; cStr *out; s = string_chars(in); len = string_length(in); /* incase they don't need it */ if (!memchr(s, '<', len) && !memchr(s, '>', len) && !memchr(s, '&', len)) return string_dup(in); /* doh, they do.. */ out = string_new(len); for (; *s != '\0'; s++) { switch (*s) { case '<': out = string_add_chars(out, "<", 4); break; case '>': out = string_add_chars(out, ">", 4); break; case '&': out = string_add_chars(out, "&", 5); break; case '\"': /* Added double-quote, Patch #1, Bruce Mitchner */ out = string_add_chars(out, """, 6); break; default: out = string_addc(out, *s); } } return out; }
static void print_shared_foreign_file(obj_t file) { printf("{<shared-file> %s}", string_chars(FOREIGN_FILE(file)->file_name)); }
static void fd_exec(obj_t self, struct thread *thread, obj_t *args) { int inpipes[2], outpipes[2], forkresult; obj_t *oldargs; oldargs = args - 1; thread->sp = args + 1; /* ### Collect some zombie processes before we launch a new process. Ideally, we'd collect them in a more orderly fashion, but this will do for now. */ while (waitpid(-1, NULL, WNOHANG) > 0) ; if (pipe(inpipes) >= 0 && pipe(outpipes) >= 0 && (forkresult = fork()) != -1) { if (forkresult == 0) { /* This process is going to exit shortly, so we needn't be too careful about malloc behavior, nor about the fact that we destructively modify the command string. */ char *command = string_chars(args[0]); char *p, **args; int argcounter = 1; for (p = command; *p != 0; p++) if (*p == ' ') { argcounter++; while (*(++p) == ' '); } args = (char **) calloc(argcounter+1, sizeof(char *)); args[0] = command; for (p = command, argcounter = 1; *p != 0; p++) { if (*p == ' ') { *p = 0; while (*(++p) == ' '); if (*p != 0) args[argcounter++] = p; } } args[argcounter] = 0; close(0); dup(inpipes[0]); close(inpipes[0]); close(inpipes[1]); close(1); dup(outpipes[1]); close(outpipes[0]); close(outpipes[1]); /* Put the child in its own session so that signals don't hit it */ setsid(); execvp(args[0], args); /* If we get here, execvp failed, so shut down as * gracefully as we can */ exit(1); } close(inpipes[0]); close(outpipes[1]); oldargs[0] = make_fixnum(inpipes[1]); oldargs[1] = make_fixnum(outpipes[0]); } else { oldargs[0] = obj_False; oldargs[1] = obj_False; } do_return(thread, oldargs, oldargs); }
void webhit(struct hitArgs *args) { int j; http_verb type; long i, body_size = 0, request_size = 0, body_start, headers_end; char tmp_buf[READ_BUF_LEN+1]; char *body; struct http_header content_length; args->buffer = new_string(READ_BUF_LEN); // we need to read the HTTP headers first... // so loop until we receive "\r\n\r\n" while (get_body_start(string_chars(args->buffer)) < 0 && args->buffer->used_bytes <= MAX_INCOMING_REQUEST) { memset(tmp_buf, 0, READ_BUF_LEN+1); request_size += read(args->socketfd, tmp_buf, READ_BUF_LEN); string_add(args->buffer, tmp_buf); if (tmp_buf[0]==0) break; } if (request_size == 0) { finish_hit(args, 3); return; } content_length = get_header("Content-Length", string_chars(args->buffer)); args->content_length = atoi(content_length.value); body_start = get_body_start(string_chars(args->buffer)); headers_end = body_start-4; if (headers_end > 0) { args->headers = mallocx((int)headers_end+1); strncpy(args->headers, string_chars(args->buffer), headers_end); args->headers[headers_end]=0; } else { args->headers = mallocx(1); args->headers[0] = 0; } if (body_start >= 0) { body_size = request_size - body_start; } // safari seems to send the headers, and then the body slightly later while (body_size < args->content_length && args->buffer->used_bytes <= MAX_INCOMING_REQUEST) { memset(tmp_buf, 0, READ_BUF_LEN+1); i = read(args->socketfd, tmp_buf, READ_BUF_LEN); if (i>0) { request_size += i; string_add(args->buffer, tmp_buf); body_size = request_size - body_start; } else { // stop looping if we cannot read any more bytes break; } } if (request_size <= 0) { // cannot read request, so we'll stop forbidden_403(args, "failed to read http request"); finish_hit(args, 3); return; } args->logger_function(LOG, "request", string_chars(args->buffer), args->hit); if (type = request_type(string_chars(args->buffer)), type == HTTP_NOT_SUPPORTED) { forbidden_403(args, "Only simple GET and POST operations are supported"); finish_hit(args, 3); return; } // get a pointer to the request body (or NULL if it's not there) body = (type==HTTP_GET) ? NULL : args->buffer->ptr+get_body_start(string_chars(args->buffer)); // the request will be "GET [URL] " or "POST [URL] " followed by other details // we will terminate after the second space, to ignore everything else for (i = (type==HTTP_GET) ? 4 : 5; i < args->buffer->used_bytes; i++) { if (string_chars(args->buffer)[i] == ' ') { string_chars(args->buffer)[i] = 0; // second space, terminate string here break; } } j = (type==HTTP_GET) ? 4 : 5; // check for an absolute directory if (string_chars(args->buffer)[j+1] == '/') { forbidden_403(args, "Sorry, absolute paths are not permitted"); finish_hit(args, 3); return; } for (; j<i-1; j++) { // check for any parent directory use if (string_chars(args->buffer)[j] == '.' && string_chars(args->buffer)[j+1] == '.') { forbidden_403(args, "Sorry, parent paths (..) are not permitted"); finish_hit(args, 3); return; } } struct http_header ctype = get_header("Content-Type", args->headers); j = (int)strlen(ctype.value); if (j > 0) { args->content_type = mallocx(j+1); strncpy(args->content_type, ctype.value, j); if (string_matches_value(args->content_type, "application/x-www-form-urlencoded")) { get_form_values(args, body); } } else { args->content_type = mallocx(1); args->content_type[0] = 0; } // call the "responder function" which has been provided to do the rest args->responder_function(args, string_chars(args->buffer) + ((type==HTTP_GET) ? 5 : 6), body, type); finish_hit(args, 1); }