native/common/jk_util.c (2,005 lines of code) (raw):

/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /*************************************************************************** * Description: Utility functions (mainly configuration) * * Author: Gal Shachor <shachor@il.ibm.com> * * Author: Henri Gomez <hgomez@apache.org> * * Author: Rainer Jung <rjung@apache.org> * ***************************************************************************/ #include "jk_util.h" #include "jk_ajp12_worker.h" #include "jk_ajp13_worker.h" #include "jk_ajp14_worker.h" #include "jk_lb_worker.h" #include "jk_mt.h" #define SYSPROPS_OF_WORKER "sysprops" #define STDERR_OF_WORKER "stderr" #define STDOUT_OF_WORKER "stdout" #define SECRET_OF_WORKER "secret" #define MX_OF_WORKER "mx" #define MS_OF_WORKER "ms" #define CP_OF_WORKER "class_path" #define BRIDGE_OF_WORKER "bridge" #define JVM_OF_WORKER "jvm_lib" #define LIBPATH_OF_WORKER "ld_path" #define CMD_LINE_OF_WORKER "cmd_line" #define NATIVE_LIB_OF_WORKER "native_lib" #define REFERENCE_OF_WORKER "reference" #define HOST_OF_WORKER "host" #define SOURCE_OF_WORKER "source" #define PORT_OF_WORKER "port" #define TYPE_OF_WORKER "type" #define CACHE_OF_WORKER_DEPRECATED "cachesize" #define CACHE_OF_WORKER "connection_pool_size" #define CACHE_OF_WORKER_MIN "connection_pool_minsize" #define CACHE_TIMEOUT_DEPRECATED "cache_timeout" #define CACHE_TIMEOUT_OF_WORKER "connection_pool_timeout" #define CACHE_ACQUIRE_OF_WORKER "connection_acquire_timeout" #define RECOVERY_OPTS_OF_WORKER "recovery_options" #define CONNECT_TIMEOUT_OF_WORKER "connect_timeout" #define PREPOST_TIMEOUT_OF_WORKER "prepost_timeout" #define REPLY_TIMEOUT_OF_WORKER "reply_timeout" #define SOCKET_TIMEOUT_OF_WORKER "socket_timeout" #define SOCKET_CONNECT_TIMEOUT_OF_WORKER "socket_connect_timeout" #define PING_TIMEOUT_OF_WORKER "ping_timeout" #define PING_MODE_OF_WORKER "ping_mode" #define SOCKET_BUFFER_OF_WORKER "socket_buffer" #define SOCKET_KEEPALIVE_OF_WORKER "socket_keepalive" #define CONN_PING_INTERVAL_OF_WORKER "connection_ping_interval" #define RECYCLE_TIMEOUT_DEPRECATED "recycle_timeout" #define LOAD_FACTOR_OF_WORKER "lbfactor" #define DISTANCE_OF_WORKER "distance" #define BALANCED_WORKERS_DEPRECATED "balanced_workers" #define BALANCE_WORKERS "balance_workers" #define STICKY_SESSION "sticky_session" #define STICKY_SESSION_FORCE "sticky_session_force" #define SESSION_COOKIE_OF_WORKER "session_cookie" #define SESSION_PATH_OF_WORKER "session_path" #define SET_SESSION_COOKIE "set_session_cookie" #define SESSION_COOKIE_PATH_OF_WORKER "session_cookie_path" #define LOCAL_WORKER_DEPRECATED "local_worker" #define LOCAL_WORKER_ONLY_DEPRECATED "local_worker_only" #define JVM_ROUTE_OF_WORKER_DEPRECATED "jvm_route" #define ROUTE_OF_WORKER "route" #define DOMAIN_OF_WORKER "domain" #define REDIRECT_OF_WORKER "redirect" #define MOUNT_OF_WORKER "mount" #define METHOD_OF_WORKER "method" #define LOCK_OF_WORKER "lock" #define IS_WORKER_DISABLED_DEPRECATED "disabled" #define IS_WORKER_STOPPED_DEPRECATED "stopped" #define ACTIVATION_OF_WORKER "activation" #define WORKER_RECOVER_TIME "recover_time" #define WORKER_ERROR_ESCALATION_TIME "error_escalation_time" #define MAX_REPLY_TIMEOUTS_OF_WORKER "max_reply_timeouts" #define RETRY_INTERVAL_OF_WORKER "retry_interval" #define BUSY_LIMIT_OF_WORKER "busy_limit" #define WORKER_MAX_PACKET_SIZE "max_packet_size" #define STYLE_SHEET_OF_WORKER "css" #define NAMESPACE_OF_WORKER "ns" #define XML_NAMESPACE_OF_WORKER "xmlns" #define XML_DOCTYPE_OF_WORKER "doctype" #define PROP_PREFIX_OF_WORKER "prefix" #define READ_ONLY_OF_WORKER "read_only" #define USER_OF_WORKER "user" #define USER_CASE_OF_WORKER "user_case_insensitive" #define GOOD_RATING_OF_WORKER "good" #define BAD_RATING_OF_WORKER "bad" #define PREFER_IPV6_ADDRESS "prefer_ipv6" #define DEFAULT_WORKER_TYPE JK_AJP13_WORKER_NAME #define SECRET_KEY_OF_WORKER "secretkey" #define RETRIES_OF_WORKER "retries" #define LB_RETRIES_OF_WORKER "lb_retries" #define STATUS_FAIL_OF_WORKER "fail_on_status" #define DEFAULT_WORKER JK_AJP13_WORKER_NAME #define WORKER_LIST_PROPERTY_NAME "worker.list" #define LIST_PROPERTY_NAME "list" #define WORKER_MAINTAIN_PROPERTY_NAME "worker.maintain" #define MAINTAIN_PROPERTY_NAME "maintain" #define DEFAULT_MAINTAIN_TIME 60 #define DEFAULT_LB_FACTOR 1 #define DEFAULT_DISTANCE 0 #define TOMCAT32_BRIDGE_NAME "tomcat32" #define TOMCAT33_BRIDGE_NAME "tomcat33" #define TOMCAT40_BRIDGE_NAME "tomcat40" #define TOMCAT41_BRIDGE_NAME "tomcat41" #define TOMCAT50_BRIDGE_NAME "tomcat5" #define LOG_BUFFER_SIZE 1024 /* * Our longest worker attribute name is below 30 bytes. * Add space for "worker.", another ".", the * worker name and the final '\0'. */ #define JK_MAX_ATTRIBUTE_NAME_LEN (30) #define PARAM_BUFFER_SIZE (JK_MAX_NAME_LEN + 8 + JK_MAX_ATTRIBUTE_NAME_LEN + 1) #define MAKE_WORKER_PARAM(P) \ { \ size_t remain = PARAM_BUFFER_SIZE; \ strcpy(buf, "worker."); remain -= strlen("worker."); \ strncat(buf, wname, remain); remain -= strlen(wname); \ strncat(buf, ".", remain); remain -= 1; \ strncat(buf, P, remain); \ } /* * define the log format, we're using by default the one from error.log * * [Mon Mar 26 19:44:48.123 2001] [jk_uri_worker_map.c (155)]: Into jk_uri_worker_map_t::uri_worker_map_alloc * log format used by apache in error.log */ #define JK_TIME_CONV_MILLI "%Q" #define JK_TIME_CONV_MICRO "%q" #define JK_TIME_PATTERN_MILLI "000" #define JK_TIME_PATTERN_MICRO "000000" #define JK_TIME_FORMAT_NONE "[%a %b %d %H:%M:%S %Y] " #define JK_TIME_FORMAT_MILLI "[%a %b %d %H:%M:%S." JK_TIME_CONV_MILLI " %Y] " #define JK_TIME_FORMAT_MICRO "[%a %b %d %H:%M:%S." JK_TIME_CONV_MICRO " %Y] " #define JK_TIME_SUBSEC_NONE 0 #define JK_TIME_SUBSEC_MILLI 1 #define JK_TIME_SUBSEC_MICRO 2 /* Visual C++ Toolkit 2003 support */ #if defined (_MSC_VER) && (_MSC_VER == 1310) extern long _ftol(double); /* defined by VC6 C libs */ extern long _ftol2(double dblSource) { return _ftol(dblSource); } #endif static const char *list_properties[] = { BALANCE_WORKERS, MOUNT_OF_WORKER, USER_OF_WORKER, GOOD_RATING_OF_WORKER, BAD_RATING_OF_WORKER, STATUS_FAIL_OF_WORKER, LIST_PROPERTY_NAME, NULL }; static const char *unique_properties[] = { SECRET_OF_WORKER, REFERENCE_OF_WORKER, HOST_OF_WORKER, SOURCE_OF_WORKER, PORT_OF_WORKER, TYPE_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, CACHE_OF_WORKER, CACHE_OF_WORKER_MIN, CACHE_TIMEOUT_DEPRECATED, CACHE_TIMEOUT_OF_WORKER, CACHE_ACQUIRE_OF_WORKER, RECOVERY_OPTS_OF_WORKER, CONNECT_TIMEOUT_OF_WORKER, PREPOST_TIMEOUT_OF_WORKER, PING_TIMEOUT_OF_WORKER, PING_MODE_OF_WORKER, REPLY_TIMEOUT_OF_WORKER, SOCKET_TIMEOUT_OF_WORKER, SOCKET_CONNECT_TIMEOUT_OF_WORKER, SOCKET_BUFFER_OF_WORKER, SOCKET_KEEPALIVE_OF_WORKER, CONN_PING_INTERVAL_OF_WORKER, RECYCLE_TIMEOUT_DEPRECATED, LOAD_FACTOR_OF_WORKER, STICKY_SESSION, STICKY_SESSION_FORCE, SESSION_COOKIE_OF_WORKER, SESSION_PATH_OF_WORKER, SET_SESSION_COOKIE, SESSION_COOKIE_PATH_OF_WORKER, LOCAL_WORKER_DEPRECATED, LOCAL_WORKER_ONLY_DEPRECATED, JVM_ROUTE_OF_WORKER_DEPRECATED, ROUTE_OF_WORKER, DOMAIN_OF_WORKER, REDIRECT_OF_WORKER, METHOD_OF_WORKER, LOCK_OF_WORKER, IS_WORKER_DISABLED_DEPRECATED, IS_WORKER_STOPPED_DEPRECATED, ACTIVATION_OF_WORKER, WORKER_RECOVER_TIME, WORKER_ERROR_ESCALATION_TIME, MAX_REPLY_TIMEOUTS_OF_WORKER, RETRY_INTERVAL_OF_WORKER, BUSY_LIMIT_OF_WORKER, WORKER_MAX_PACKET_SIZE, STYLE_SHEET_OF_WORKER, READ_ONLY_OF_WORKER, RETRIES_OF_WORKER, LB_RETRIES_OF_WORKER, WORKER_MAINTAIN_PROPERTY_NAME, NAMESPACE_OF_WORKER, XML_NAMESPACE_OF_WORKER, XML_DOCTYPE_OF_WORKER, PROP_PREFIX_OF_WORKER, USER_CASE_OF_WORKER, PREFER_IPV6_ADDRESS, NULL }; static const char *deprecated_properties[] = { SYSPROPS_OF_WORKER, STDERR_OF_WORKER, STDOUT_OF_WORKER, MX_OF_WORKER, MS_OF_WORKER, CP_OF_WORKER, BRIDGE_OF_WORKER, JVM_OF_WORKER, LIBPATH_OF_WORKER, CMD_LINE_OF_WORKER, NATIVE_LIB_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, CACHE_TIMEOUT_DEPRECATED, RECYCLE_TIMEOUT_DEPRECATED, BALANCED_WORKERS_DEPRECATED, JVM_ROUTE_OF_WORKER_DEPRECATED, LOCAL_WORKER_DEPRECATED, LOCAL_WORKER_ONLY_DEPRECATED, IS_WORKER_DISABLED_DEPRECATED, IS_WORKER_STOPPED_DEPRECATED, NULL }; static const char *supported_properties[] = { SYSPROPS_OF_WORKER, STDERR_OF_WORKER, STDOUT_OF_WORKER, SECRET_OF_WORKER, MX_OF_WORKER, MS_OF_WORKER, CP_OF_WORKER, BRIDGE_OF_WORKER, JVM_OF_WORKER, LIBPATH_OF_WORKER, CMD_LINE_OF_WORKER, NATIVE_LIB_OF_WORKER, REFERENCE_OF_WORKER, HOST_OF_WORKER, SOURCE_OF_WORKER, PORT_OF_WORKER, TYPE_OF_WORKER, CACHE_OF_WORKER_DEPRECATED, CACHE_OF_WORKER, CACHE_OF_WORKER_MIN, CACHE_TIMEOUT_DEPRECATED, CACHE_TIMEOUT_OF_WORKER, CACHE_ACQUIRE_OF_WORKER, RECOVERY_OPTS_OF_WORKER, CONNECT_TIMEOUT_OF_WORKER, PREPOST_TIMEOUT_OF_WORKER, PING_TIMEOUT_OF_WORKER, PING_MODE_OF_WORKER, REPLY_TIMEOUT_OF_WORKER, SOCKET_TIMEOUT_OF_WORKER, SOCKET_CONNECT_TIMEOUT_OF_WORKER, SOCKET_BUFFER_OF_WORKER, SOCKET_KEEPALIVE_OF_WORKER, CONN_PING_INTERVAL_OF_WORKER, RECYCLE_TIMEOUT_DEPRECATED, LOAD_FACTOR_OF_WORKER, DISTANCE_OF_WORKER, BALANCED_WORKERS_DEPRECATED, BALANCE_WORKERS, STICKY_SESSION, STICKY_SESSION_FORCE, SESSION_COOKIE_OF_WORKER, SESSION_PATH_OF_WORKER, SET_SESSION_COOKIE, SESSION_COOKIE_PATH_OF_WORKER, LOCAL_WORKER_DEPRECATED, LOCAL_WORKER_ONLY_DEPRECATED, JVM_ROUTE_OF_WORKER_DEPRECATED, ROUTE_OF_WORKER, DOMAIN_OF_WORKER, REDIRECT_OF_WORKER, MOUNT_OF_WORKER, METHOD_OF_WORKER, LOCK_OF_WORKER, IS_WORKER_DISABLED_DEPRECATED, IS_WORKER_STOPPED_DEPRECATED, ACTIVATION_OF_WORKER, WORKER_RECOVER_TIME, WORKER_ERROR_ESCALATION_TIME, MAX_REPLY_TIMEOUTS_OF_WORKER, RETRY_INTERVAL_OF_WORKER, BUSY_LIMIT_OF_WORKER, WORKER_MAX_PACKET_SIZE, STYLE_SHEET_OF_WORKER, NAMESPACE_OF_WORKER, XML_NAMESPACE_OF_WORKER, XML_DOCTYPE_OF_WORKER, PROP_PREFIX_OF_WORKER, READ_ONLY_OF_WORKER, USER_OF_WORKER, USER_CASE_OF_WORKER, GOOD_RATING_OF_WORKER, BAD_RATING_OF_WORKER, SECRET_KEY_OF_WORKER, RETRIES_OF_WORKER, LB_RETRIES_OF_WORKER, STATUS_FAIL_OF_WORKER, LIST_PROPERTY_NAME, MAINTAIN_PROPERTY_NAME, PREFER_IPV6_ADDRESS, NULL }; static const char *jk_level_verbs[] = { "[" JK_LOG_TRACE_VERB "] ", "[" JK_LOG_DEBUG_VERB "] ", "[" JK_LOG_INFO_VERB "] ", "[" JK_LOG_WARN_VERB "] ", "[" JK_LOG_ERROR_VERB "] ", "[" JK_LOG_EMERG_VERB "] ", NULL }; const char *jk_get_bool(int v) { if (v == 0) return "False"; else return "True"; } int jk_get_bool_code(const char *v, int def) { if (!v) { return def; } if (!strcasecmp(v, "off") || *v == 'F' || *v == 'f' || *v == 'N' || *v == 'n' || (*v == '0' && *(v + 1) == '\0')) { return JK_FALSE; } if (!strcasecmp(v, "on") || *v == 'T' || *v == 't' || *v == 'Y' || *v == 'y' || (*v == '1' && *(v + 1) == '\0')) { return JK_TRUE; } return def; } /* Sleep for 100ms */ void jk_sleep(int ms) { #ifdef OS2 DosSleep(ms); #elif defined(BEOS) snooze(ms * 1000); #elif defined(WIN32) Sleep(ms); #else struct timeval tv; tv.tv_usec = (ms % 1000) * 1000; tv.tv_sec = ms / 1000; select(0, NULL, NULL, NULL, &tv); #endif } /* Replace the first occurence of a sub second time format character * by a series of zero digits with the right precision. * We format our timestamp with strftime, but this can not handle * sub second timestamps. * So we first patch the milliseconds or microseconds literally into * the format string, and then pass it on the strftime. * In order to do that efficiently, we prepare a format string, that * already has placeholder digits for the sub second time stamp * and we save the position and time precision of this placeholder. */ void jk_set_time_fmt(jk_logger_t *l, const char *jk_log_fmt) { if (l) { char *s; if (!jk_log_fmt) { #ifndef NO_GETTIMEOFDAY jk_log_fmt = JK_TIME_FORMAT_MILLI; #else jk_log_fmt = JK_TIME_FORMAT_NONE; #endif } l->log_fmt_type = JK_TIME_SUBSEC_NONE; l->log_fmt_offset = 0; l->log_fmt_size = 0; l->log_fmt = jk_log_fmt; /* Look for the first occurence of JK_TIME_CONV_MILLI */ if ((s = strstr(jk_log_fmt, JK_TIME_CONV_MILLI))) { size_t offset = s - jk_log_fmt; size_t len = strlen(JK_TIME_PATTERN_MILLI); /* If we don't have enough space in our fixed-length char array, * we simply stick to the default format, ignoring JK_TIME_CONV_MILLI. * Otherwise we replace the first occurence of * JK_TIME_CONV_MILLI by JK_TIME_PATTERN_MILLI. */ if (offset + len < JK_TIME_MAX_SIZE) { l->log_fmt_type = JK_TIME_SUBSEC_MILLI; l->log_fmt_offset = offset; memcpy(l->log_fmt_subsec, jk_log_fmt, offset); memcpy(l->log_fmt_subsec + offset, JK_TIME_PATTERN_MILLI, len); memcpy(l->log_fmt_subsec + offset + len, s + strlen(JK_TIME_CONV_MILLI), JK_TIME_MAX_SIZE - offset - len - 1); /* Now we put a stop mark into the string to make it's length * at most JK_TIME_MAX_SIZE-1 plus terminating '\0'. */ l->log_fmt_subsec[JK_TIME_MAX_SIZE - 1] = '\0'; l->log_fmt_size = strlen(l->log_fmt_subsec); } } /* Look for the first occurence of JK_TIME_CONV_MICRO */ else if ((s = strstr(jk_log_fmt, JK_TIME_CONV_MICRO))) { size_t offset = s - jk_log_fmt; size_t len = strlen(JK_TIME_PATTERN_MICRO); /* If we don't have enough space in our fixed-length char array, * we simply stick to the default format, ignoring JK_TIME_CONV_MICRO. * Otherwise we replace the first occurence of JK_TIME_CONV_MICRO * by JK_TIME_PATTERN_MICRO. */ if (offset + len < JK_TIME_MAX_SIZE) { l->log_fmt_type = JK_TIME_SUBSEC_MICRO; l->log_fmt_offset = offset; memcpy(l->log_fmt_subsec, jk_log_fmt, offset); memcpy(l->log_fmt_subsec + offset, JK_TIME_PATTERN_MICRO, len); memcpy(l->log_fmt_subsec + offset + len, s + strlen(JK_TIME_CONV_MICRO), JK_TIME_MAX_SIZE - offset - len - 1); /* Now we put a stop mark into the string to make it's length * at most JK_TIME_MAX_SIZE-1 plus terminating '\0'. */ l->log_fmt_subsec[JK_TIME_MAX_SIZE - 1] = '\0'; l->log_fmt_size = strlen(l->log_fmt_subsec); } } } } static int set_time_str(char *str, int len, jk_logger_t *l) { time_t t; struct tm *tms; #ifdef _MT_CODE_PTHREAD struct tm res; #endif int done; /* We want to use a fixed maximum size buffer here. * If we would dynamically adjust it to the real format * string length, we could support longer format strings, * but we would have to allocate and free for each log line. */ char log_fmt[JK_TIME_MAX_SIZE]; if (!l || !l->log_fmt) { return 0; } log_fmt[0] = '\0'; #ifndef NO_GETTIMEOFDAY if (l->log_fmt_type != JK_TIME_SUBSEC_NONE) { struct timeval tv; int rc = 0; #ifdef WIN32 gettimeofday(&tv, NULL); #else rc = gettimeofday(&tv, NULL); #endif if (rc == 0) { /* We need this subsec buffer, because we convert * the integer with sprintf(), but we don't * want to write the terminating '\0' into our * final log format string. */ char subsec[7]; t = tv.tv_sec; strncpy(log_fmt, l->log_fmt_subsec, l->log_fmt_size + 1); if (l->log_fmt_type == JK_TIME_SUBSEC_MILLI) { sprintf(subsec, "%03d", (int)(tv.tv_usec/1000)); strncpy(log_fmt + l->log_fmt_offset, subsec, 3); } else if (l->log_fmt_type == JK_TIME_SUBSEC_MICRO) { sprintf(subsec, "%06d", (int)(tv.tv_usec)); strncpy(log_fmt + l->log_fmt_offset, subsec, 6); } } else { t = time(NULL); } } else { t = time(NULL); } #else t = time(NULL); #endif #ifdef _MT_CODE_PTHREAD tms = localtime_r(&t, &res); #else tms = localtime(&t); #endif if (log_fmt[0]) done = (int)strftime(str, len, log_fmt, tms); else done = (int)strftime(str, len, l->log_fmt, tms); return done; } static int JK_METHOD log_to_file(jk_logger_t *l, int level, int used, char *what) { if (l && (l->level <= level || level == JK_LOG_REQUEST_LEVEL) && l->logger_private && what) { jk_file_logger_t *p = l->logger_private; if (p->logfile) { what[used++] = '\n'; what[used] = '\0'; #if defined(JK_LOG_LOCKING) #if defined(WIN32) && defined(_MSC_VER) LockFile((HANDLE)_get_osfhandle(_fileno(p->logfile)), 0, 0, 1, 0); #endif #endif fputs(what, p->logfile); /* [V] Flush the dam' thing! */ fflush(p->logfile); #if defined(JK_LOG_LOCKING) #if defined(WIN32) && defined(_MSC_VER) UnlockFile((HANDLE)_get_osfhandle(_fileno(p->logfile)), 0, 0, 1, 0); #endif #endif } return JK_TRUE; } return JK_FALSE; } int jk_parse_log_level(const char *level) { if (!strcasecmp(level, JK_LOG_TRACE_VERB)) return JK_LOG_TRACE_LEVEL; if (!strcasecmp(level, JK_LOG_DEBUG_VERB)) return JK_LOG_DEBUG_LEVEL; if (!strcasecmp(level, JK_LOG_INFO_VERB)) return JK_LOG_INFO_LEVEL; if (!strcasecmp(level, JK_LOG_WARN_VERB)) return JK_LOG_WARNING_LEVEL; if (!strcasecmp(level, JK_LOG_ERROR_VERB)) return JK_LOG_ERROR_LEVEL; if (!strcasecmp(level, JK_LOG_EMERG_VERB)) return JK_LOG_EMERG_LEVEL; return JK_LOG_DEF_LEVEL; } int jk_open_file_logger(jk_logger_t **l, const char *file, int level) { if (l && file) { jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t)); jk_file_logger_t *p = (jk_file_logger_t *) malloc(sizeof(jk_file_logger_t)); if (rc && p) { rc->log = log_to_file; rc->level = level; rc->logger_private = p; #if defined(AS400) && !defined(AS400_UTF8) p->logfile = fopen(file, "a+, o_ccsid=0"); #elif defined(WIN32) && defined(_MSC_VER) p->logfile = fopen(file, "a+c"); #else p->logfile = fopen(file, "a+"); #endif if (p->logfile) { *l = rc; jk_set_time_fmt(rc, NULL); return JK_TRUE; } } if (rc) { free(rc); } if (p) { free(p); } *l = NULL; } return JK_FALSE; } int jk_attach_file_logger(jk_logger_t **l, int fd, int level) { if (l && fd >= 0) { jk_logger_t *rc = (jk_logger_t *)malloc(sizeof(jk_logger_t)); jk_file_logger_t *p = (jk_file_logger_t *) malloc(sizeof(jk_file_logger_t)); if (rc && p) { rc->log = log_to_file; rc->level = level; rc->logger_private = p; #if defined(AS400) && !defined(AS400_UTF8) p->logfile = fdopen(fd, "a+, o_ccsid=0"); #elif defined(WIN32) && defined(_MSC_VER) p->logfile = fdopen(fd, "a+c"); #else p->logfile = fdopen(fd, "a+"); #endif if (p->logfile) { *l = rc; jk_set_time_fmt(rc, NULL); return JK_TRUE; } } if (rc) { free(rc); } if (p) { free(p); } *l = NULL; } return JK_FALSE; } int jk_close_file_logger(jk_logger_t **l) { if (l && *l) { jk_file_logger_t *p = (*l)->logger_private; if (p) { fflush(p->logfile); fclose(p->logfile); free(p); } free(*l); *l = NULL; return JK_TRUE; } return JK_FALSE; } int jk_log(jk_log_context_t *log_ctx, const char *file, int line, const char *funcname, int level, const char *fmt, ...) { int rc = 0; jk_logger_t *l; /* * Need to reserve space for terminating zero byte * and platform specific line endings added during the call * to the output routing. */ static int usable_size = LOG_BUFFER_SIZE - 3; if (!log_ctx || !(l = log_ctx->logger) || !file || !fmt) { return -1; } if ((l->level <= level) || (level == JK_LOG_REQUEST_LEVEL)) { char buf[LOG_BUFFER_SIZE]; char *f = (char *)(file + strlen(file) - 1); va_list args; int used = 0; while (f != file && '\\' != *f && '/' != *f) { f--; } if (f != file) { f++; } used = set_time_str(buf, usable_size, l); if (line) { /* line==0 only used for request log item */ /* Log [requestid] for all levels except REQUEST. */ const char *context_id; if (log_ctx == NULL) { context_id = "-"; rc = 1; } else if (log_ctx->id == NULL) { context_id = "NO-ID"; rc = 5; } else { context_id = log_ctx->id; rc = (int)strlen(context_id); } if (usable_size - used >= rc + 3) { strncpy(buf + used, "[", 1); used += 1; strncpy(buf + used, context_id, rc); used += rc; strncpy(buf + used, "] ", 2); used += 2; } else { strcpy(buf, "Logging failed in context_id formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; } /* Log [pid:threadid] for all levels except REQUEST. * This information helps to correlate lines from different logs. * Performance is no issue, because with production log levels * we only call it often, if we have a lot of errors */ rc = snprintf(buf + used, usable_size - used, "[%" JK_PID_T_FMT ":%" JK_PTHREAD_T_FMT "] ", getpid(), jk_gettid()); used += rc; if (rc < 0) { strcpy(buf, "Logging failed in pid/tid formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; } rc = (int)strlen(jk_level_verbs[level]); if (usable_size - used >= rc) { strncpy(buf + used, jk_level_verbs[level], rc); used += rc; } else { strcpy(buf, "Logging failed in log level formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } if (funcname) { rc = (int)strlen(funcname); if (usable_size - used >= rc + 2) { strncpy(buf + used, funcname, rc); used += rc; strncpy(buf + used, "::", 2); used += 2; } else { strcpy(buf, "Logging failed in function name formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } } rc = (int)strlen(f); if (usable_size - used >= rc) { strncpy(buf + used, f, rc); used += rc; } else { strcpy(buf, "Logging failed in source file name formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } rc = snprintf(buf + used, usable_size - used, " (%d): ", line); used += rc; if (rc < 0 || usable_size - used < 0) { strcpy(buf, "Logging failed in line number formatting"); l->log(l, level, (int)strlen(buf), buf); return 0; /* [V] not sure what to return... */ } } va_start(args, fmt); rc = vsnprintf(buf + used, usable_size - used, fmt, args); va_end(args); /* Depending on the snprintf implementation used, * "rc == usable_size - used" can indicate not enough space in buffer */ if (rc < usable_size - used) { used += rc; } else { used = usable_size; buf[used - 1] = '.'; buf[used - 2] = '.'; buf[used - 3] = '.'; } l->log(l, level, used, buf); } return rc; } const char *jk_get_worker_type(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(TYPE_OF_WORKER); return jk_map_get_string(m, buf, DEFAULT_WORKER_TYPE); } const char *jk_get_worker_route(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(ROUTE_OF_WORKER); v = jk_map_get_string(m, buf, def); if (v) { return v; } /* Try old jvm_route directive */ MAKE_WORKER_PARAM(JVM_ROUTE_OF_WORKER_DEPRECATED); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_domain(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(DOMAIN_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_redirect(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(REDIRECT_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_secret(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SECRET_OF_WORKER); return jk_map_get_string(m, buf, NULL); } const char *jk_get_worker_host(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(HOST_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_source(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SOURCE_OF_WORKER); return jk_map_get_string(m, buf, def); } int jk_get_worker_port(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PORT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_prefer_ipv6(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PREFER_IPV6_ADDRESS); return jk_map_get_bool(m, buf, def); } static int def_cache_size = -1; int jk_get_worker_def_cache_size(int protocol) { if (def_cache_size < 1) { if (protocol == AJP14_PROTO) def_cache_size = AJP14_DEF_CACHE_SZ; else def_cache_size = AJP13_DEF_CACHE_SZ; } return def_cache_size; } void jk_set_worker_def_cache_size(int sz) { def_cache_size = sz; } int jk_get_worker_cache_size(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int rv; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_OF_WORKER); if ((rv = jk_map_get_int(m, buf, -1)) >= 0) return rv; MAKE_WORKER_PARAM(CACHE_OF_WORKER_DEPRECATED); return jk_map_get_int(m, buf, def); } int jk_get_worker_cache_size_min(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_OF_WORKER_MIN); return jk_map_get_int(m, buf, def); } int jk_get_worker_cache_acquire_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_ACQUIRE_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_socket_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_socket_connect_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_CONNECT_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_recover_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(WORKER_RECOVER_TIME); return jk_map_get_int(m, buf, def); } int jk_get_worker_error_escalation_time(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(WORKER_ERROR_ESCALATION_TIME); return jk_map_get_int(m, buf, def); } int jk_get_worker_max_reply_timeouts(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(MAX_REPLY_TIMEOUTS_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_retry_interval(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(RETRY_INTERVAL_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_busy_limit(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(BUSY_LIMIT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_socket_buffer(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int i; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_BUFFER_OF_WORKER); i = jk_map_get_int(m, buf, 0); if (i > 0 && i < def) i = def; return i; } int jk_get_worker_socket_keepalive(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(SOCKET_KEEPALIVE_OF_WORKER); return jk_map_get_bool(m, buf, def); } int jk_get_worker_conn_ping_interval(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CONN_PING_INTERVAL_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_cache_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int rv; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CACHE_TIMEOUT_OF_WORKER); if ((rv = jk_map_get_int(m, buf, -1)) >= 0) return rv; MAKE_WORKER_PARAM(CACHE_TIMEOUT_DEPRECATED); return jk_map_get_int(m, buf, def); } int jk_get_worker_connect_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(CONNECT_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_prepost_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PREPOST_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_ping_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PING_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_ping_mode(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; char mode[100]; const char *v; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PING_MODE_OF_WORKER); jk_ajp_get_cping_text(def, mode); v = jk_map_get_string(m, buf, mode); return jk_ajp_get_cping_mode(v, def); } int jk_get_worker_reply_timeout(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(REPLY_TIMEOUT_OF_WORKER); return jk_map_get_int(m, buf, def); } int jk_get_worker_recycle_timeout(jk_map_t *m, const char *wname, int def) { return def; } int jk_get_worker_retries(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; int rv; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(RETRIES_OF_WORKER); rv = jk_map_get_int(m, buf, def); if (rv < 1) rv = 1; return rv; } int jk_get_worker_lb_retries(jk_map_t *m, const char *wname, int def) { char buf[1024]; int rv; if (!m || !wname) { return -1; } MAKE_WORKER_PARAM(LB_RETRIES_OF_WORKER); rv = jk_map_get_int(m, buf, def); if (rv < 1) rv = 1; return rv; } int jk_get_worker_recovery_opts(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(RECOVERY_OPTS_OF_WORKER); return jk_map_get_int(m, buf, def); } const char *jk_get_worker_secret_key(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SECRET_KEY_OF_WORKER); return jk_map_get_string(m, buf, NULL); } int jk_get_worker_list(jk_map_t *m, char ***list, unsigned *num_of_workers) { if (m && list && num_of_workers) { char **ar = jk_map_get_string_list(m, WORKER_LIST_PROPERTY_NAME, num_of_workers, DEFAULT_WORKER); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num_of_workers = 0; } return JK_FALSE; } int jk_get_is_worker_disabled(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(IS_WORKER_DISABLED_DEPRECATED); return jk_map_get_bool(m, buf, def); } return JK_TRUE; } int jk_get_is_worker_stopped(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(IS_WORKER_STOPPED_DEPRECATED); return jk_map_get_bool(m, buf, def); } return JK_TRUE; } int jk_get_worker_activation(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return JK_LB_ACTIVATION_ACTIVE; } MAKE_WORKER_PARAM(ACTIVATION_OF_WORKER); v = jk_map_get_string(m, buf, NULL); if (v) return jk_lb_get_activation_code(v); if (jk_get_is_worker_stopped(m, wname)) return JK_LB_ACTIVATION_STOPPED; if (jk_get_is_worker_disabled(m, wname)) return JK_LB_ACTIVATION_DISABLED; return JK_LB_ACTIVATION_DEF; } int jk_get_lb_factor(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return DEFAULT_LB_FACTOR; } MAKE_WORKER_PARAM(LOAD_FACTOR_OF_WORKER); return jk_map_get_int(m, buf, DEFAULT_LB_FACTOR); } int jk_get_distance(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return DEFAULT_DISTANCE; } MAKE_WORKER_PARAM(DISTANCE_OF_WORKER); return jk_map_get_int(m, buf, DEFAULT_DISTANCE); } int jk_get_is_sticky_session(jk_map_t *m, const char *wname) { int def = JK_TRUE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(STICKY_SESSION); return jk_map_get_bool(m, buf, def); } return def; } int jk_get_is_sticky_session_force(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(STICKY_SESSION_FORCE); return jk_map_get_bool(m, buf, def); } return def; } int jk_get_lb_method(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return JK_LB_METHOD_DEF; } MAKE_WORKER_PARAM(METHOD_OF_WORKER); v = jk_map_get_string(m, buf, JK_LB_METHOD_DEF); return jk_lb_get_method_code(v); } int jk_get_lb_lock(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; const char *v; if (!m || !wname) { return JK_LB_LOCK_DEF; } MAKE_WORKER_PARAM(LOCK_OF_WORKER); v = jk_map_get_string(m, buf, JK_LB_LOCK_DEF); return jk_lb_get_lock_code(v); } int jk_get_max_packet_size(jk_map_t *m, const char *wname) { char buf[PARAM_BUFFER_SIZE]; int sz; if (!m || !wname) { return AJP13_DEF_PACKET_SIZE; } MAKE_WORKER_PARAM(WORKER_MAX_PACKET_SIZE); sz = jk_map_get_int(m, buf, AJP13_DEF_PACKET_SIZE); sz = JK_ALIGN(sz, AJP13_PACKET_SIZE_ALIGN); if (sz < AJP13_DEF_PACKET_SIZE) sz = AJP13_DEF_PACKET_SIZE; else if (sz > AJP13_MAX_PACKET_SIZE) sz = AJP13_MAX_PACKET_SIZE; return sz; } int jk_get_worker_fail_on_status(jk_map_t *m, const char *wname, int **list, unsigned int *list_size) { char buf[PARAM_BUFFER_SIZE]; int *ar; if (!m || !wname || !list || !list_size) { return 0; } MAKE_WORKER_PARAM(STATUS_FAIL_OF_WORKER); ar = jk_map_get_int_list(m, buf, list_size, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *list_size = 0; return JK_FALSE; } int jk_get_worker_user_case_insensitive(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(USER_CASE_OF_WORKER); return jk_map_get_bool(m, buf, def); } return def; } const char *jk_get_worker_style_sheet(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(STYLE_SHEET_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_name_space(jk_map_t *m, const char *wname, const char *def) { const char *rc; char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(NAMESPACE_OF_WORKER); rc = jk_map_get_string(m, buf, def); if (*rc == '-') return ""; else return rc; } const char *jk_get_worker_xmlns(jk_map_t *m, const char *wname, const char *def) { const char *rc; char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(XML_NAMESPACE_OF_WORKER); rc = jk_map_get_string(m, buf, def); if (*rc == '-') return ""; else return rc; } const char *jk_get_worker_xml_doctype(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(XML_DOCTYPE_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_worker_prop_prefix(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return def; } MAKE_WORKER_PARAM(PROP_PREFIX_OF_WORKER); return jk_map_get_string(m, buf, def); } int jk_get_is_read_only(jk_map_t *m, const char *wname) { int def = JK_FALSE; char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(READ_ONLY_OF_WORKER); return jk_map_get_bool(m, buf, def); } return def; } int jk_get_worker_user_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num && wname) { char **ar = NULL; MAKE_WORKER_PARAM(USER_OF_WORKER); ar = jk_map_get_string_list(m, buf, num, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num = 0; } return JK_FALSE; } int jk_get_worker_good_rating(jk_map_t *m, const char *wname, char ***list, unsigned int *num) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num && wname) { char **ar = NULL; MAKE_WORKER_PARAM(GOOD_RATING_OF_WORKER); ar = jk_map_get_string_list(m, buf, num, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num = 0; } return JK_FALSE; } int jk_get_worker_bad_rating(jk_map_t *m, const char *wname, char ***list, unsigned int *num) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num && wname) { char **ar = NULL; MAKE_WORKER_PARAM(BAD_RATING_OF_WORKER); ar = jk_map_get_string_list(m, buf, num, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num = 0; } return JK_FALSE; } int jk_get_lb_worker_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num_of_workers) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num_of_workers && wname) { char **ar = NULL; MAKE_WORKER_PARAM(BALANCE_WORKERS); ar = jk_map_get_string_list(m, buf, num_of_workers, NULL); if (ar) { *list = ar; return JK_TRUE; } /* Try old balanced_workers directive */ MAKE_WORKER_PARAM(BALANCED_WORKERS_DEPRECATED); ar = jk_map_get_string_list(m, buf, num_of_workers, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num_of_workers = 0; } return JK_FALSE; } int jk_get_worker_mount_list(jk_map_t *m, const char *wname, char ***list, unsigned int *num_of_maps) { char buf[PARAM_BUFFER_SIZE]; if (m && list && num_of_maps && wname) { char **ar = NULL; MAKE_WORKER_PARAM(MOUNT_OF_WORKER); ar = jk_map_get_string_list(m, buf, num_of_maps, NULL); if (ar) { *list = ar; return JK_TRUE; } *list = NULL; *num_of_maps = 0; } return JK_FALSE; } int jk_get_worker_maintain_time(jk_map_t *m) { return jk_map_get_int(m, WORKER_MAINTAIN_PROPERTY_NAME, DEFAULT_MAINTAIN_TIME); } int jk_get_worker_mx(jk_map_t *m, const char *wname, unsigned *mx) { char buf[PARAM_BUFFER_SIZE]; if (m && mx && wname) { int i; MAKE_WORKER_PARAM(MX_OF_WORKER); i = jk_map_get_int(m, buf, -1); if (-1 != i) { *mx = (unsigned)i; return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_ms(jk_map_t *m, const char *wname, unsigned *ms) { char buf[PARAM_BUFFER_SIZE]; if (m && ms && wname) { int i; MAKE_WORKER_PARAM(MS_OF_WORKER); i = jk_map_get_int(m, buf, -1); if (-1 != i) { *ms = (unsigned)i; return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_classpath(jk_map_t *m, const char *wname, const char **cp) { char buf[PARAM_BUFFER_SIZE]; if (m && cp && wname) { MAKE_WORKER_PARAM(CP_OF_WORKER); *cp = jk_map_get_string(m, buf, NULL); if (*cp) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_bridge_type(jk_map_t *m, const char *wname, unsigned *bt) { char buf[PARAM_BUFFER_SIZE]; const char *type; if (m && bt && wname) { MAKE_WORKER_PARAM(BRIDGE_OF_WORKER); type = jk_map_get_string(m, buf, NULL); if (type) { if (!strcasecmp(type, TOMCAT32_BRIDGE_NAME)) *bt = TC32_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT33_BRIDGE_NAME)) *bt = TC33_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT40_BRIDGE_NAME)) *bt = TC40_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT41_BRIDGE_NAME)) *bt = TC41_BRIDGE_TYPE; else if (!strcasecmp(type, TOMCAT50_BRIDGE_NAME)) *bt = TC50_BRIDGE_TYPE; return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_jvm_path(jk_map_t *m, const char *wname, const char **vm_path) { char buf[PARAM_BUFFER_SIZE]; if (m && vm_path && wname) { MAKE_WORKER_PARAM(JVM_OF_WORKER); *vm_path = jk_map_get_string(m, buf, NULL); if (*vm_path) { return JK_TRUE; } } return JK_FALSE; } /* [V] This is unused. currently. */ int jk_get_worker_callback_dll(jk_map_t *m, const char *wname, const char **cb_path) { char buf[PARAM_BUFFER_SIZE]; if (m && cb_path && wname) { MAKE_WORKER_PARAM(NATIVE_LIB_OF_WORKER); *cb_path = jk_map_get_string(m, buf, NULL); if (*cb_path) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_cmd_line(jk_map_t *m, const char *wname, const char **cmd_line) { char buf[PARAM_BUFFER_SIZE]; if (m && cmd_line && wname) { MAKE_WORKER_PARAM(CMD_LINE_OF_WORKER); *cmd_line = jk_map_get_string(m, buf, NULL); if (*cmd_line) { return JK_TRUE; } } return JK_FALSE; } int jk_stat(const char *f, struct stat * statbuf) { int rc; /** * i5/OS V5R4 expect filename in ASCII for fopen but required them in EBCDIC for stat() */ #ifdef AS400_UTF8 char *ptr; ptr = (char *)malloc(strlen(f) + 1); jk_ascii2ebcdic((char *)f, ptr); rc = stat(ptr, statbuf); free(ptr); #else rc = stat(f, statbuf); #endif return (rc); } int jk_file_exists(const char *f) { if (f) { struct stat st; if ((0 == jk_stat(f, &st)) && (st.st_mode & S_IFREG)) return JK_TRUE; } return JK_FALSE; } static int jk_is_some_property(const char *prp_name, const char *suffix, const char *sep) { if (prp_name && suffix && sep) { size_t prp_name_len = strlen(prp_name); size_t suffix_len = strlen(suffix); size_t sep_len = strlen(sep); size_t sep_off = sep_len + suffix_len; if (prp_name_len >= sep_off) { if (!strncmp(prp_name + prp_name_len - sep_off, sep, sep_len) && !strncmp(prp_name + prp_name_len - suffix_len, suffix, suffix_len)) { return JK_TRUE; } } } return JK_FALSE; } int jk_is_path_property(const char *prp_name) { return jk_is_some_property(prp_name, "path", "_"); } int jk_is_cmd_line_property(const char *prp_name) { return jk_is_some_property(prp_name, CMD_LINE_OF_WORKER, "."); } int jk_is_list_property(const char *prp_name) { const char **props = &list_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_is_unique_property(const char *prp_name) { const char **props = &unique_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_is_deprecated_property(const char *prp_name) { const char **props = &deprecated_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_check_buffer_size() { const char **props; size_t len = 0; size_t max_len = 0; props = &supported_properties[0]; while (*props) { len = strlen(*props); if (len > max_len) max_len = len; props++; } return JK_MAX_ATTRIBUTE_NAME_LEN - (int)max_len; } /* * Check that property is a valid one (to prevent user typos). * Only property starting with worker. */ int jk_is_valid_property(const char *prp_name) { const char **props; /* Any property not starting with "worker." is "valid". * It is interpreted as the definition of a custom variable. */ if (memcmp(prp_name, "worker.", 7)) return JK_TRUE; props = &supported_properties[0]; while (*props) { if (jk_is_some_property(prp_name, *props, ".")) return JK_TRUE; props++; } return JK_FALSE; } int jk_get_worker_stdout(jk_map_t *m, const char *wname, const char **stdout_name) { char buf[PARAM_BUFFER_SIZE]; if (m && stdout_name && wname) { MAKE_WORKER_PARAM(STDOUT_OF_WORKER); *stdout_name = jk_map_get_string(m, buf, NULL); if (*stdout_name) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_stderr(jk_map_t *m, const char *wname, const char **stderr_name) { char buf[PARAM_BUFFER_SIZE]; if (m && stderr_name && wname) { MAKE_WORKER_PARAM(STDERR_OF_WORKER); *stderr_name = jk_map_get_string(m, buf, NULL); if (*stderr_name) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_sysprops(jk_map_t *m, const char *wname, const char **sysprops) { char buf[PARAM_BUFFER_SIZE]; if (m && sysprops && wname) { MAKE_WORKER_PARAM(SYSPROPS_OF_WORKER); *sysprops = jk_map_get_string(m, buf, NULL); if (*sysprops) { return JK_TRUE; } } return JK_FALSE; } int jk_get_worker_libpath(jk_map_t *m, const char *wname, const char **libpath) { char buf[PARAM_BUFFER_SIZE]; if (m && libpath && wname) { MAKE_WORKER_PARAM(LIBPATH_OF_WORKER); *libpath = jk_map_get_string(m, buf, NULL); if (*libpath) { return JK_TRUE; } } return JK_FALSE; } const char *jk_get_lb_session_cookie(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SESSION_COOKIE_OF_WORKER); return jk_map_get_string(m, buf, def); } const char *jk_get_lb_session_path(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SESSION_PATH_OF_WORKER); return jk_map_get_string(m, buf, def); } int jk_get_lb_set_session_cookie(jk_map_t *m, const char *wname, int def) { char buf[PARAM_BUFFER_SIZE]; if (m && wname) { MAKE_WORKER_PARAM(SET_SESSION_COOKIE); return jk_map_get_bool(m, buf, def); } return def; } const char *jk_get_lb_session_cookie_path(jk_map_t *m, const char *wname, const char *def) { char buf[PARAM_BUFFER_SIZE]; if (!m || !wname) { return NULL; } MAKE_WORKER_PARAM(SESSION_COOKIE_PATH_OF_WORKER); return jk_map_get_string(m, buf, def); } int is_http_status_fail(unsigned int http_status_fail_num, int *http_status_fail, int status) { unsigned int i; int soft_status = -1 * status; for (i = 0; i < http_status_fail_num; i++) { if (http_status_fail[i] == status) return 1; if (http_status_fail[i] == soft_status) return -1; } return 0; } char **jk_parse_sysprops(jk_pool_t *p, const char *sysprops) { char **rc = NULL; #ifdef _MT_CODE_PTHREAD char *lasts; #endif if (p && sysprops) { char *prps = jk_pool_strdup(p, sysprops); if (prps && strlen(prps)) { unsigned num_of_prps; for (num_of_prps = 1; *sysprops; sysprops++) { if ('*' == *sysprops) { num_of_prps++; } } rc = jk_pool_alloc(p, (num_of_prps + 1) * sizeof(char *)); if (rc) { unsigned i = 0; #ifdef _MT_CODE_PTHREAD char *tmp = strtok_r(prps, "*", &lasts); #else char *tmp = strtok(prps, "*"); #endif while (tmp && i < num_of_prps) { rc[i] = tmp; #ifdef _MT_CODE_PTHREAD tmp = strtok_r(NULL, "*", &lasts); #else tmp = strtok(NULL, "*"); #endif i++; } rc[i] = NULL; } } } return rc; } void jk_append_libpath(jk_pool_t *p, const char *libpath) { char *env = NULL; char *current = getenv(PATH_ENV_VARIABLE); if (current) { env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) + strlen(current) + strlen(libpath) + 5); if (env) { sprintf(env, "%s=%s%c%s", PATH_ENV_VARIABLE, libpath, PATH_SEPERATOR, current); } } else { env = jk_pool_alloc(p, strlen(PATH_ENV_VARIABLE) + strlen(libpath) + 5); if (env) { sprintf(env, "%s=%s", PATH_ENV_VARIABLE, libpath); } } if (env) { putenv(env); } } void jk_init_ws_service(jk_ws_service_t *s) { memset(s, 0, sizeof(jk_ws_service_t)); s->server_port = 80; s->ssl_key_size = -1; s->activation = JK_LB_ACTIVATION_TEXT_ACTIVE; s->reco_status = RECO_NONE; s->extension.reply_timeout = -1; s->http_response_status = JK_HTTP_OK; } /* Match = 0, NoMatch = 1, Abort = -1 * Based loosely on sections of wildmat.c by Rich Salz */ int jk_wildchar_match(const char *str, const char *exp, int icase) { int x, y; for (x = 0, y = 0; exp[y]; ++y, ++x) { if (!str[x] && exp[y] != '*') return -1; if (exp[y] == '*') { while (exp[++y] == '*'); if (!exp[y]) return 0; while (str[x]) { int ret; if ((ret = jk_wildchar_match(&str[x++], &exp[y], icase)) != 1) return ret; } return -1; } else if (exp[y] != '?') { if (icase && (tolower(str[x]) != tolower(exp[y]))) return 1; else if (!icase && str[x] != exp[y]) return 1; } } return (str[x] != '\0'); } int jk_servlet_normalize(char *path, jk_log_context_t *log_ctx) { int l, w; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "URI on entering jk_servlet_normalize: [%s]", path); } // This test allows the loops below to start at index 1 rather than 0. if (path[0] != '/') { if (path[0] == '*' && path[1] == '\0') { /* Most likely an "OPTIONS *" request */ return 0; } jk_log(log_ctx, JK_LOG_WARNING, "Uri [%s] does not start with '/'.", path); return JK_NORMALIZE_BAD_PATH; } /* First pass. * Remove path parameters ;foo=bar/ from any path segment */ for (l = 1, w = 1; path[l] != '\0';) { if (path[l] == ';') { l++; while (path[l] != '/' && path[l] != '\0') { l++; } } else path[w++] = path[l++]; } path[w] = '\0'; /* * Second pass. * Collapse ///// sequences to / */ for (l = 1, w = 1; path[l] != '\0';) { if (path[w - 1] == '/' && (path[l] == '/')) { l++; } else path[w++] = path[l++]; } path[w] = '\0'; /* Third pass. * Remove /./ segments * Both leading and trailing segments will be removed. */ for (l = 1, w = 1; path[l] != '\0';) { if (path[l] == '.' && (path[l + 1] == '/' || path[l + 1] == '\0') && (l == 0 || path[l - 1] == '/')) { l++; if (path[l] == '/') { l++; } } else path[w++] = path[l++]; } path[w] = '\0'; /* Fourth pass. * Remove /xx/../ segments * Trailing segments will be removed but leading /../ segments are an error * condition. */ for (l = 1, w = 1; path[l] != '\0';) { if (path[l] == '.' && path[l + 1] == '.' && (path[l + 2] == '/' || path[l + 2] == '\0') && (l == 0 || path[l - 1] == '/')) { // Wind w back to remove the previous segment if (w == 1) { jk_log(log_ctx, JK_LOG_EMERG, "[%s] contains a '/../' sequence that tries to escape above the root.", path); return JK_NORMALIZE_TRAVERSAL; } do { w--; } while (w != 0 && path[w - 1] != '/'); // Move l forward to the next segment l += 2; if (path[l] == '/') { l++; } } else path[w++] = path[l++]; } path[w] = '\0'; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "URI on exiting jk_servlet_normalize: [%s]", path); } return 0; } int jk_strip_session_id(char* path, char* session_name, jk_log_context_t *log_ctx) { char *jsessionid; jsessionid = strstr(path, session_name); if (jsessionid) { int i; int j; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "removing session identifier for non servlet uri [%s]", path); } // Found a session path parameter. // Need to skip at least as many characters as there are in // strip_session_name i = (int) strlen(session_name); j = 0; // Increment i until the first character after the parameter while (jsessionid[i] != '\0' && jsessionid[i] != ';' && jsessionid[i] != '/') { i++; } // Copy until the end while (jsessionid[i] != '\0') { jsessionid[j++] = jsessionid[i++]; } // Terminate jsessionid[j] = '\0'; if (JK_IS_DEBUG_LEVEL(log_ctx)) { jk_log(log_ctx, JK_LOG_DEBUG, "result of removing session identifier for non servlet uri is [%s]", path); } return 1; } return 0; } #ifdef _MT_CODE_PTHREAD jk_pthread_t jk_gettid() { union { pthread_t tid; jk_uint64_t alignme; } u; #ifdef AS400 /* OS400 use 64 bits ThreadId */ pthread_id_np_t tid; #endif /* AS400 */ u.tid = pthread_self(); #ifdef AS400 /* Get only low 32 bits for now */ pthread_getunique_np(&(u.tid), &tid); return ((jk_uint32_t)(tid.intId.lo & 0xFFFFFFFF)); #else return ((jk_pthread_t)u.tid); #endif /* AS400 */ } #endif /*** * ASCII <-> EBCDIC conversions * * For now usefull only in i5/OS V5R4 where UTF and EBCDIC mode are mixed */ #ifdef AS400_UTF8 /* EBCDIC to ASCII translation table */ static u_char ebcdic_to_ascii[256] = { 0x00,0x01,0x02,0x03,0x20,0x09,0x20,0x7f, /* 00-07 */ 0x20,0x20,0x20,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ 0x10,0x11,0x12,0x13,0x20,0x0a,0x08,0x20, /* 10-17 */ 0x18,0x19,0x20,0x20,0x20,0x1d,0x1e,0x1f, /* 18-1f */ 0x20,0x20,0x1c,0x20,0x20,0x0a,0x17,0x1b, /* 20-27 */ 0x20,0x20,0x20,0x20,0x20,0x05,0x06,0x07, /* 28-2f */ 0x20,0x20,0x16,0x20,0x20,0x20,0x20,0x04, /* 30-37 */ 0x20,0x20,0x20,0x20,0x14,0x15,0x20,0x1a, /* 38-3f */ 0x20,0x20,0x83,0x84,0x85,0xa0,0xc6,0x86, /* 40-47 */ 0x87,0xa4,0xbd,0x2e,0x3c,0x28,0x2b,0x7c, /* 48-4f */ 0x26,0x82,0x88,0x89,0x8a,0xa1,0x8c,0x8b, /* 50-57 */ 0x8d,0xe1,0x21,0x24,0x2a,0x29,0x3b,0xaa, /* 58-5f */ 0x2d,0x2f,0xb6,0x8e,0xb7,0xb5,0xc7,0x8f, /* 60-67 */ 0x80,0xa5,0xdd,0x2c,0x25,0x5f,0x3e,0x3f, /* 68-6f */ 0x9b,0x90,0xd2,0xd3,0xd4,0xd6,0xd7,0xd8, /* 70-77 */ 0xde,0x60,0x3a,0x23,0x40,0x27,0x3d,0x22, /* 78-7f */ 0x9d,0x61,0x62,0x63,0x64,0x65,0x66,0x67, /* 80-87 */ 0x68,0x69,0xae,0xaf,0xd0,0xec,0xe7,0xf1, /* 88-8f */ 0xf8,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,0x70, /* 90-97 */ 0x71,0x72,0xa6,0xa7,0x91,0xf7,0x92,0xcf, /* 98-9f */ 0xe6,0x7e,0x73,0x74,0x75,0x76,0x77,0x78, /* a8-a7 */ 0x79,0x7a,0xad,0xa8,0xd1,0xed,0xe8,0xa9, /* a8-af */ 0x5e,0x9c,0xbe,0xfa,0xb8,0x15,0x14,0xac, /* b0-b7 */ 0xab,0xf3,0x5b,0x5d,0xee,0xf9,0xef,0x9e, /* b8-bf */ 0x7b,0x41,0x42,0x43,0x44,0x45,0x46,0x47, /* c0-c7 */ 0x48,0x49,0xf0,0x93,0x94,0x95,0xa2,0xe4, /* c8-cf */ 0x7d,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50, /* d0-d7 */ 0x51,0x52,0xfb,0x96,0x81,0x97,0xa3,0x98, /* d8-df */ 0x5c,0xf6,0x53,0x54,0x55,0x56,0x57,0x58, /* e0-e7 */ 0x59,0x5a,0xfc,0xe2,0x99,0xe3,0xe0,0xe5, /* e8-ef */ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, /* f0-f7 */ 0x38,0x39,0xfd,0xea,0x9a,0xeb,0xe9,0xff /* f8-ff */ }; /* ASCII to EBCDIC translation table */ static u_char ascii_to_ebcdic[256] = { 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, /* 00-07 */ 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, /* 08-0f */ 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, /* 10-17 */ 0x18,0x19,0x3f,0x27,0x22,0x1d,0x1e,0x1f, /* 18-1f */ 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, /* 20-27 */ 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, /* 28-2f */ 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, /* 30-37 */ 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, /* 38-3f */ 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, /* 40-47 */ 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, /* 48-4f */ 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, /* 50-57 */ 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, /* 58-5f */ 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, /* 60-67 */ 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, /* 68-6f */ 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, /* 70-77 */ 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, /* 78-7f */ 0x68,0xdc,0x51,0x42,0x43,0x44,0x47,0x48, /* 80-87 */ 0x52,0x53,0x54,0x57,0x56,0x58,0x63,0x67, /* 88-8f */ 0x71,0x9c,0x9e,0xcb,0xcc,0xcd,0xdb,0xdd, /* 90-97 */ 0xdf,0xec,0xfc,0x70,0xb1,0x80,0xbf,0x40, /* 98-9f */ 0x45,0x55,0xee,0xde,0x49,0x69,0x9a,0x9b, /* a8-a7 */ 0xab,0xaf,0x5f,0xb8,0xb7,0xaa,0x8a,0x8b, /* a8-af */ 0x40,0x40,0x40,0x40,0x40,0x65,0x62,0x64, /* b0-b7 */ 0xb4,0x40,0x40,0x40,0x40,0x4a,0xb2,0x40, /* b8-bf */ 0x40,0x40,0x40,0x40,0x40,0x40,0x46,0x66, /* c0-c7 */ 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x9f, /* c8-cf */ 0x8c,0xac,0x72,0x73,0x74,0x89,0x75,0x76, /* d0-d7 */ 0x77,0x40,0x40,0x40,0x40,0x6a,0x78,0x40, /* d8-df */ 0xee,0x59,0xeb,0xed,0xcf,0xef,0xa0,0x8e, /* e0-e7 */ 0xae,0xfe,0xfb,0xfd,0x8d,0xad,0xbc,0xbe, /* e8-ef */ 0xca,0x8f,0x40,0xb9,0xb6,0xb5,0xe1,0x9d, /* f0-f7 */ 0x90,0xbd,0xb3,0xda,0xea,0xfa,0x40,0x40 /* f8-ff */ }; void jk_ascii2ebcdic(char *src, char *dst) { char c; while ((c = *src++) != 0) { *dst++ = ascii_to_ebcdic[(unsigned int)c]; } *dst = 0; } void jk_ebcdic2ascii(char *src, char *dst) { char c; while ((c = *src++) != 0) { *dst++ = ebcdic_to_ascii[(unsigned int)c]; } *dst = 0; } #endif #if defined (WIN32) static PSECURITY_ATTRIBUTES pNullSA; static SECURITY_ATTRIBUTES stEmptySA; /* To share the objects with other processes, we need a 0 ACL * Code from MS KB Q106387 */ PSECURITY_ATTRIBUTES jk_get_sa_with_null_dacl() { DWORD rc = 0; PSECURITY_DESCRIPTOR pSD; if (pNullSA != NULL) { return pNullSA; } else { stEmptySA.nLength = (DWORD)sizeof(SECURITY_ATTRIBUTES); stEmptySA.lpSecurityDescriptor = 0; } if (!(pNullSA = LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES)))) { rc = GetLastError(); goto cleanup; } pNullSA->nLength = (DWORD)sizeof(SECURITY_ATTRIBUTES); pSD = LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (pSD == 0) { rc = GetLastError(); goto cleanup; } pNullSA->lpSecurityDescriptor = pSD; if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { rc = GetLastError(); goto cleanup; } if (!SetSecurityDescriptorDacl(pSD, TRUE, (PACL)0, FALSE)) { rc = GetLastError(); goto cleanup; } pNullSA->lpSecurityDescriptor = pSD; pNullSA->bInheritHandle = FALSE; SetLastError(0); return pNullSA; cleanup: if (pSD) LocalFree(pSD); if (pNullSA) LocalFree(pNullSA); pNullSA = &stEmptySA; pNullSA->bInheritHandle = FALSE; SetLastError(rc); return pNullSA; } #endif