Beispiel #1
0
int sieve_execute_bytecode(sieve_execute_t *exe, sieve_interp_t *interp,
			   void *script_context, void *message_context) 
{
    action_list_t *actions = NULL;
    notify_list_t *notify_list = NULL;
    /*   notify_action_t *notify_action;*/
    action_t lastaction = -1;
    int ret;
    char actions_string[ACTIONS_STRING_LEN] = "";
    const char *errmsg = NULL;
    strarray_t imapflags = STRARRAY_INITIALIZER;
    
    if (!interp) return SIEVE_FAIL;

    if (interp->notify) {
	notify_list = new_notify_list();
	if (notify_list == NULL) {
	    return do_sieve_error(SIEVE_NOMEM, interp,
				  script_context, message_context, &imapflags,
				  actions, notify_list, lastaction, 0,
				  actions_string, errmsg);
	}
    }

    actions = new_action_list();
    if (actions == NULL) {
	ret = do_sieve_error(SIEVE_NOMEM, interp,
			     script_context, message_context, &imapflags,
			     actions, notify_list, lastaction, 0,
			     actions_string, errmsg);
    }
    else {
	ret = sieve_eval_bc(exe, 0, interp,
			    script_context, message_context,
			    &imapflags, actions, notify_list, &errmsg);

	if (ret < 0) {
	    ret = do_sieve_error(SIEVE_RUN_ERROR, interp,
				 script_context, message_context, &imapflags,
				 actions, notify_list, lastaction, 0,
				 actions_string, errmsg);
	}
	else {
	    ret = do_action_list(interp,
				 script_context, message_context, 
				 &imapflags, actions, notify_list,
				 actions_string, errmsg);
	}
    }

    strarray_fini(&imapflags);

    return ret;
}
Beispiel #2
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;
}