/** * Compile the file * @return bool */ bool File::compile() { // never works if the path is invalid if (!_path) return false; // is the file already compiled? if (_opcodes) return _opcodes->valid(); // we are going to open the file zend_file_handle fileHandle; // we need the tsrm_ls variable (@todo would it be better if this was a member?) TSRMLS_FETCH(); // open the file if (zend_stream_open(_path, &fileHandle TSRMLS_CC) == FAILURE) return false; // make sure the path name is stored in the handle if (!fileHandle.opened_path) fileHandle.opened_path = estrdup(_path); // we need temporary compiler options CompilerOptions options(ZEND_COMPILE_DEFAULT TSRMLS_CC); // create the opcodes _opcodes = new Opcodes(zend_compile_file(&fileHandle, ZEND_INCLUDE TSRMLS_CC) TSRMLS_CC); // close the file handle zend_destroy_file_handle(&fileHandle TSRMLS_CC); // done return _opcodes->valid(); }
static size_t zend_stream_read(zend_file_handle *file_handle, char *buf, size_t len) /* {{{ */ { if (!zend_stream_is_mmap(file_handle) && file_handle->handle.stream.isatty) { int c = '*'; size_t n; #ifdef NETWARE /* c != 4 check is there as fread of a character in NetWare LibC gives 4 upon ^D character. Ascii value 4 is actually EOT character which is not defined anywhere in the LibC or else we can use instead of hardcoded 4. */ for (n = 0; n < len && (c = zend_stream_getc(file_handle)) != EOF && c != 4 && c != '\n'; ++n) { #else for (n = 0; n < len && (c = zend_stream_getc(file_handle)) != EOF && c != '\n'; ++n) { #endif buf[n] = (char)c; } if (c == '\n') { buf[n++] = (char)c; } return n; } return file_handle->handle.stream.reader(file_handle->handle.stream.handle, buf, len); } /* }}} */ ZEND_API int zend_stream_fixup(zend_file_handle *file_handle, char **buf, size_t *len) /* {{{ */ { size_t size; zend_stream_type old_type; if (file_handle->type == ZEND_HANDLE_FILENAME) { if (zend_stream_open(file_handle->filename, file_handle) == FAILURE) { return FAILURE; } } switch (file_handle->type) { case ZEND_HANDLE_FD: file_handle->type = ZEND_HANDLE_FP; file_handle->handle.fp = fdopen(file_handle->handle.fd, "rb"); /* no break; */ case ZEND_HANDLE_FP: if (!file_handle->handle.fp) { return FAILURE; } memset(&file_handle->handle.stream.mmap, 0, sizeof(zend_mmap)); file_handle->handle.stream.isatty = isatty(fileno((FILE *)file_handle->handle.stream.handle)) ? 1 : 0; file_handle->handle.stream.reader = (zend_stream_reader_t)zend_stream_stdio_reader; file_handle->handle.stream.closer = (zend_stream_closer_t)zend_stream_stdio_closer; file_handle->handle.stream.fsizer = (zend_stream_fsizer_t)zend_stream_stdio_fsizer; memset(&file_handle->handle.stream.mmap, 0, sizeof(file_handle->handle.stream.mmap)); /* no break; */ case ZEND_HANDLE_STREAM: /* nothing to do */ break; case ZEND_HANDLE_MAPPED: file_handle->handle.stream.mmap.pos = 0; *buf = file_handle->handle.stream.mmap.buf; *len = file_handle->handle.stream.mmap.len; return SUCCESS; default: return FAILURE; } size = zend_stream_fsize(file_handle); if (size == (size_t)-1) { return FAILURE; } old_type = file_handle->type; file_handle->type = ZEND_HANDLE_STREAM; /* we might still be _FP but we need fsize() work */ if (old_type == ZEND_HANDLE_FP && !file_handle->handle.stream.isatty && size) { #if HAVE_MMAP size_t page_size = REAL_PAGE_SIZE; if (file_handle->handle.fp && size != 0 && ((size - 1) % page_size) <= page_size - ZEND_MMAP_AHEAD) { /* *buf[size] is zeroed automatically by the kernel */ *buf = mmap(0, size + ZEND_MMAP_AHEAD, PROT_READ, MAP_PRIVATE, fileno(file_handle->handle.fp), 0); if (*buf != MAP_FAILED) { zend_long offset = ftell(file_handle->handle.fp); file_handle->handle.stream.mmap.map = *buf; if (offset != -1) { *buf += offset; size -= offset; } file_handle->handle.stream.mmap.buf = *buf; file_handle->handle.stream.mmap.len = size; goto return_mapped; } } #endif file_handle->handle.stream.mmap.map = 0; file_handle->handle.stream.mmap.buf = *buf = safe_emalloc(1, size, ZEND_MMAP_AHEAD); file_handle->handle.stream.mmap.len = zend_stream_read(file_handle, *buf, size); } else { size_t read, remain = 4*1024; *buf = emalloc(remain); size = 0; while ((read = zend_stream_read(file_handle, *buf + size, remain)) > 0) { size += read; remain -= read; if (remain == 0) { *buf = safe_erealloc(*buf, size, 2, 0); remain = size; } } file_handle->handle.stream.mmap.map = 0; file_handle->handle.stream.mmap.len = size; if (size && remain < ZEND_MMAP_AHEAD) { *buf = safe_erealloc(*buf, size, 1, ZEND_MMAP_AHEAD); } file_handle->handle.stream.mmap.buf = *buf; } if (file_handle->handle.stream.mmap.len == 0) { *buf = erealloc(*buf, ZEND_MMAP_AHEAD); file_handle->handle.stream.mmap.buf = *buf; } if (ZEND_MMAP_AHEAD) { memset(file_handle->handle.stream.mmap.buf + file_handle->handle.stream.mmap.len, 0, ZEND_MMAP_AHEAD); } #if HAVE_MMAP return_mapped: #endif file_handle->type = ZEND_HANDLE_MAPPED; file_handle->handle.stream.mmap.pos = 0; file_handle->handle.stream.mmap.old_handle = file_handle->handle.stream.handle; file_handle->handle.stream.mmap.old_closer = file_handle->handle.stream.closer; file_handle->handle.stream.handle = &file_handle->handle.stream; file_handle->handle.stream.closer = (zend_stream_closer_t)zend_stream_mmap_closer; *buf = file_handle->handle.stream.mmap.buf; *len = file_handle->handle.stream.mmap.len; return SUCCESS; } /* }}} */
/* {{{ php_fopen_primary_script */ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle) { char *path_info; char *filename = NULL; zend_string *resolved_path = NULL; int length; zend_bool orig_display_errors; path_info = SG(request_info).request_uri; #if HAVE_PWD_H if (PG(user_dir) && *PG(user_dir) && path_info && '/' == path_info[0] && '~' == path_info[1]) { char *s = strchr(path_info + 2, '/'); if (s) { /* if there is no path name after the file, do not bother */ char user[32]; /* to try open the directory */ struct passwd *pw; #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) struct passwd pwstruc; long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX); char *pwbuf; if (pwbuflen < 1) { return FAILURE; } pwbuf = emalloc(pwbuflen); #endif length = s - (path_info + 2); if (length > (int)sizeof(user) - 1) { length = sizeof(user) - 1; } memcpy(user, path_info + 2, length); user[length] = '\0'; #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) if (getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw)) { efree(pwbuf); return FAILURE; } #else pw = getpwnam(user); #endif if (pw && pw->pw_dir) { spprintf(&filename, 0, "%s%c%s%c%s", pw->pw_dir, PHP_DIR_SEPARATOR, PG(user_dir), PHP_DIR_SEPARATOR, s + 1); /* Safe */ } else { filename = SG(request_info).path_translated; } #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX) efree(pwbuf); #endif } } else #endif if (PG(doc_root) && path_info && (length = (int)strlen(PG(doc_root))) && IS_ABSOLUTE_PATH(PG(doc_root), length)) { int path_len = (int)strlen(path_info); filename = emalloc(length + path_len + 2); if (filename) { memcpy(filename, PG(doc_root), length); if (!IS_SLASH(filename[length - 1])) { /* length is never 0 */ filename[length++] = PHP_DIR_SEPARATOR; } if (IS_SLASH(path_info[0])) { length--; } strncpy(filename + length, path_info, path_len + 1); } } else { filename = SG(request_info).path_translated; } if (filename) { resolved_path = zend_resolve_path(filename, (int)strlen(filename)); } if (!resolved_path) { if (SG(request_info).path_translated != filename) { if (filename) { efree(filename); } } /* we have to free SG(request_info).path_translated here because * php_destroy_request_info assumes that it will get * freed when the include_names hash is emptied, but * we're not adding it in this case */ if (SG(request_info).path_translated) { efree(SG(request_info).path_translated); SG(request_info).path_translated = NULL; } return FAILURE; } zend_string_release(resolved_path); orig_display_errors = PG(display_errors); PG(display_errors) = 0; if (zend_stream_open(filename, file_handle) == FAILURE) { PG(display_errors) = orig_display_errors; if (SG(request_info).path_translated != filename) { if (filename) { efree(filename); } } if (SG(request_info).path_translated) { efree(SG(request_info).path_translated); SG(request_info).path_translated = NULL; } return FAILURE; } PG(display_errors) = orig_display_errors; if (SG(request_info).path_translated != filename) { if (SG(request_info).path_translated) { efree(SG(request_info).path_translated); } SG(request_info).path_translated = filename; } return SUCCESS; }
PHP_SUHOSIN_API void suhosin_log(int loglevel, char *fmt, ...) { int s, r, i=0, fd; long written, towrite; int getcaller=0; char *wbuf; struct timeval tv; time_t now; struct tm tm; #if defined(AF_UNIX) struct sockaddr_un saun; #endif #ifdef PHP_WIN32 LPTSTR strs[2]; unsigned short etype; DWORD evid; #endif char buf[5000]; char error[5000]; char *ip_address; char *fname; char *alertstring; int lineno; va_list ap; TSRMLS_FETCH(); #if PHP_VERSION_ID >= 50500 getcaller = (loglevel & S_GETCALLER) == S_GETCALLER; #endif /* remove the S_GETCALLER flag */ loglevel = loglevel & ~S_GETCALLER; SDEBUG("(suhosin_log) loglevel: %d log_syslog: %u - log_sapi: %u - log_script: %u", loglevel, SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script)); /* dump core if wanted */ if (SUHOSIN_G(coredump) && loglevel == S_MEMORY) { volatile unsigned int *x = 0; volatile int y = *x; } if (SUHOSIN_G(log_use_x_forwarded_for)) { ip_address = suhosin_getenv("HTTP_X_FORWARDED_FOR", 20 TSRMLS_CC); if (ip_address == NULL) { ip_address = "X-FORWARDED-FOR not set"; } } else { ip_address = suhosin_getenv("REMOTE_ADDR", 11 TSRMLS_CC); if (ip_address == NULL) { ip_address = "REMOTE_ADDR not set"; } } va_start(ap, fmt); ap_php_vsnprintf(error, sizeof(error), fmt, ap); va_end(ap); while (error[i]) { if (error[i] < 32) error[i] = '.'; i++; } if (SUHOSIN_G(simulation)) { alertstring = "ALERT-SIMULATION"; } else { alertstring = "ALERT"; } if (zend_is_executing(TSRMLS_C)) { zend_execute_data *exdata = EG(current_execute_data); if (exdata) { if (getcaller && exdata->prev_execute_data) { lineno = exdata->prev_execute_data->opline->lineno; fname = (char *)exdata->prev_execute_data->op_array->filename; } else { lineno = exdata->opline->lineno; fname = (char *)exdata->op_array->filename; } } else { lineno = zend_get_executed_lineno(TSRMLS_C); fname = (char *)zend_get_executed_filename(TSRMLS_C); } ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s', line %u)", alertstring, error, ip_address, fname, lineno); } else { fname = suhosin_getenv("SCRIPT_FILENAME", 15 TSRMLS_CC); if (fname==NULL) { fname = "unknown"; } ap_php_snprintf(buf, sizeof(buf), "%s - %s (attacker '%s', file '%s')", alertstring, error, ip_address, fname); } /* Syslog-Logging disabled? */ if (((SUHOSIN_G(log_syslog)|S_INTERNAL) & loglevel)==0) { goto log_file; } #if defined(AF_UNIX) ap_php_snprintf(error, sizeof(error), "<%u>suhosin[%u]: %s\n", (unsigned int)(SUHOSIN_G(log_syslog_facility)|SUHOSIN_G(log_syslog_priority)),getpid(),buf); s = socket(AF_UNIX, SOCK_DGRAM, 0); if (s == -1) { goto log_file; } memset(&saun, 0, sizeof(saun)); saun.sun_family = AF_UNIX; strcpy(saun.sun_path, SYSLOG_PATH); /*saun.sun_len = sizeof(saun);*/ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); if (r) { close(s); s = socket(AF_UNIX, SOCK_STREAM, 0); if (s == -1) { goto log_file; } memset(&saun, 0, sizeof(saun)); saun.sun_family = AF_UNIX; strcpy(saun.sun_path, SYSLOG_PATH); /*saun.sun_len = sizeof(saun);*/ r = connect(s, (struct sockaddr *)&saun, sizeof(saun)); if (r) { close(s); goto log_file; } } send(s, error, strlen(error), 0); close(s); #endif #ifdef PHP_WIN32 ap_php_snprintf(error, sizeof(error), "suhosin[%u]: %s", getpid(),buf); switch (SUHOSIN_G(log_syslog_priority)) { /* translate UNIX type into NT type */ case 1: /*LOG_ALERT:*/ etype = EVENTLOG_ERROR_TYPE; break; case 6: /*LOG_INFO:*/ etype = EVENTLOG_INFORMATION_TYPE; break; default: etype = EVENTLOG_WARNING_TYPE; } evid = loglevel; strs[0] = error; /* report the event */ if (log_source == NULL) { log_source = RegisterEventSource(NULL, "Suhosin-" SUHOSIN_EXT_VERSION); } ReportEvent(log_source, etype, (unsigned short) SUHOSIN_G(log_syslog_priority), evid, NULL, 1, 0, strs, NULL); #endif log_file: /* File-Logging disabled? */ if ((SUHOSIN_G(log_file) & loglevel)==0) { goto log_sapi; } if (!SUHOSIN_G(log_filename) || !SUHOSIN_G(log_filename)[0]) { goto log_sapi; } fd = open(SUHOSIN_G(log_filename), O_CREAT|O_APPEND|O_WRONLY, 0640); if (fd == -1) { suhosin_log(S_INTERNAL, "Unable to open logfile: %s", SUHOSIN_G(log_filename)); return; } gettimeofday(&tv, NULL); now = tv.tv_sec; php_gmtime_r(&now, &tm); ap_php_snprintf(error, sizeof(error), "%s %2d %02d:%02d:%02d [%u] %s\n", month_names[tm.tm_mon], tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, getpid(),buf); towrite = strlen(error); wbuf = error; php_flock(fd, LOCK_EX); while (towrite > 0) { written = write(fd, wbuf, towrite); if (written < 0) { break; } towrite -= written; wbuf += written; } php_flock(fd, LOCK_UN); close(fd); log_sapi: /* SAPI Logging activated? */ SDEBUG("(suhosin_log) log_syslog: %u - log_sapi: %u - log_script: %u - log_phpscript: %u", SUHOSIN_G(log_syslog), SUHOSIN_G(log_sapi), SUHOSIN_G(log_script), SUHOSIN_G(log_phpscript)); if (((SUHOSIN_G(log_sapi)|S_INTERNAL) & loglevel)!=0) { #if PHP_VERSION_ID < 50400 sapi_module.log_message(buf); #else sapi_module.log_message(buf TSRMLS_CC); #endif } if ((SUHOSIN_G(log_stdout) & loglevel)!=0) { printf("%s\n", buf); } /*log_script:*/ /* script logging activaed? */ if (((SUHOSIN_G(log_script) & loglevel)!=0) && SUHOSIN_G(log_scriptname)!=NULL) { char cmd[8192], *cmdpos, *bufpos; FILE *in; int space; struct stat st; char *sname = SUHOSIN_G(log_scriptname); while (isspace(*sname)) ++sname; if (*sname == 0) goto log_phpscript; if (VCWD_STAT(sname, &st) < 0) { suhosin_log(S_INTERNAL, "unable to find logging shell script %s - file dropped", sname); goto log_phpscript; } if (access(sname, X_OK|R_OK) < 0) { suhosin_log(S_INTERNAL, "logging shell script %s is not executable - file dropped", sname); goto log_phpscript; } /* TODO: clean up this code to calculate size of output dynamically */ ap_php_snprintf(cmd, sizeof(cmd) - 20, "%s %s \'", sname, loglevel2string(loglevel)); space = sizeof(cmd) - strlen(cmd) - 20; cmdpos = cmd + strlen(cmd); bufpos = buf; if (space <= 1) return; while (space > 2 && *bufpos) { if (*bufpos == '\'') { if (space<=5) break; *cmdpos++ = '\''; *cmdpos++ = '\\'; *cmdpos++ = '\''; *cmdpos++ = '\''; bufpos++; space-=4; } else { *cmdpos++ = *bufpos++; space--; } } *cmdpos++ = '\''; *cmdpos++ = ' '; *cmdpos++ = '2'; *cmdpos++ = '>'; *cmdpos++ = '&'; *cmdpos++ = '1'; *cmdpos = 0; if ((in=VCWD_POPEN(cmd, "r"))==NULL) { suhosin_log(S_INTERNAL, "Unable to execute logging shell script: %s", sname); goto log_phpscript; } /* read and forget the result */ while (1) { int readbytes = fread(cmd, 1, sizeof(cmd), in); if (readbytes<=0) { break; } if (strncmp(cmd, "sh: ", 4) == 0) { /* assume this is an error */ suhosin_log(S_INTERNAL, "Error while executing logging shell script: %s", sname); pclose(in); goto log_phpscript; } } pclose(in); } log_phpscript: if ((SUHOSIN_G(log_phpscript) & loglevel)!=0 && EG(in_execution) && SUHOSIN_G(log_phpscriptname) && SUHOSIN_G(log_phpscriptname)[0]) { zend_file_handle file_handle; zend_op_array *new_op_array; zval *result = NULL; long orig_execution_depth = SUHOSIN_G(execution_depth); #if PHP_VERSION_ID < 50400 zend_bool orig_safe_mode = PG(safe_mode); #endif char *orig_basedir = PG(open_basedir); char *phpscript = SUHOSIN_G(log_phpscriptname); SDEBUG("scriptname %s", SUHOSIN_G(log_phpscriptname)); #ifdef ZEND_ENGINE_2 if (zend_stream_open(phpscript, &file_handle TSRMLS_CC) == SUCCESS) { #else if (zend_open(phpscript, &file_handle) == SUCCESS && ZEND_IS_VALID_FILE_HANDLE(&file_handle)) { file_handle.filename = phpscript; file_handle.free_filename = 0; #endif if (!file_handle.opened_path) { file_handle.opened_path = estrndup(phpscript, strlen(phpscript)); } new_op_array = zend_compile_file(&file_handle, ZEND_REQUIRE TSRMLS_CC); zend_destroy_file_handle(&file_handle TSRMLS_CC); if (new_op_array) { HashTable *active_symbol_table = EG(active_symbol_table); zval *zerror, *zerror_class; if (active_symbol_table == NULL) { active_symbol_table = &EG(symbol_table); } EG(return_value_ptr_ptr) = &result; EG(active_op_array) = new_op_array; MAKE_STD_ZVAL(zerror); MAKE_STD_ZVAL(zerror_class); ZVAL_STRING(zerror, buf, 1); ZVAL_LONG(zerror_class, loglevel); zend_hash_update(active_symbol_table, "SUHOSIN_ERROR", sizeof("SUHOSIN_ERROR"), (void **)&zerror, sizeof(zval *), NULL); zend_hash_update(active_symbol_table, "SUHOSIN_ERRORCLASS", sizeof("SUHOSIN_ERRORCLASS"), (void **)&zerror_class, sizeof(zval *), NULL); SUHOSIN_G(execution_depth) = 0; if (SUHOSIN_G(log_phpscript_is_safe)) { #if PHP_VERSION_ID < 50400 PG(safe_mode) = 0; #endif PG(open_basedir) = NULL; } zend_execute(new_op_array TSRMLS_CC); SUHOSIN_G(execution_depth) = orig_execution_depth; #if PHP_VERSION_ID < 50400 PG(safe_mode) = orig_safe_mode; #endif PG(open_basedir) = orig_basedir; #ifdef ZEND_ENGINE_2 destroy_op_array(new_op_array TSRMLS_CC); #else destroy_op_array(new_op_array); #endif efree(new_op_array); #ifdef ZEND_ENGINE_2 if (!EG(exception)) #endif { if (EG(return_value_ptr_ptr)) { zval_ptr_dtor(EG(return_value_ptr_ptr)); EG(return_value_ptr_ptr) = NULL; } } } else { suhosin_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SUHOSIN_G(log_phpscriptname)); return; } } else { suhosin_log(S_INTERNAL, "Unable to execute logging PHP script: %s", SUHOSIN_G(log_phpscriptname)); return; } } }