示例#1
0
static mbox_req_cfg_t *get_req_conf(request_rec *r)
{
    mbox_req_cfg_t *conf = ap_get_module_config(r->request_config, &mbox_module);
    const char *temp;
    if (conf)
        return conf;

    conf = apr_pcalloc(r->pool, sizeof(*conf));

    temp = ap_strstr_c(r->uri, r->path_info);
    if (temp)
        conf->base_uri = apr_pstrmemdup(r->pool, r->uri, temp - r->uri);
    else
        conf->base_uri = r->uri;

    temp = ap_strstr_c(conf->base_uri, ".mbox");
    /* 7 is length of "/yyyymm" */
    if (temp && temp >= conf->base_uri + 7) {
        conf->base_path = apr_pstrmemdup(r->pool, conf->base_uri,
                                         temp - 7 - conf->base_uri);

        conf->base_name = ap_strrchr_c(conf->base_path, '/') + 1;
    }
    ap_set_module_config(r->request_config, &mbox_module, conf);
    return conf;
}
示例#2
0
static int req_mime_types(lua_State *L)
{
  request_rec *r = CHECK_REQUEST_OBJECT(1);
  apr_pool_t *p = r->connection->base_server->process->pool;
  const char* resource_name = luaL_checkstring(L, 2);
  int set = lua_isnoneornil(L, 3) ? 0 : lua_toboolean(L, 3);
  apr_hash_t *mimes = NULL;
  apr_status_t rc = apr_pool_userdata_get((void**)&mimes, "mod_luaex", p);
  const char* fn, *ext, *fntmp;
  const char* type = NULL;

  if (rc == APR_SUCCESS && mimes)
  {
    if ((fn = ap_strrchr_c(resource_name, '/')) == NULL)
    {
      fn = resource_name;
    }
    else
    {
      ++fn;
    }
    /* Always drop the path leading up to the file name. */

    /* The exception list keeps track of those filename components that
     * are not associated with extensions indicating metadata.
     * The base name is always the first exception (i.e., "txt.html" has
     * a basename of "txt" even though it might look like an extension).
     * Leading dots are considered to be part of the base name (a file named
     * ".png" is likely not a png file but just a hidden file called png).
     */
    fntmp = fn;
    while (*fntmp == '.')
      fntmp++;
    fntmp = ap_strchr_c(fntmp, '.');
    if (fntmp)
    {
      fn = fntmp + 1;
      ext = apr_pstrdup(r->pool, fn);
    }
    else
    {
      ext = apr_pstrdup(r->pool, fn);
      fn += strlen(fn);
    }

    if (set && (type = apr_hash_get(mimes, ext, APR_HASH_KEY_STRING)) != NULL)
    {
      ap_set_content_type(r, (char*) type);
    }
  }
  if (type)
    lua_pushstring(L, type);
  else
    lua_pushnil(L);

  return 1;
}
示例#3
0
static apr_status_t ap_compile_output_filter(ap_filter_t *filter, apr_bucket_brigade *input_brigade) {
  request_rec *request = filter->r;
  if ( ! request->filename) {
    return ap_pass_brigade(filter->next, input_brigade);
  }
  const char       *resource_name;
  compile_config_t *directory_config = (compile_config_t*) ap_get_module_config(request->per_dir_config,        &compile_module);
  compile_config_t *server_config    = (compile_config_t*) ap_get_module_config(request->server->module_config, &compile_module);
  compile_config_t *config           = compile_merge_config(request->pool, server_config, directory_config);
  if (config->use_path_info) {
    resource_name = apr_pstrcat(request->pool, request->filename, request->path_info, NULL);
  } else {
    resource_name = request->filename;
  }
  const char *filename;
        char *extension;
  filename = ap_strrchr_c(resource_name, '/');
  if (filename == NULL) {
    filename = resource_name;
  } else {
    ++ filename;
  }
  extension = ap_getword(request->pool, &filename, '.');
  while (*filename && (extension = ap_getword(request->pool, &filename, '.'))) {
    if (*extension == '\0') {
      continue;
    }
    ap_str_tolower(extension);
    if (config->extension_commands != NULL) {
      const compile_extension_config_t *extension_config = NULL;
      extension_config = (compile_extension_config_t*) apr_hash_get(config->extension_commands, extension, APR_HASH_KEY_STRING);
      if (extension_config != NULL && extension_config->command_line) {
#ifdef _DEBUG
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, request->server, "ap_compile_output_filter('%s')", apr_psprintf(request->pool, extension_config->command_line, resource_name));
#endif
        // TODO: http://svn.apache.org/repos/asf/httpd/httpd/tags/2.2.6/modules/experimental/mod_case_filter.c
        // Collect buckets, save to disk, run command line and tail-insert result
        ap_set_content_type(request, "text/html;charset=utf-8");
        break;
      }
    }
  }
  return ap_pass_brigade(filter->next, input_brigade);
}
示例#4
0
static char *ssl_var_lookup_ssl_cert_dn(apr_pool_t *p, X509_NAME *xsname,
                                        const char *var)
{
    const char *ptr;
    char *result;
    X509_NAME_ENTRY *xsne;
    int i, j, n, idx = 0, raw = 0;
    apr_size_t varlen;

    ptr = ap_strrchr_c(var, '_');
    if (ptr && ptr > var && strcmp(ptr + 1, "RAW") == 0) {
        var = apr_pstrmemdup(p, var, ptr - var);
        raw = 1;
    }
    
    /* if an _N suffix is used, find the Nth attribute of given name */
    ptr = ap_strchr_c(var, '_');
    if (ptr != NULL && strspn(ptr + 1, "0123456789") == strlen(ptr + 1)) {
        idx = atoi(ptr + 1);
        varlen = ptr - var;
    } else {
        varlen = strlen(var);
    }

    result = NULL;

    for (i = 0; ssl_var_lookup_ssl_cert_dn_rec[i].name != NULL; i++) {
        if (strEQn(var, ssl_var_lookup_ssl_cert_dn_rec[i].name, varlen)
            && strlen(ssl_var_lookup_ssl_cert_dn_rec[i].name) == varlen) {
            for (j = 0; j < X509_NAME_entry_count(xsname); j++) {
                xsne = X509_NAME_get_entry(xsname, j);

                n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));

                if (n == ssl_var_lookup_ssl_cert_dn_rec[i].nid && idx-- == 0) {
                    result = modssl_X509_NAME_ENTRY_to_string(p, xsne, raw);
                    break;
                }
            }
            break;
        }
    }
    return result;
}
static const char *start_if_define_extended(cmd_parms * cmd, void *dummy,
                                            const char *arg)
{
    const char *endp;
    char *expr;
    int define;
    int not = 0;

    endp = ap_strrchr_c(arg, '>');
    if (endp == NULL) {
        return (const char *) apr_pstrcat(cmd->pool, cmd->cmd->name,
                                          "> directive missing closing '>'",
                                          NULL);
    }

    expr = apr_pstrndup(cmd->temp_pool, arg, endp - arg);
    if (expr[0] == '!') {
        not = 1;
        expr++;
    }

    define = is_define(cmd, expr);
    if ((!not && define) || (not && !define)) {
        ap_directive_t *parent = NULL;
        ap_directive_t *current = NULL;
        const char *retval;

        retval = ap_build_cont_config(cmd->pool, cmd->temp_pool, cmd,
                                      &current, &parent, "<IfDefineExtended");
        *(ap_directive_t **) dummy = current;
        return retval;
    }
    else {
        *(ap_directive_t **) dummy = NULL;
        return ap_soak_end_container(cmd, "<IfDefineExtended");
    }
}
示例#6
0
static void log_error_core(const char *file, int line, int level,
                           apr_status_t status, const server_rec *s,
                           const conn_rec *c,
                           const request_rec *r, apr_pool_t *pool,
                           const char *fmt, va_list args)
{
    char errstr[MAX_STRING_LEN];
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
    char scratch[MAX_STRING_LEN];
#endif
    apr_size_t len, errstrlen;
    apr_file_t *logf = NULL;
    const char *referer;
    int level_and_mask = level & APLOG_LEVELMASK;

    if (r && r->connection) {
        c = r->connection;
    }

    if (s == NULL) {
        /*
         * If we are doing stderr logging (startup), don't log messages that are
         * above the default server log level unless it is a startup/shutdown
         * notice
         */
        if ((level_and_mask != APLOG_NOTICE)
            && (level_and_mask > ap_default_loglevel)) {
            return;
        }

        logf = stderr_log;
    }
    else if (s->error_log) {
        /*
         * If we are doing normal logging, don't log messages that are
         * above the server log level unless it is a startup/shutdown notice
         */
        if ((level_and_mask != APLOG_NOTICE)
            && (level_and_mask > s->loglevel)) {
            return;
        }

        logf = s->error_log;
    }
#ifdef TPF
    else if (tpf_child) {
        /*
         * If we are doing normal logging, don't log messages that are
         * above the server log level unless it is a startup/shutdown notice
         */
        if ((level_and_mask != APLOG_NOTICE)
            && (level_and_mask > s->loglevel)) {
            return;
        }

        logf = stderr;
    }
#endif /* TPF */
    else {
        /*
         * If we are doing syslog logging, don't log messages that are
         * above the server log level (including a startup/shutdown notice)
         */
        if (level_and_mask > s->loglevel) {
            return;
        }
    }

    if (logf && ((level & APLOG_STARTUP) != APLOG_STARTUP)) {
        errstr[0] = '[';
        ap_recent_ctime(errstr + 1, apr_time_now());
        errstr[1 + APR_CTIME_LEN - 1] = ']';
        errstr[1 + APR_CTIME_LEN    ] = ' ';
        len = 1 + APR_CTIME_LEN + 1;
    } else {
        len = 0;
    }

    if ((level & APLOG_STARTUP) != APLOG_STARTUP) {
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            "[%s] ", priorities[level_and_mask].t_name);
    }

#ifndef TPF
    if (file && level_and_mask == APLOG_DEBUG) {
#if defined(_OSD_POSIX) || defined(WIN32) || defined(__MVS__)
        char tmp[256];
        char *e = strrchr(file, '/');
#ifdef WIN32
        if (!e) {
            e = strrchr(file, '\\');
        }
#endif

        /* In OSD/POSIX, the compiler returns for __FILE__
         * a string like: __FILE__="*POSIX(/usr/include/stdio.h)"
         * (it even returns an absolute path for sources in
         * the current directory). Here we try to strip this
         * down to the basename.
         */
        if (e != NULL && e[1] != '\0') {
            apr_snprintf(tmp, sizeof(tmp), "%s", &e[1]);
            e = &tmp[strlen(tmp)-1];
            if (*e == ')') {
                *e = '\0';
            }
            file = tmp;
        }
#else /* _OSD_POSIX || WIN32 */
        const char *p;
        /* On Unix, __FILE__ may be an absolute path in a
         * VPATH build. */
        if (file[0] == '/' && (p = ap_strrchr_c(file, '/')) != NULL) {
            file = p + 1;
        }
#endif /*_OSD_POSIX || WIN32 */
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            "%s(%d): ", file, line);
    }
#endif /* TPF */

    if (c) {
        /* XXX: TODO: add a method of selecting whether logged client
         * addresses are in dotted quad or resolved form... dotted
         * quad is the most secure, which is why I'm implementing it
         * first. -djg
         */
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            "[client %s] ", c->remote_ip);
    }
    if (status != 0) {
        if (status < APR_OS_START_EAIERR) {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(%d)", status);
        }
        else if (status < APR_OS_START_SYSERR) {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(EAI %d)", status - APR_OS_START_EAIERR);
        }
        else if (status < 100000 + APR_OS_START_SYSERR) {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(OS %d)", status - APR_OS_START_SYSERR);
        }
        else {
            len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                                "(os 0x%08x)", status - APR_OS_START_SYSERR);
        }
        apr_strerror(status, errstr + len, MAX_STRING_LEN - len);
        len += strlen(errstr + len);
        if (MAX_STRING_LEN - len > 2) {
            errstr[len++] = ':';
            errstr[len++] = ' ';
            errstr[len] = '\0';
        }
    }

    errstrlen = len;
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
    if (apr_vsnprintf(scratch, MAX_STRING_LEN - len, fmt, args)) {
        len += ap_escape_errorlog_item(errstr + len, scratch,
                                       MAX_STRING_LEN - len);
    }
#else
    len += apr_vsnprintf(errstr + len, MAX_STRING_LEN - len, fmt, args);
#endif

    if (   r && (referer = apr_table_get(r->headers_in, "Referer"))
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
        && ap_escape_errorlog_item(scratch, referer, MAX_STRING_LEN - len)
#endif
        ) {
        len += apr_snprintf(errstr + len, MAX_STRING_LEN - len,
                            ", referer: %s",
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
                            scratch
#else
                            referer
#endif
                            );
    }

    /* NULL if we are logging to syslog */
    if (logf) {
        /* Truncate for the terminator (as apr_snprintf does) */
        if (len > MAX_STRING_LEN - sizeof(APR_EOL_STR)) {
            len = MAX_STRING_LEN - sizeof(APR_EOL_STR);
        }
        strcpy(errstr + len, APR_EOL_STR);
        apr_file_puts(errstr, logf);
        apr_file_flush(logf);
    }
#ifdef HAVE_SYSLOG
    else {
        syslog(level_and_mask, "%s", errstr);
    }
#endif

    ap_run_error_log(file, line, level, status, s, r, pool, errstr + errstrlen);
}
示例#7
0
文件: unixd.c 项目: pexip/os-apache2
static apr_status_t ap_unix_create_privileged_process(
                              apr_proc_t *newproc, const char *progname,
                              const char * const *args,
                              const char * const *env,
                              apr_procattr_t *attr, ap_unix_identity_t *ugid,
                              apr_pool_t *p)
{
    int i = 0;
    const char **newargs;
    char *newprogname;
    char *execuser, *execgroup;
    const char *argv0;

    if (!ap_unixd_config.suexec_enabled) {
        return apr_proc_create(newproc, progname, args, env, attr, p);
    }

    argv0 = ap_strrchr_c(progname, '/');
    /* Allow suexec's "/" check to succeed */
    if (argv0 != NULL) {
        argv0++;
    }
    else {
        argv0 = progname;
    }


    if (ugid->userdir) {
        execuser = apr_psprintf(p, "~%ld", (long) ugid->uid);
    }
    else {
        execuser = apr_psprintf(p, "%ld", (long) ugid->uid);
    }
    execgroup = apr_psprintf(p, "%ld", (long) ugid->gid);

    if (!execuser || !execgroup) {
        return APR_ENOMEM;
    }

    i = 0;
    while (args[i])
        i++;
    /* allocate space for 4 new args, the input args, and a null terminator */
    newargs = apr_palloc(p, sizeof(char *) * (i + 4));
    newprogname = SUEXEC_BIN;
    newargs[0] = SUEXEC_BIN;
    newargs[1] = execuser;
    newargs[2] = execgroup;
    newargs[3] = apr_pstrdup(p, argv0);

    /*
    ** using a shell to execute suexec makes no sense thus
    ** we force everything to be APR_PROGRAM, and never
    ** APR_SHELLCMD
    */
    if (apr_procattr_cmdtype_set(attr, APR_PROGRAM) != APR_SUCCESS) {
        return APR_EGENERAL;
    }

    i = 1;
    do {
        newargs[i + 3] = args[i];
    } while (args[i++]);

    return apr_proc_create(newproc, newprogname, newargs, env, attr, p);
}
static apr_status_t cache_canonicalise_key(request_rec *r, apr_pool_t* p,
        const char *uri, apr_uri_t *parsed_uri, const char **key)
{
    cache_server_conf *conf;
    char *port_str, *hn, *lcs;
    const char *hostname, *scheme;
    int i;
    const char *path;
    char *querystring;

    if (*key) {
        /*
         * We have been here before during the processing of this request.
         */
        return APR_SUCCESS;
    }

    /*
     * Get the module configuration. We need this for the CacheIgnoreQueryString
     * option below.
     */
    conf = (cache_server_conf *) ap_get_module_config(r->server->module_config,
            &cache_module);

    /*
     * Use the canonical name to improve cache hit rate, but only if this is
     * not a proxy request or if this is a reverse proxy request.
     * We need to handle both cases in the same manner as for the reverse proxy
     * case we have the following situation:
     *
     * If a cached entry is looked up by mod_cache's quick handler r->proxyreq
     * is still unset in the reverse proxy case as it only gets set in the
     * translate name hook (either by ProxyPass or mod_rewrite) which is run
     * after the quick handler hook. This is different to the forward proxy
     * case where it gets set before the quick handler is run (in the
     * post_read_request hook).
     * If a cache entry is created by the CACHE_SAVE filter we always have
     * r->proxyreq set correctly.
     * So we must ensure that in the reverse proxy case we use the same code
     * path and using the canonical name seems to be the right thing to do
     * in the reverse proxy case.
     */
    if (!r->proxyreq || (r->proxyreq == PROXYREQ_REVERSE)) {
        if (conf->base_uri && conf->base_uri->hostname) {
            hostname = conf->base_uri->hostname;
        }
        else {
            /* Use _default_ as the hostname if none present, as in mod_vhost */
            hostname = ap_get_server_name(r);
            if (!hostname) {
                hostname = "_default_";
            }
        }
    }
    else if (parsed_uri->hostname) {
        /* Copy the parsed uri hostname */
        hn = apr_pstrdup(p, parsed_uri->hostname);
        ap_str_tolower(hn);
        /* const work-around */
        hostname = hn;
    }
    else {
        /* We are a proxied request, with no hostname. Unlikely
         * to get very far - but just in case */
        hostname = "_default_";
    }

    /*
     * Copy the scheme, ensuring that it is lower case. If the parsed uri
     * contains no string or if this is not a proxy request get the http
     * scheme for this request. As r->parsed_uri.scheme is not set if this
     * is a reverse proxy request, it is ensured that the cases
     * "no proxy request" and "reverse proxy request" are handled in the same
     * manner (see above why this is needed).
     */
    if (r->proxyreq && parsed_uri->scheme) {
        /* Copy the scheme and lower-case it */
        lcs = apr_pstrdup(p, parsed_uri->scheme);
        ap_str_tolower(lcs);
        /* const work-around */
        scheme = lcs;
    }
    else {
        if (conf->base_uri && conf->base_uri->scheme) {
            scheme = conf->base_uri->scheme;
        }
        else {
            scheme = ap_http_scheme(r);
        }
    }

    /*
     * If this is a proxy request, but not a reverse proxy request (see comment
     * above why these cases must be handled in the same manner), copy the
     * URI's port-string (which may be a service name). If the URI contains
     * no port-string, use apr-util's notion of the default port for that
     * scheme - if available. Otherwise use the port-number of the current
     * server.
     */
    if (r->proxyreq && (r->proxyreq != PROXYREQ_REVERSE)) {
        if (parsed_uri->port_str) {
            port_str = apr_pcalloc(p, strlen(parsed_uri->port_str) + 2);
            port_str[0] = ':';
            for (i = 0; parsed_uri->port_str[i]; i++) {
                port_str[i + 1] = apr_tolower(parsed_uri->port_str[i]);
            }
        }
        else if (apr_uri_port_of_scheme(scheme)) {
            port_str = apr_psprintf(p, ":%u", apr_uri_port_of_scheme(scheme));
        }
        else {
            /* No port string given in the AbsoluteUri, and we have no
             * idea what the default port for the scheme is. Leave it
             * blank and live with the inefficiency of some extra cached
             * entities.
             */
            port_str = "";
        }
    }
    else {
        if (conf->base_uri && conf->base_uri->port_str) {
            port_str = conf->base_uri->port_str;
        }
        else if (conf->base_uri && conf->base_uri->hostname) {
            port_str = "";
        }
        else {
            /* Use the server port */
            port_str = apr_psprintf(p, ":%u", ap_get_server_port(r));
        }
    }

    /*
     * Check if we need to ignore session identifiers in the URL and do so
     * if needed.
     */
    path = uri;
    querystring = parsed_uri->query;
    if (conf->ignore_session_id->nelts) {
        int i;
        char **identifier;

        identifier = (char **) conf->ignore_session_id->elts;
        for (i = 0; i < conf->ignore_session_id->nelts; i++, identifier++) {
            int len;
            const char *param;

            len = strlen(*identifier);
            /*
             * Check that we have a parameter separator in the last segment
             * of the path and that the parameter matches our identifier
             */
            if ((param = ap_strrchr_c(path, ';'))
                    && !strncmp(param + 1, *identifier, len)
                    && (*(param + len + 1) == '=')
                    && !ap_strchr_c(param + len + 2, '/')) {
                path = apr_pstrndup(p, path, param - path);
                continue;
            }
            /*
             * Check if the identifier is in the querystring and cut it out.
             */
            if (querystring) {
                /*
                 * First check if the identifier is at the beginning of the
                 * querystring and followed by a '='
                 */
                if (!strncmp(querystring, *identifier, len)
                        && (*(querystring + len) == '=')) {
                    param = querystring;
                }
                else {
                    char *complete;

                    /*
                     * In order to avoid subkey matching (PR 48401) prepend
                     * identifier with a '&' and append a '='
                     */
                    complete = apr_pstrcat(p, "&", *identifier, "=", NULL);
                    param = strstr(querystring, complete);
                    /* If we found something we are sitting on the '&' */
                    if (param) {
                        param++;
                    }
                }
                if (param) {
                    const char *amp;

                    if (querystring != param) {
                        querystring = apr_pstrndup(p, querystring,
                                param - querystring);
                    }
                    else {
                        querystring = "";
                    }

                    if ((amp = ap_strchr_c(param + len + 1, '&'))) {
                        querystring = apr_pstrcat(p, querystring, amp + 1,
                                NULL);
                    }
                    else {
                        /*
                         * If querystring is not "", then we have the case
                         * that the identifier parameter we removed was the
                         * last one in the original querystring. Hence we have
                         * a trailing '&' which needs to be removed.
                         */
                        if (*querystring) {
                            querystring[strlen(querystring) - 1] = '\0';
                        }
                    }
                }
            }
        }
    }

    /* Key format is a URI, optionally without the query-string */
    if (conf->ignorequerystring) {
        *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
                NULL);
    }
    else {
        *key = apr_pstrcat(p, scheme, "://", hostname, port_str, path, "?",
                querystring, NULL);
    }

    /*
     * Store the key in the request_config for the cache as r->parsed_uri
     * might have changed in the time from our first visit here triggered by the
     * quick handler and our possible second visit triggered by the CACHE_SAVE
     * filter (e.g. r->parsed_uri got unescaped). In this case we would save the
     * resource in the cache under a key where it is never found by the quick
     * handler during following requests.
     */
    ap_log_rerror(
            APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(00698) "cache: Key for entity %s?%s is %s", uri, parsed_uri->query, *key);

    return APR_SUCCESS;
}
示例#9
0
/* 处理安全策略和规则集的指令 */
static int process_security_rule(server_policy_t *sp, ap_directive_t *current,
            ap_directive_t *conftree, apr_pool_t *ptemp)
{
    apr_status_t rv;
    ap_directive_t *newdir;
    apr_array_header_t *secpolicy_config;
    int i;
    char *cmd_name, *bracket;
    const char *endp;
    int container_num, closed_container_num;
    const char **cmd_args;
    ap_directive_t *curr_parent = conftree;  

    /* 处理安全策略的指令 */
    secpolicy_config  = apr_array_make(ptemp, 1, sizeof(char *));
    rv = convert_sec_policy_query(sp->sec_policy->name, &secpolicy_config);
    if (rv != OK) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                     "query security policy %s error", sp->sec_policy->name);
        return DECLINED;
    }

    container_num = 0;
    closed_container_num = 0;
    for (i = 0; i < secpolicy_config->nelts; i ++) {
        cmd_args = (const char **)(secpolicy_config->elts + (secpolicy_config->elt_size * i));
        if (cmd_args) {
            cmd_name = ap_getword_conf(ptemp, cmd_args);
            switch (get_command_type(cmd_name)) {
            case CONTAINER_COMMAND:
                container_num = container_num + 1;
                newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t));
                newdir->filename = sp->name; /* 使用服务器策略名字作为指令文件名 */
                newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1);
                newdir->directive = apr_pstrdup(ptemp, cmd_name);
                newdir->args = apr_pstrdup(ptemp, *cmd_args);
                endp = ap_strrchr_c(newdir->args, '>');
                if (endp == NULL) {
                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s directive missing closing '>'", cmd_name);
                    return DECLINED;
                }
              
                current = ap_add_node(&curr_parent, current, newdir, 1);
                break;
                
            case CLOSED_CONTAINER_COMMAND:
                if (curr_parent == NULL) {
                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "no appear < container");
                    return DECLINED;
                }
                
                closed_container_num = closed_container_num + 1;      
                bracket = cmd_name + strlen(cmd_name) - 1;
                if (*bracket != '>') {
                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s directive missing closing '>'", cmd_name);
                    return DECLINED;
                }

                *bracket = '\0';
                if (strcasecmp(cmd_name + 2, curr_parent->directive + 1) != 0) {
                    ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Expected </%s> but saw %s>", curr_parent->directive + 1, cmd_name + 2);
                    return DECLINED;
                }

                *bracket = '>';
                current = curr_parent;
                curr_parent = curr_parent->parent;
                break;
                
            case SINGLE_COMMAND:
                newdir = (ap_directive_t *)apr_pcalloc(ptemp, sizeof(ap_directive_t));
                newdir->filename = sp->name; /* 使用服务器策略名字作为指令文件名 */
                newdir->line_num = (current == NULL) ? 1 : (current->line_num + 1);
                newdir->directive = apr_pstrdup(ptemp, cmd_name);
                newdir->args = apr_pstrdup(ptemp, *cmd_args);
                current = ap_add_node(&curr_parent, current, newdir, 0);
                break;
                
            default:
                break;
            }
        }
    }

    if (container_num != closed_container_num) {
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "< > container number not equal to </ > container number");
        return DECLINED;
    }

    return OK;
}