Exemple #1
0
int handle_egress(struct __sk_buff *skb)
{
	int ret = 0, nh_off = BPF_LL_OFF + ETH_HLEN;

	if (likely(skb->protocol == __constant_htons(ETH_P_IP)))
		ret = do_redirect(skb, nh_off, 1);
	
	return ret;
}
Exemple #2
0
static int execute(int argc, char *argv[], redirect_map_t *map)
{
    int             status, pid;
    cmd_t           *cmd;

    for (cmd = builtin_cmds; cmd->cmd_name; cmd++) {
        if (!strcmp(cmd->cmd_name, argv[0]))
            break;
    }
    if (cmd->cmd_name) {
        ioenv_t io;

        build_ioenv(map, &io);
        status = builtin_exec(cmd, argc, argv, &io);
        destroy_ioenv(&io);
        cleanup_redirects(map);
        return 0;
    }

    if (!(pid = fork())) {
        if (do_redirect(map) < 0)
            exit(1);

        execve(argv[0], argv, my_envp);
        if (errno == ENOENT) {
            char buf[256];
            snprintf(buf, 255, "/usr/bin/%s", argv[0]);
            execve(buf, argv, my_envp);
            fprintf(stderr, "sh: command not found: %s\n", argv[0]);
        } else
            fprintf(stderr, "sh: exec failed for %s: %s\n",
                    argv[0], strerror(errno));
        exit(1);
    } else {
        if (0 > pid) {
            fprintf(stderr, "sh: fork failed errno = %d\n", errno);
        }
    }

    cleanup_redirects(map);
    int ret = wait(&status);
    if (status == EFAULT) {
        fprintf(stderr, "sh: child process accessed invalid memory\n");
    }

    return ret;
}
Exemple #3
0
static unsigned int
fw_in(unsigned int hooknum,
      struct sk_buff **pskb,
      const struct net_device *in,
      const struct net_device *out,
      int (*okfn)(struct sk_buff *))
{
	int ret = FW_BLOCK;
	u_int16_t redirpt;

	/* Assume worse case: any hook could change packet */
	(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
	if ((*pskb)->ip_summed == CHECKSUM_HW)
		if (skb_checksum_help(*pskb, (out == NULL)))
			return NF_DROP;

	switch (hooknum) {
	case NF_IP_PRE_ROUTING:
		if (fwops->fw_acct_in)
			fwops->fw_acct_in(fwops, PF_INET,
					  (struct net_device *)in,
					  &redirpt, pskb);

		if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
			*pskb = ip_ct_gather_frags(*pskb);

			if (!*pskb)
				return NF_STOLEN;
		}

		ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
				      &redirpt, pskb);
		break;

	case NF_IP_FORWARD:
		/* Connection will only be set if it was
                   demasqueraded: if so, skip forward chain. */
		if ((*pskb)->nfct)
			ret = FW_ACCEPT;
		else ret = fwops->fw_forward(fwops, PF_INET,
					     (struct net_device *)out,
					     &redirpt, pskb);
		break;

	case NF_IP_POST_ROUTING:
		ret = fwops->fw_output(fwops, PF_INET,
				       (struct net_device *)out,
				       &redirpt, pskb);
		if (ret == FW_ACCEPT || ret == FW_SKIP) {
			if (fwops->fw_acct_out)
				fwops->fw_acct_out(fwops, PF_INET,
						   (struct net_device *)out,
						   &redirpt,
						   pskb);

			/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
			if (ip_conntrack_confirm(*pskb) == NF_DROP)
				ret = FW_BLOCK;
		}
		break;
	}

	switch (ret) {
	case FW_REJECT: {
		/* Alexey says:
		 *
		 * Generally, routing is THE FIRST thing to make, when
		 * packet enters IP stack. Before packet is routed you
		 * cannot call any service routines from IP stack.  */
		struct iphdr *iph = (*pskb)->nh.iph;

		if ((*pskb)->dst != NULL
		    || ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
				      (struct net_device *)in) == 0)
			icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
				  0);
		return NF_DROP;
	}

	case FW_ACCEPT:
	case FW_SKIP:
		if (hooknum == NF_IP_PRE_ROUTING) {
			check_for_demasq(pskb);
			check_for_redirect(*pskb);
		} else if (hooknum == NF_IP_POST_ROUTING) {
			check_for_unredirect(*pskb);
			/* Handle ICMP errors from client here */
			if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
			    && (*pskb)->nfct)
				check_for_masq_error(pskb);
		}
		return NF_ACCEPT;

	case FW_MASQUERADE:
		if (hooknum == NF_IP_FORWARD) {
#ifdef CONFIG_IP_VS
			/* check if it is for ip_vs */
			if (check_for_ip_vs_out(pskb, okfn) == NF_STOLEN)
				return NF_STOLEN;
#endif
			return do_masquerade(pskb, out);
		}
		else return NF_ACCEPT;

	case FW_REDIRECT:
		if (hooknum == NF_IP_PRE_ROUTING)
			return do_redirect(*pskb, in, redirpt);
		else return NF_ACCEPT;

	default:
		/* FW_BLOCK */
		return NF_DROP;
	}
}
Exemple #4
0
/*
 * Function Name: validate_session_policy
 * This is the NSAPI directive funtion which gets called for each request
 * It does session validation and policy check for each request.
 * Input: As defined by a SAF
 * Output: As defined by a SAF
 */
NSAPI_PUBLIC int
validate_session_policy(pblock *param, Session *sn, Request *rq) {
    const char *thisfunc = "validate_session_policy()";
    char *dpro_cookie = NULL;
    am_status_t status = AM_SUCCESS;
    int  requestResult = REQ_ABORTED;
    int	 notifResult = REQ_ABORTED;
    const char *ruser = NULL;
    am_map_t env_parameter_map = NULL;
    am_policy_result_t result = AM_POLICY_RESULT_INITIALIZER;
    void *args[] = { (void *)rq };
    char *request_url = NULL;
    char *orig_req = NULL ;
    char *response = NULL;
    char *clf_req = NULL;
    char *server_protocol = NULL;
    void *agent_config = NULL;
    char *logout_url = NULL;
    char *uri_hdr = NULL;
    char *pathInfo_hdr = NULL;
    char *method_hdr = NULL;
    char *method = NULL;
    char *virtHost_hdr = NULL;
    char *query_hdr = NULL;
    char *query = NULL;
    char *protocol = "HTTP";
    const char *clientIP_hdr_name = NULL;
    char *clientIP_hdr = NULL;
    char *clientIP = NULL;
    const char *clientHostname_hdr_name = NULL;
    char *clientHostname_hdr = NULL;
    char *clientHostname = NULL;
    am_status_t cdStatus = AM_FAILURE;

    // check if agent is initialized.
    // if not initialized, then call agent init function
    // This needs to be synchronized as only one time agent
    // initialization needs to be done.

    if(agentInitialized != B_TRUE){
        //Start critical section
        crit_enter(initLock);
        if(agentInitialized != B_TRUE){
            am_web_log_debug("%s: Will call init.", thisfunc);
            init_at_request(); 
            if(agentInitialized != B_TRUE){
                am_web_log_error("%s: Agent is still not intialized",
                                 thisfunc);
                //deny the access
                requestResult =  do_deny(sn, rq, status);
                status = AM_FAILURE;
            } else {
                am_web_log_debug("%s: Agent intialized");
            }
        }
        //end critical section
        crit_exit(initLock);
    }
    if (status == AM_SUCCESS) {
        // Get the agent configuration
        agent_config = am_web_get_agent_configuration();
        // Dump the entire set of request headers
        if (am_web_is_max_debug_on()) {
            char *header_str = pblock_pblock2str(rq->reqpb, NULL);
            am_web_log_max_debug("%s: Headers: %s", thisfunc, header_str);
            system_free(header_str);
        }
    }
    // Get header values
    if (status == AM_SUCCESS) {
        status = get_header_value(rq->reqpb, REQUEST_URI,
                               B_TRUE, &uri_hdr, B_FALSE, NULL);
    }
    if (status == AM_SUCCESS) {
        status = get_header_value(rq->vars, PATH_INFO,
                               B_FALSE, &pathInfo_hdr, B_FALSE, NULL);
    }
    if (status == AM_SUCCESS) {
        status = get_header_value(rq->reqpb, REQUEST_METHOD,
                               B_TRUE, &method_hdr, B_TRUE, &method);
    }
    if (status == AM_SUCCESS) {
        status = get_header_value(rq->headers, "ampxy_host",
                               B_TRUE, &virtHost_hdr, B_FALSE, NULL);
    }
    if (status == AM_SUCCESS) {
        status = get_header_value(rq->reqpb, REQUEST_QUERY,
                               B_FALSE, &query_hdr, B_TRUE, &query);
    }
    if (security_active) {
        protocol = "HTTPS";
    }
    // Get the request URL
    if (status == AM_SUCCESS) {
        if (am_web_is_proxy_override_host_port_set(agent_config) == AM_FALSE) {
            status = am_web_get_request_url(virtHost_hdr, protocol,
                                            NULL, 0, uri_hdr, query,
                                            &request_url, agent_config);
            if(status == AM_SUCCESS) {
                am_web_log_debug("%s: Request_url: %s", thisfunc, request_url);
            } else {
                am_web_log_error("%s: Could not get the request URL. "
                                 "Failed with error: %s.",
                                 thisfunc, am_status_to_string(status));
            }
        }
    }
    if (status == AM_SUCCESS) {
        if (am_web_is_proxy_override_host_port_set(agent_config) == AM_TRUE) {
            const char *agent_host = am_web_get_agent_server_host(agent_config);
            int agent_port = am_web_get_agent_server_port(agent_config);
            if (agent_host != NULL) {
                char *temp = NULL;
                temp = replace_host_port(request_url, agent_host, agent_port,
                                         agent_config);
                if (temp != NULL) {
                    free(request_url);
                    request_url = temp;
                }
            }
            am_web_log_debug("%s: Request_url after overriding "
                             "host and port: %s",
                             thisfunc, request_url);
        }
    }
    if (status == AM_SUCCESS) {
        // Check for magic notification URL
        if (B_TRUE == am_web_is_notification(request_url, agent_config)) {
            am_web_free_memory(request_url);
            am_web_delete_agent_configuration(agent_config);
            if(query != NULL) {
                free(query);
                query = NULL;
            }
            if(method != NULL) {
                free(method);
                method = NULL;
            }
            return REQ_PROCEED;
        }
    }
    // Check if the SSO token is in the cookie header
    if (status == AM_SUCCESS) {
        requestResult = getISCookie(pblock_findval(COOKIE_HDR, rq->headers),
                                    &dpro_cookie, agent_config);
        if (requestResult == REQ_ABORTED) {
            status = AM_FAILURE;
        } else if (dpro_cookie != NULL) {
            am_web_log_debug("%s: SSO token found in cookie header.",
                             thisfunc);
        }
    }
    // Create the environment map
    if( status == AM_SUCCESS) {
        status = am_map_create(&env_parameter_map);
        if( status != AM_SUCCESS) {
            am_web_log_error("%s: Unable to create map, status = %s (%d)",
                   thisfunc, am_status_to_string(status), status);
        }
    }    
    // If there is a proxy in front of the agent, the user can set in the
    // properties file the name of the headers that the proxy uses to set
    // the real client IP and host name. In that case the agent needs
    // to use the value of these headers to process the request
    //
    // Get the client IP address header set by the proxy, if there is one
    if (status == AM_SUCCESS) {
        clientIP_hdr_name = am_web_get_client_ip_header_name(agent_config);
        if (clientIP_hdr_name != NULL) {
            status = get_header_value(rq->headers, clientIP_hdr_name,
                                    B_FALSE, &clientIP_hdr,
                                    B_FALSE, NULL);
        }
    }
    // Get the client host name header set by the proxy, if there is one
    if (status == AM_SUCCESS) {
        clientHostname_hdr_name = 
               am_web_get_client_hostname_header_name(agent_config);
        if (clientHostname_hdr_name != NULL) {
            status = get_header_value(rq->headers, clientHostname_hdr_name,
                                    B_FALSE, &clientHostname_hdr,
                                    B_FALSE, NULL);
        }
    }
    // If the client IP and host name headers contain more than one
    // value, take the first value.
    if (status == AM_SUCCESS) {
        if ((clientIP_hdr != NULL) || (clientHostname_hdr != NULL)) {
            status = am_web_get_client_ip_host(clientIP_hdr,
                                               clientHostname_hdr,
                                               &clientIP, &clientHostname);
        }
    }
    // Set the IP address and host name in the environment map
    if ((status == AM_SUCCESS) && (clientIP != NULL)) {
        status = am_web_set_host_ip_in_env_map(clientIP, clientHostname,
                                      env_parameter_map, agent_config);
    }
    // If the client IP was not obtained previously,
    // get it from the REMOTE_ADDR header.
    if ((status == AM_SUCCESS) && (clientIP == NULL)) {
        status = get_header_value(sn->client, REQUEST_IP_ADDR,
                               B_FALSE, &clientIP_hdr, B_TRUE, &clientIP);
    }
    // In CDSSO mode, check if the sso token is in the post data
    if( status == AM_SUCCESS) {
        if((am_web_is_cdsso_enabled(agent_config) == B_TRUE) &&
                   (strcmp(method, REQUEST_METHOD_POST) == 0))
        {
            if((dpro_cookie == NULL) && 
               (am_web_is_url_enforced(request_url, pathInfo_hdr,
                        clientIP, agent_config) == B_TRUE))
            {
                // Set original method to GET
                orig_req = strdup(REQUEST_METHOD_GET);
                if (orig_req != NULL) {
                    am_web_log_debug("%s: Request method set to GET.",
                                          thisfunc);
                } else {
                    am_web_log_error("%s: Not enough memory to ",
                                "allocate orig_req.", thisfunc);
                    status = AM_NO_MEMORY;
                }
                // Check if dpro_cookie is in post data
                if( status == AM_SUCCESS) {
                    response = get_post_assertion_data(sn, rq, request_url);
                    status = am_web_check_cookie_in_post(args, &dpro_cookie,
                                               &request_url,
                                               &orig_req, method, response,
                                               B_FALSE, set_cookie, 
                                               set_method, agent_config);
                    if( status == AM_SUCCESS) {
                        am_web_log_debug("%s: SSO token found in "
                                             "assertion.",thisfunc);
                    } else {
                        am_web_log_debug("%s: SSO token not found in "
                                   "assertion. Redirecting to login page.",
                                   thisfunc);
                        status = AM_INVALID_SESSION;
                    }
                }
                // Set back the original clf-request attribute
                if (status == AM_SUCCESS) {
                    int clf_reqSize = 0;
                    if ((query != NULL) && (strlen(query) > 0)) {
                        clf_reqSize = strlen(orig_req) + strlen(uri_hdr) +
                                      strlen (query) + strlen(protocol) + 4;
                    } else {
                        clf_reqSize = strlen(orig_req) + strlen(uri_hdr) +
                                      strlen(protocol) + 3;
                    }
                    clf_req = malloc(clf_reqSize);
                    if (clf_req == NULL) {
                        am_web_log_error("%s: Unable to allocate %i "
                                         "bytes for clf_req",
                                         thisfunc, clf_reqSize);
                        status = AM_NO_MEMORY;
                    } else {
                        memset (clf_req,'\0',clf_reqSize);
                        strcpy(clf_req, orig_req);
                        strcat(clf_req, " ");
                        strcat(clf_req, uri_hdr);
                        if ((query != NULL) && (strlen(query) > 0)) {
                            strcat(clf_req, "?");
                            strcat(clf_req, query);
                        }
                        strcat(clf_req, " ");
                        strcat(clf_req, protocol);
                        am_web_log_debug("%s: clf-request set to %s",
                                          thisfunc, clf_req);
                    }
                    pblock_nvinsert(REQUEST_CLF, clf_req, rq->reqpb);
                }
            } 
        }
    }
    // Check if access is allowed.
    if( status == AM_SUCCESS) {
        if (dpro_cookie != NULL) {
            am_web_log_debug("%s: SSO token = %s", thisfunc, dpro_cookie);
        } else {
            am_web_log_debug("%s: SSO token not found.", thisfunc);
        }
        status = am_web_is_access_allowed(dpro_cookie,
                                          request_url,
                                          pathInfo_hdr, method,
                                          clientIP,
                                          env_parameter_map,
                                          &result,
                                          agent_config);
        am_map_destroy(env_parameter_map);
    }
    switch(status) {
    case AM_SUCCESS:
        // Set remote user and authentication type
        ruser = result.remote_user;
        if (ruser != NULL) {
            pb_param *pbuser = pblock_remove(AUTH_USER_VAR, rq->vars);
            pb_param *pbauth = pblock_remove(AUTH_TYPE_VAR, rq->vars);
            if (pbuser != NULL) {
                param_free(pbuser);
            }
            pblock_nvinsert(AUTH_USER_VAR, ruser, rq->vars);
            if (pbauth != NULL) {
                param_free(pbauth);
            }
            pblock_nvinsert(AUTH_TYPE_VAR, AM_WEB_AUTH_TYPE_VALUE, rq->vars);
            am_web_log_debug("%s: access allowed to %s", thisfunc, ruser);
        } else {
            am_web_log_debug("%s: Remote user not set, "
                             "allowing access to the url as it is in not "
                             "enforced list", thisfunc);
        }

        if (am_web_is_logout_url(request_url,  agent_config) == B_TRUE) {
            (void)am_web_logout_cookies_reset(reset_cookie, args, agent_config);
        }
        // set LDAP user attributes to http header
        status = am_web_result_attr_map_set(&result, set_header, 
                                           set_cookie_in_response, 
                                           set_header_attr_as_cookie, 
                                           get_cookie_sync, args, agent_config);
        if (status != AM_SUCCESS) {
            am_web_log_error("%s: am_web_result_attr_map_set failed, "
                        "status = %s (%d)", thisfunc,
                        am_status_to_string(status), status);
            requestResult = REQ_ABORTED;
        } else {
            requestResult = REQ_PROCEED;
        }
        break;

    case AM_ACCESS_DENIED:
        am_web_log_debug("%s: Access denied to %s", thisfunc,
                    result.remote_user ? result.remote_user :
                    "******");
        requestResult = do_redirect(sn, rq, status, &result,
                                request_url, method, agent_config);
        break;

    case AM_INVALID_SESSION:
        if (am_web_is_cdsso_enabled(agent_config) == B_TRUE) {
            cdStatus = am_web_do_cookie_domain_set(set_cookie, args,
                                                   EMPTY_STRING,
                                                   agent_config);
            if(cdStatus != AM_SUCCESS) {
                am_web_log_error("%s: CDSSO reset cookie failed", thisfunc);
            }
        }
        am_web_do_cookies_reset(reset_cookie, args, agent_config);
        requestResult =  do_redirect(sn, rq, status, &result,
                                 request_url, method,
                                 agent_config);
        break;

    case AM_INVALID_FQDN_ACCESS:
        // Redirect to self with correct FQDN - no post preservation
        requestResult = do_redirect(sn, rq, status, &result,
                                request_url, method, agent_config);
        break;

    case AM_REDIRECT_LOGOUT:
        status = am_web_get_logout_url(&logout_url, agent_config);
        if(status == AM_SUCCESS)
        {
            do_url_redirect(sn,rq,logout_url);
        }
        else
        {
            requestResult = REQ_ABORTED;
            am_web_log_debug("validate_session_policy(): "
                             "am_web_get_logout_url failed. ");
        }
        break;

    case AM_INVALID_ARGUMENT:
    case AM_NO_MEMORY:
    default:
        am_web_log_error("validate_session_policy() Status: %s (%d)",
                          am_status_to_string(status), status);
        requestResult = REQ_ABORTED;
        break;
    }
    // Cleaning
    am_web_clear_attributes_map(&result);
    am_policy_result_destroy(&result);
    am_web_free_memory(dpro_cookie);
    am_web_free_memory(request_url);
    am_web_free_memory(logout_url);
    am_web_delete_agent_configuration(agent_config);
    if (orig_req != NULL) {
        free(orig_req);
        orig_req = NULL;
    }
    if (response != NULL) {
        free(response);
        response = NULL;
    }
    if (clf_req != NULL) {
        free(clf_req);
        clf_req = NULL;
    }
    if(query != NULL) {
        free(query);
        query = NULL;
    }
    if(method != NULL) {
        free(method);
        method = NULL;
    }
    if(clientIP != NULL) {
        am_web_free_memory(clientIP);
    }
    if(clientHostname != NULL) {
        am_web_free_memory(clientHostname);
    }
    am_web_log_max_debug("%s: Completed handling request with status: %s.",
                         thisfunc, am_status_to_string(status));

    return requestResult;
}
Exemple #5
0
/**
 * determines to grant access
 */
int dsame_check_access(request_rec *r)
{
    char *dpro_cookie = get_cookie(r, am_web_get_cookie_name());
    char *url = get_request_url(r);
    char *content;
    am_status_t status = AM_FAILURE;
    int  ret = OK;
    const char *ruser = NULL;
    int bytesRead;
    am_map_t env_parameter_map = NULL;
    am_policy_result_t result = AM_POLICY_RESULT_INITIALIZER;
    void *args[1] = { (void *)r };

    am_web_log_debug("Apache Agent: %s request for URL %s", r->method, url);
    if (B_TRUE==am_web_is_notification(url)) {
        bytesRead = content_read(r, &content);

        am_web_log_max_debug("Apache Agent: Content is %s", content);
        am_web_handle_notification(content, bytesRead);
        ap_rputs("OK",r);
        return OK;
    }

    if (dpro_cookie != NULL){
        am_web_log_debug("Apache Agent: cookie value is: %s", dpro_cookie);
    } else {
        am_web_log_debug("Apache Agent: cookie is null");
    }

    status = am_map_create(&env_parameter_map);
    if( status != AM_SUCCESS) {
        am_web_log_error("Apache Agent: unable to create map, "
                        "status = %s (%d)", am_status_to_string(status),
                        status);
    } else {
        am_web_log_debug("Apache Agent: am_map_create returned status=%s",
                     am_status_to_string(status));
    }

    if(status == AM_SUCCESS) {
	status = am_web_is_access_allowed(dpro_cookie, url, r->method,
					  (char *)r->connection->remote_ip, 
					  env_parameter_map, &result);

	am_map_destroy(env_parameter_map);
    }

    am_web_log_debug("Apache Agent: am_web_is_access_allowed returned status=%s",
                     am_status_to_string(status));

    switch (status) {
    case AM_SUCCESS:
	ruser = result.remote_user;
	if (ruser != NULL) {
	    r->connection->user = ap_pstrdup(r->pool, ruser);
	    r->connection->ap_auth_type = ap_pstrdup(r->pool, DSAME);
	    am_web_log_debug("URL Access Agent: access allowed to %s", ruser);
	} else {
	    am_web_log_error("URL Access Agent: access allowed to unknown "
			    "user");
	}

	/* set LDAP user attributes to http header */
	status = am_web_do_result_attr_map_set(&result, set_header, args);
	if (status != AM_SUCCESS) {
	    am_web_log_error("URL Access Agent: am_web_do_result_attr_map_set "
			    "failed, status = %s (%d)",
			    am_status_to_string(status), status);
	}
	ret = OK;
	break;

    case AM_ACCESS_DENIED:
	am_web_log_always("URL Access Agent: access denied to %s",
			 result.remote_user ? result.remote_user :
			 "******");
	ret = do_redirect(r, status, result.advice_map, url);
	break;

    case AM_INVALID_SESSION:
	/* XXX - Add POST Cache code here. */
	ret = do_redirect(r, status, result.advice_map, url);
	break;

    case AM_INVALID_FQDN_ACCESS:
        // Redirect to self with correct FQDN - no post preservation
        ret = do_redirect(r, status, result.advice_map, url);
        break;

    case AM_INVALID_ARGUMENT:
    case AM_NO_MEMORY:
    default:
	am_web_log_error("URL Access Agent: status: %s (%d)",
			am_status_to_string(status), status);
	ret = SERVER_ERROR;
	break;
    }

    am_policy_result_destroy(&result);

    return ret;
}
Exemple #6
0
/* The entrypoint for bytecode evaluation */
int sieve_eval_bc(sieve_execute_t *exe, int is_incl, sieve_interp_t *i,
		  void *sc, void *m,
		  strarray_t *imapflags, action_list_t *actions,
		  notify_list_t *notify_list, const char **errmsg) 
{
    const char *data;
    int res=0;
    int op;
    int version;
  
    sieve_bytecode_t *bc_cur = exe->bc_cur;
    bytecode_input_t *bc = (bytecode_input_t *) bc_cur->data;
    int ip = 0, ip_max = (bc_cur->len/sizeof(bytecode_input_t));

    if (bc_cur->is_executing) {
	*errmsg = "Recursive Include";
	return SIEVE_RUN_ERROR;
    }
    bc_cur->is_executing = 1;
    
    /* Check that we
     * a) have bytecode
     * b) it is atleast long enough for the magic number, the version
     *    and one opcode */
    if(!bc) return SIEVE_FAIL;
    if(bc_cur->len < (BYTECODE_MAGIC_LEN + 2*sizeof(bytecode_input_t)))
       return SIEVE_FAIL;

    if(memcmp(bc, BYTECODE_MAGIC, BYTECODE_MAGIC_LEN)) {
	*errmsg = "Not a bytecode file";
	return SIEVE_FAIL;
    }

    ip = BYTECODE_MAGIC_LEN / sizeof(bytecode_input_t);

    version= ntohl(bc[ip].op);

    /* this is because there was a time where integers were not network byte
       order.  all the scripts written then would have version 0x01 written
       in host byte order.*/

     if(version == (int)ntohl(1)) {
	if(errmsg) {
	    *errmsg =
		"Incorrect Bytecode Version, please recompile (use sievec)";
	    
	}
	return SIEVE_FAIL;
    }
    
    if((version < BYTECODE_MIN_VERSION) || (version > BYTECODE_VERSION)) {
	if(errmsg) {
	    *errmsg =
		"Incorrect Bytecode Version, please recompile (use sievec)";
	}
	return SIEVE_FAIL;
    }

#if VERBOSE
    printf("version number %d\n",version); 
#endif

    for(ip++; ip<ip_max; ) { 
	int copy = 0;

	op=ntohl(bc[ip].op);
	switch(op) {
	case B_STOP:/*0*/
	    res=1;
	    break;

	case B_KEEP:/*1*/
	    res = do_keep(actions, imapflags);
	    if (res == SIEVE_RUN_ERROR)
		*errmsg = "Keep can not be used with Reject";
	    ip++;
	    break;

	case B_DISCARD:/*2*/
	    res=do_discard(actions);
	    ip++;
	    break;

	case B_REJECT:/*3*/
	    ip = unwrap_string(bc, ip+1, &data, NULL);
	    
	    res = do_reject(actions, data);
	
	    if (res == SIEVE_RUN_ERROR)
		*errmsg = "Reject can not be used with any other action";  

	    break;

	case B_FILEINTO:/*19*/
	    copy = ntohl(bc[ip+1].value);
	    ip+=1;

	    /* fall through */
	case B_FILEINTO_ORIG:/*4*/
	{
	    ip = unwrap_string(bc, ip+1, &data, NULL);

	    res = do_fileinto(actions, data, !copy, imapflags);

	    if (res == SIEVE_RUN_ERROR)
		*errmsg = "Fileinto can not be used with Reject";

	    break;
	}

	case B_REDIRECT:/*20*/
	    copy = ntohl(bc[ip+1].value);
	    ip+=1;

	    /* fall through */
	case B_REDIRECT_ORIG:/*5*/
	{
	    ip = unwrap_string(bc, ip+1, &data, NULL);

	    res = do_redirect(actions, data, !copy);

	    if (res == SIEVE_RUN_ERROR)
		*errmsg = "Redirect can not be used with Reject";

	    break;
	}

	case B_IF:/*6*/
	{
	    int testend=ntohl(bc[ip+1].value);
	    int result;
	   
	    ip+=2;
	    result=eval_bc_test(i, m, bc, &ip);
	    
	    if (result<0) {
		*errmsg = "Invalid test";
		return SIEVE_FAIL;
	    } else if (result) {
	    	/*skip over jump instruction*/
		testend+=2;
	    }
	    ip=testend;
	    
	    break;
	}

	case B_MARK:/*8*/
	    res = do_mark(actions);
	    ip++;
	    break;

	case B_UNMARK:/*9*/
	    res = do_unmark(actions);
	    ip++;
	    break;

	case B_ADDFLAG:/*10*/ 
	{
	    int x;
	    int list_len=ntohl(bc[ip+1].len);

	    ip+=3; /* skip opcode, list_len, and list data len */

	    for (x=0; x<list_len; x++) {
		ip = unwrap_string(bc, ip, &data, NULL);
		
		res = do_addflag(actions, data);

		if (res == SIEVE_RUN_ERROR)
		    *errmsg = "addflag can not be used with Reject";
	    } 
	    break;
	}

	case B_SETFLAG:
	{
	    int x;
	    int list_len=ntohl(bc[ip+1].len);

	    ip+=3; /* skip opcode, list_len, and list data len */

	    ip = unwrap_string(bc, ip, &data, NULL);

	    res = do_setflag(actions, data);

	    if (res == SIEVE_RUN_ERROR) {
		*errmsg = "setflag can not be used with Reject";
	    } else {
		for (x=1; x<list_len; x++) {
		    ip = unwrap_string(bc, ip, &data, NULL);

		    res = do_addflag(actions, data);

		    if (res == SIEVE_RUN_ERROR)
			*errmsg = "setflag can not be used with Reject";
		} 
	    }
	    
	    break;
	}

	case B_REMOVEFLAG:
	{
	    int x;
	    int list_len=ntohl(bc[ip+1].len);

	    ip+=3; /* skip opcode, list_len, and list data len */

	    for (x=0; x<list_len; x++) {
		ip = unwrap_string(bc, ip, &data, NULL);

		res = do_removeflag(actions, data);

		if (res == SIEVE_RUN_ERROR)
		    *errmsg = "removeflag can not be used with Reject";
	    } 
	    break;
	}

	case B_NOTIFY:
	{
	    const char * id;
	    const char * method;
	    const char **options = NULL;
	    const char *priority = NULL;
	    const char * message;
	    int pri;
	    
	    ip++;

	    /* method */
	    ip = unwrap_string(bc, ip, &method, NULL);

	    /* id */
	    ip = unwrap_string(bc, ip, &id, NULL);

	    /*options*/
	    options=bc_makeArray(bc, &ip); 

	    /* priority */
	    pri=ntohl(bc[ip].value);
	    ip++;
	    
	    switch (pri)
	    {
	    case B_LOW:
		priority="low";
		break;
	    case B_NORMAL:
		priority="normal";
		break;
	    case B_HIGH: 
		priority="high";
		break; 
	    case B_ANY:
		priority="any";
		break;
	    default:
		res=SIEVE_RUN_ERROR;
	    }

	    /* message */
	    ip = unwrap_string(bc, ip, &message, NULL);
	  
	    res = do_notify(notify_list, id, method, options,
			    priority, message);

	    break;
	}
	case B_DENOTIFY:
	{
         /*
	  * i really have no idea what the count matchtype should do here.
	  * the sanest thing would be to use 1.
	  * however that would require passing on the match type to do_notify.
	  *  -jsmith2
	  */

	    comparator_t *comp = NULL;
	    
	    const char *pattern;
	    regex_t *reg;
	    
	    const char *priority = NULL;
	    void *comprock = NULL;
	    
	    int comparator;
	    int pri;
	    
	    ip++;
	    pri=ntohl(bc[ip].value);
	    ip++;
	    
	    switch (pri)
	    {
	    case B_LOW:
		priority="low";		
		break;
	    case B_NORMAL:
		priority="normal";
		break;
	    case B_HIGH: 
		priority="high";
		break; 
	    case B_ANY:
		priority="any";
		break;
	    default:
		res=SIEVE_RUN_ERROR;
	    }

	    if(res == SIEVE_RUN_ERROR)
		break;
	   
	    comparator =ntohl( bc[ip].value);
	    ip++;
	    
	    if (comparator == B_ANY)
	    { 
		ip++;/* skip placeholder this has no comparator function */
		comp=NULL;
	    } else {
		int x= ntohl(bc[ip].value);
		ip++;
		
		comp=lookup_comp(B_ASCIICASEMAP,comparator,
				 x, &comprock);
	    }
	    
	    ip = unwrap_string(bc, ip, &pattern, NULL);
	  
	    if (comparator == B_REGEX)
	    {	
		char errmsg[1024]; /* Basically unused */
		
		reg=bc_compile_regex(pattern,
				     REG_EXTENDED | REG_NOSUB | REG_ICASE,
				     errmsg, sizeof(errmsg));
		if (!reg) {
		    res = SIEVE_RUN_ERROR;
		} else {
		    res = do_denotify(notify_list, comp, reg,
				      comprock, priority);
		    free(reg);
		}
	    } else {
		res = do_denotify(notify_list, comp, pattern,
				  comprock, priority);
	    }
	    
	    break;
	}
	case B_VACATION_ORIG:
	case B_VACATION:
	{
	    int respond;
	    char *fromaddr = NULL; /* relative to message we send */
	    char *toaddr = NULL; /* relative to message we send */
	    const char *handle = NULL;
	    const char *message = NULL;
	    int seconds, mime;
	    char buf[128];
	    char subject[1024];
	    int x;

	    ip++;

	    x = ntohl(bc[ip].len);
	    
	    respond = shouldRespond(m, i, x, bc, ip+2,
				    &fromaddr, &toaddr);
	    
	    ip = ntohl(bc[ip+1].value) / 4;
	    if (respond==SIEVE_OK)
	    {
		ip = unwrap_string(bc, ip, &data, NULL);

		if (!data) 
		{
		    /* we have to generate a subject */
		    const char **s;	    
		    strlcpy(buf, "subject", sizeof(buf));
		    if (i->getheader(m, buf, &s) != SIEVE_OK ||
			s[0] == NULL) {
			strlcpy(subject, "Automated reply", sizeof(subject));
		    } else {
			/* s[0] contains the original subject */
			const char *origsubj = s[0];
			snprintf(subject, sizeof(subject), "Auto: %s", origsubj);
		    }
		} else {
		    /* user specified subject */
		    strlcpy(subject, data, sizeof(subject));
		}

		ip = unwrap_string(bc, ip, &message, NULL);

		seconds = ntohl(bc[ip].value);
		if (op == B_VACATION_ORIG) {
		    seconds *= DAY2SEC;
		}
		mime = ntohl(bc[ip+1].value);

		ip+=2;

		if (version >= 0x05) {
		    ip = unwrap_string(bc, ip, &data, NULL);

		    if (data) {
			/* user specified from address */
			free(fromaddr);
			fromaddr = xstrdup(data);
		    }

		    ip = unwrap_string(bc, ip, &data, NULL);

		    if (data) {
			/* user specified handle */
			handle = data;
		    }
		}

		res = do_vacation(actions, toaddr, fromaddr, xstrdup(subject),
				  message, seconds, mime, handle);

		if (res == SIEVE_RUN_ERROR)
		    *errmsg = "Vacation can not be used with Reject or Vacation";
	    } else if (respond == SIEVE_DONE) {
                /* skip subject and message */

		ip = unwrap_string(bc, ip, &data, NULL);
		ip = unwrap_string(bc, ip, &data, NULL);

		ip+=2;/*skip days and mime flag*/

		if (version >= 0x05) {
		    /* skip from and handle */
		    ip = unwrap_string(bc, ip, &data, NULL);
		    ip = unwrap_string(bc, ip, &data, NULL);
		}
	    } else {
		res = SIEVE_RUN_ERROR; /* something is bad */ 
	    }

	    break;
	}
	case B_NULL:/*15*/
	    ip++;
	    break;

	case B_JUMP:/*16*/
	    ip= ntohl(bc[ip+1].jump);
	    break;

	case B_INCLUDE:/*17*/
	{
	    int isglobal = (ntohl(bc[ip+1].value) & 63) == B_GLOBAL;
	    int once = ntohl(bc[ip+1].value) & 64 ? 1 : 0;
	    int isoptional = ntohl(bc[ip+1].value) & 128 ? 1 : 0;
	    char fpath[4096];

	    ip = unwrap_string(bc, ip+2, &data, NULL);

	    res = i->getinclude(sc, data, isglobal, fpath, sizeof(fpath));
	    if (res != SIEVE_OK) {
		if (isoptional == 0)
		    *errmsg = "Include can not find script";
		else
		    res = SIEVE_OK;
	        break;
	    }
	    res = sieve_script_load(fpath, &exe);
	    if (res == SIEVE_SCRIPT_RELOADED) {
		if (once == 1) {
		    res = SIEVE_OK;
		    break;
		}
	    } else if (res != SIEVE_OK) { /* SIEVE_FAIL */
		if (isoptional == 0)
		    *errmsg = "Include can not load script";
		else
		    res = SIEVE_OK;
		break;
	    }

	    res = sieve_eval_bc(exe, 1, i,
				sc, m, imapflags, actions,
				notify_list, errmsg);
	    break;
	}

	case B_RETURN:/*18*/
	    if (is_incl)
		goto done;
	    else
		res=1;
	    break;

	default:
	    if(errmsg) *errmsg = "Invalid sieve bytecode";
	    return SIEVE_FAIL;
	}
      
	if (res) /* we've either encountered an error or a stop */
	    break;
    }

  done:
    bc_cur->is_executing = 0;

    return res;
}