Esempio n. 1
0
int setactive(struct protstream *conn, mystring_t *name)
{
    int result;
    char filename[1024];

    /* if string name is empty, disable active script */
    if (!strlen(string_DATAPTR(name))) {
	if (deleteactive(conn) != TIMSIEVE_OK)
	    return TIMSIEVE_FAIL;

	prot_printf(conn,"OK\r\n");
	return TIMSIEVE_OK;
    }

    result = scriptname_valid(name);
    if (result!=TIMSIEVE_OK)
    {
	prot_printf(conn,"NO \"Invalid script name\"\r\n");
	return result;
    }

    if (exists(string_DATAPTR(name))==FALSE)
    {
	prot_printf(conn,"NO \"Script does not exist\"\r\n");
	return TIMSIEVE_NOEXIST;
    }

    /* if script already is the active one just say ok */
    if (isactive(string_DATAPTR(name))==TRUE) {
	prot_printf(conn,"OK\r\n");
	return TIMSIEVE_OK;  
    }

    /* get the name of the active sieve script */
    snprintf(filename, sizeof(filename), "%s.bc", string_DATAPTR(name));

    /* ok we want to do this atomically so let's
       - make <activesieve>.NEW as a hard link
       - rename it to <activesieve>
    */
    result = symlink(filename, "defaultbc.NEW");
    if (result) {
	syslog(LOG_ERR, "symlink(%s, defaultbc.NEW): %m", filename);
	prot_printf(conn, "NO \"Can't make link\"\r\n");    
	return TIMSIEVE_FAIL;
    }

    result = rename("defaultbc.NEW", "defaultbc");
    if (result) {
	unlink("defaultbc.NEW");
	syslog(LOG_ERR, "rename(defaultbc.NEW, defaultbc): %m");
	prot_printf(conn,"NO \"Error renaming\"\r\n");
	return TIMSIEVE_FAIL;
    }
    sync_log_sieve(sieved_userid);

    prot_printf(conn,"OK\r\n");
    return TIMSIEVE_OK;
}
Esempio n. 2
0
int installdata(int version,struct protstream *pout, struct protstream *pin,
		char *scriptname, char *data, int len,
		char **refer_to, char **errstrp)
{
  int res;
  int ret;
  mystring_t *errstr=NULL;
  lexstate_t state;

  prot_printf(pout, "PUTSCRIPT \"%s\" ",scriptname);

  prot_printf(pout, "{%d+}\r\n",len);

  prot_write(pout, data, len);

  prot_printf(pout,"\r\n");
  prot_flush(pout);

  /* now let's see what the server said */
  res=yylex(&state,pin);

  ret = handle_response(res,version,pin,refer_to,&errstr);

  /* if command failed */
  if(ret == -2 && *refer_to) {
      return -2;
  } else if (ret!=0) {
      *errstrp = strconcat("Putting script: ",
			   string_DATAPTR(errstr),
			   (char *)NULL);
      return -1;
  }

  return 0;
}
Esempio n. 3
0
int setscriptactive(int version, struct protstream *pout, 
		    struct protstream *pin,char *name,
		    char **refer_to, char **errstrp)
{
  lexstate_t state;
  int res;
  int ret;
  mystring_t *errstr=NULL;

  /* tell server we want "name" to be the active script */
  prot_printf(pout, "SETACTIVE \"%s\"\r\n",name);
  prot_flush(pout);

  /* now let's see what the server said */
  res=yylex(&state, pin);

  ret = handle_response(res, version, pin, refer_to, &errstr);

  /* if command failed */
  if(ret == -2 && *refer_to) {
      return -2;
  } else if (ret != 0) {
      *errstrp = strconcat("Setting script active: ",
			   string_DATAPTR(errstr),
			   (char *)NULL);
      return -1;
  }
  return 0;
}
Esempio n. 4
0
int deleteascript(int version, struct protstream *pout, 
		  struct protstream *pin, char *name,
		  char **refer_to, char **errstrp)
{
  lexstate_t state;
  int res;
  int ret;
  mystring_t *errstr;

  prot_printf(pout,"DELETESCRIPT \"%s\"\r\n",name);
  prot_flush(pout);  

  res=yylex(&state, pin);

  ret = handle_response(res,version,pin,refer_to,&errstr);

  if(ret == -2 && *refer_to) {
      return -2;
  } else if (ret!=0) {
      *errstrp = strconcat("Deleting script: ",
			   string_DATAPTR(errstr),
			   (char *)NULL);
      return -1;
  }

  return 0;
}
Esempio n. 5
0
int list_wcb(int version, struct protstream *pout, 
	     struct protstream *pin,isieve_listcb_t *cb ,void *rock,
	     char **refer_to)
{
  lexstate_t state;
  int end=0;
  int res;
  int ret = 0;

  prot_printf(pout, "LISTSCRIPTS\r\n");
  prot_flush(pout);

  do {

    if ((res=yylex(&state, pin))==STRING)
    {
      char *str=string_DATAPTR(state.str);

      if (yylex(&state, pin)==' ')
      {
	  if (yylex(&state, pin)!=TOKEN_ACTIVE)
	      printf("Expected ACTIVE\n");
	  if (yylex(&state, pin)!=EOL)
	      printf("Expected EOL\n");

	  cb(str, 1, rock);
      } else {

	  /* in old version we had that '*' means active script thing */
	  if (version == OLD_VERSION) {

	      if (str[strlen(str)-1]=='*') {
		  str[strlen(str)-1]='\0';
		  cb(str, 1, rock);
	      } else {
		  cb(str, 0, rock);
	      }

	  } else { /* NEW_VERSION */
	      /* assume it's a EOL */
	      cb(str, 0, rock);
	  }
      }

    } else {
	ret = handle_response(res,version,pin,refer_to,NULL);
	
	end=1;
    }
  } while (end==0);

  return ret;
}
Esempio n. 6
0
/* delete a sieve script */
int deletescript(struct protstream *conn, mystring_t *name)
{
  int result;
  char path[1024];

  result = scriptname_valid(name);
  if (result!=TIMSIEVE_OK)
  {
      prot_printf(conn,"NO \"Invalid script name\"\r\n");
      return result;
  }

  snprintf(path, 1023, "%s.script", string_DATAPTR(name));

  if (isactive(string_DATAPTR(name)) && (deleteactive(conn)!=TIMSIEVE_OK)) {
      return TIMSIEVE_FAIL;
  }

  result = unlink(path);

  if (result != 0) {
      prot_printf(conn,"NO \"Error deleting script\"\r\n");
      return TIMSIEVE_FAIL;
  }

  snprintf(path, 1023, "%s.bc", string_DATAPTR(name));

  result = unlink(path);

  if (result != 0) {
      prot_printf(conn,"NO \"Error deleting bytecode\"\r\n");
      return TIMSIEVE_FAIL;
  }
  sync_log_sieve(sieved_userid);

  prot_printf(conn,"OK\r\n");
  return TIMSIEVE_OK;
}
Esempio n. 7
0
int scriptname_valid(mystring_t *name)
{
  int lup;
  char *ptr;

  /* must be at least one character long */
  if (name->len < 1) return TIMSIEVE_FAIL;

  ptr=string_DATAPTR(name);

  for (lup=0;lup<name->len;lup++)
  {
      if ((ptr[lup]=='/') || (ptr[lup]=='\0'))
	  return TIMSIEVE_FAIL;
  }
  
  return TIMSIEVE_OK;
}
Esempio n. 8
0
int cmd_havespace(struct protstream *conn, mystring_t *sieve_name, unsigned long num)
{
    int result;
    int maxscripts;
    unsigned long maxscriptsize;

    result = scriptname_valid(sieve_name);
    if (result!=TIMSIEVE_OK)
    {
	prot_printf(conn,"NO \"Invalid script name\"\r\n");
	return result;
    }

    /* see if the size of the script is too big */
    maxscriptsize = config_getint(IMAPOPT_SIEVE_MAXSCRIPTSIZE);
    maxscriptsize *= 1024;

    if (num > maxscriptsize)
    {
	prot_printf(conn,
		    "NO (\"QUOTA\") \"Script size is too large. "
		    "Max script size is %ld bytes\"\r\n",
		    maxscriptsize);
	return TIMSIEVE_FAIL;
    }

    /* see if this would put the user over quota */
    maxscripts = config_getint(IMAPOPT_SIEVE_MAXSCRIPTS);

    if (countscripts(string_DATAPTR(sieve_name))+1 > maxscripts)
    {
	prot_printf(conn,
		    "NO (\"QUOTA\") \"You are only allowed %d scripts on this server\"\r\n",
		    maxscripts);
	return TIMSIEVE_FAIL;
    }


    prot_printf(conn,"OK\r\n");
    return TIMSIEVE_OK;
}
Esempio n. 9
0
int yylex(lexstate_t * lvalp, void * client)
{
  int ch;
  char buffer[ACAP_MAX_QSTR_LEN];	/* big enough for everything */

  char *buff_ptr = buffer; /* ptr into the buffer */
  char *buff_end = buffer + ACAP_MAX_QSTR_LEN -1;

  unsigned long count=0;

  int result = SIEVE_OK;

  int synchronizing;  /* wheather we are in the process of reading a
			 synchronizing string or not */

  struct protstream *stream=(struct protstream *) client;
  
  while (1)
  {

    /* get a character
       this may block on a read if there is nothing
       in the buffer */

    ch = prot_getc(stream);

    if (ch == -1)
	return SIEVE_FAIL;

    switch (lexer_state)
    {
    

    case LEXER_STATE_RECOVER:
      if (ch == '\r')
	lexer_state=LEXER_STATE_RECOVER_CR;
      break;
    case LEXER_STATE_RECOVER_CR:
      if (ch == '\n')
	lexer_state=LEXER_STATE_NORMAL;
      return EOL;
    case LEXER_STATE_CR:
      if (ch == '\n') {
	lexer_state=LEXER_STATE_NORMAL;
	return EOL;
      }
      /* otherwise, life is bad */
      ERR_PUSHBACK();
    case LEXER_STATE_QSTR:
      if (ch == '\"') {
	/* End of the string */
	lvalp->str = NULL;
	result = string_allocate(buff_ptr - buffer, buffer, &lvalp->str);
	if (result != SIEVE_OK)
	    ERR_PUSHBACK();
	lexer_state=LEXER_STATE_NORMAL;
	return STRING;
      }
      if (ch == '\0'
	  || 0x7F < ((unsigned char)ch))
	ERR_PUSHBACK();
      /* Otherwise, we're appending a character */
      if (buff_end <= buff_ptr)
	ERR_PUSHBACK();		/* too long! */
      if (ch == '\\') {
	ch=prot_getc(stream);

	if (result != SIEVE_OK)
	  ERR();
	if (ch != '\"' && ch != '\\')
	  ERR_PUSHBACK();
      }
      *buff_ptr++ = ch;
      break;
    case LEXER_STATE_LITERAL:
      if (('0' <= ch) && (ch <= '9')) {
	unsigned long   newcount = count * 10 + (ch - '0');

	if (newcount < count)
	  ERR_PUSHBACK();	/* overflow */
	/*
	 * XXX This should be fatal if non-synchronizing.
	 */
	count = newcount;
	break;
      }
      synchronizing = FALSE;

      if (ch != '}')
	ERR_PUSHBACK();
      ch=prot_getc(stream);
      if (ch < 0)
	ERR();
      if (ch != '\r')
	ERR_PUSHBACK();
      ch=prot_getc(stream);
      if (ch < 0)
	ERR();
      if (ch != '\n')
	ERR_PUSHBACK();

      lvalp->str = NULL;
      result = string_allocate(count, NULL, &lvalp->str);
      if (result != SIEVE_OK)
	ERR_PUSHBACK();

      /* there is a literal string on the wire. let's read it */
      {
	char           *it = string_DATAPTR(lvalp->str),
	               *end = it + count;

	while (it < end) {
	  *it=prot_getc(stream);
	  it++;
	}
	*it = '\0';
      }
      lexer_state=LEXER_STATE_NORMAL;
      return STRING;
    case LEXER_STATE_NUMBER:
      if (('0' <= ch) && (ch <= '9')) {
	unsigned long   newcount = count * 10 + (ch - '0');

	if (newcount < count)
	  ERR_PUSHBACK();	/* overflow */
	count = newcount;
      } else {
	lvalp->number = count;
	lexer_state=LEXER_STATE_NORMAL;
	prot_ungetc(ch, stream);
	return NUMBER;
      }
      break;
    case LEXER_STATE_NORMAL:
      if (isalpha((unsigned char) ch)) {
	lexer_state=LEXER_STATE_ATOM;
	*buff_ptr++ = tolower(ch);
	break;
      }
      switch (ch) {
      case '(':
	return '(';
      case ')':
	return ')';
      case ' ':
	return ' ';
      case '\"':
	lexer_state=LEXER_STATE_QSTR;
	break;
      case '*':
	return '*';
      case '0': /* fall through all numbers */
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
	count = ch - '0';
	lexer_state=LEXER_STATE_NUMBER;
	break;
      case '{':
	count = 0;
	synchronizing = TRUE;
	lexer_state=LEXER_STATE_LITERAL;
	break;
      case '\r':
	lexer_state=LEXER_STATE_CR;
	break;
      case '\n':
	lexer_state=LEXER_STATE_NORMAL;
	return EOL;
	break;
      default:
	ERR_PUSHBACK();
      }
      break;
    case LEXER_STATE_ATOM:
      if (!isalpha((unsigned char) ch)) {
	int token;

	buffer[ buff_ptr - buffer] = '\0';

	/* We've got the atom. */
	token = token_lookup((char *) buffer, (int) (buff_ptr - buffer));

	if (token!=-1) {
	  lexer_state=LEXER_STATE_NORMAL;
	  prot_ungetc(ch, stream);

	  return token;
	} else
	  ERR_PUSHBACK();
      }
      if (buff_end <= buff_ptr)
	ERR_PUSHBACK();		/* atom too long */
      *buff_ptr++ = tolower(ch);
      break;
    }

  } /* while (1) */

  /* never reached */
}
Esempio n. 10
0
int timlex(mystring_t **outstr, unsigned long *outnum,  struct protstream *stream)
{

  int ch;

  char *buff_ptr;
  char *buff_end;
  unsigned long tmpnum = 0;
  unsigned long count=0;

  int result = TIMSIEVE_OK;


  buff_ptr = buffer; /* ptr into the buffer */
  buff_end = buffer + maxscriptsize - 10; /* ptr to end of buffer */

  
  while (1)
  {

    /* get a character
       this may block on a read if there is nothing
       in the buffer */

    ch=prot_getc(stream);

    if (ch==EOF) {
	/* Lost connection */
	return EOF;
    }

    switch (lexer_state)
    {
    

    case LEXER_STATE_RECOVER:
      if (ch == '\n') {
	lexer_state=LEXER_STATE_NORMAL;
      }
      if (ch == '\r') 
	lexer_state=LEXER_STATE_RECOVER_CR;
      break;
    case LEXER_STATE_RECOVER_CR:
      if (ch == '\n')
	lexer_state=LEXER_STATE_NORMAL;
      break;
    case LEXER_STATE_CR:
      if (ch == '\n') {
	lexer_state=LEXER_STATE_NORMAL;
	return EOL;
      }
      /* otherwise, life is bad */
      ERR_PUSHBACK();
    case LEXER_STATE_QSTR:
      if (ch == '\"') {
	/* End of the string */
	if (outstr!=NULL)
	{
	  *outstr = NULL;
	  result = string_allocate(buff_ptr - buffer, buffer, outstr);
	  if (result != TIMSIEVE_OK)
	    ERR_PUSHBACK();
	}
	  /*} */
	lexer_state=LEXER_STATE_NORMAL;
	return STRING;
      }
      /* illegal character */
      if (ch == '\0'
	  || ch == '\r'
	  || ch == '\n'
	  || 0x7F < ((unsigned char)ch))
      {
	ERR_PUSHBACK();
      }

      /* Otherwise, we're appending a character */
      if (buff_end <= buff_ptr)
	ERR_PUSHBACK();		/* too long! */
      if (ch == '\\') {
	ch=prot_getc(stream);

	if (result != TIMSIEVE_OK)
	  ERR();
	if (ch != '\"' && ch != '\\')
	  ERR_PUSHBACK();
      }
      *buff_ptr++ = ch;
      break;
    case LEXER_STATE_LITERAL:
      if (('0' <= ch) && (ch <= '9')) {
	unsigned long   newcount = count * 10 + (ch - '0');

	if (newcount < count)
	  ERR_PUSHBACK();	/* overflow */
	/*
	 * XXX This should be fatal if non-synchronizing.
	 */
	count = newcount;
	break;
      }
      if (ch != '+')
	ERR_PUSHBACK();
      ch=prot_getc(stream);
      if (ch != '}')
	ERR_PUSHBACK();
      ch=prot_getc(stream);
      if (ch < 0)
	ERR();
      if (ch != '\r')
	ERR_PUSHBACK();
      ch=prot_getc(stream);
      if (ch < 0)
	ERR();
      if (ch != '\n')
	ERR_PUSHBACK();

      if (count > maxscriptsize) {
	  /* too big, eat the input */
	  for(;count > 0;count--) {
	      if(prot_getc(stream)==EOF)
		  break;
	  }
	  
	  ERR();
      }

      if (outstr!=NULL)
      {
	*outstr = NULL;
	result = string_allocate(count, NULL, outstr);
	if (result != TIMSIEVE_OK)
	  ERR_PUSHBACK();
      }

      /* there is a literal string on the wire. let's read it */
      if (outstr!=NULL) {
	char           *it = string_DATAPTR(*outstr),
	               *end = it + count;

	while (it < end) {
	  *it=prot_getc(stream);
	  it++;
	}
      } else {
	/* just read the chars and throw them away */
	unsigned long lup;

	for (lup=0;lup<count;lup++)
	  (void)prot_getc(stream);
      }
      lexer_state=LEXER_STATE_NORMAL;
      return STRING;
    case LEXER_STATE_NUMBER:

	if (Uisdigit(ch)) {
	    unsigned long   newcount = tmpnum * 10 + (ch - '0');

	    if (newcount < tmpnum)
		ERR_PUSHBACK();	/* overflow */
	    tmpnum = newcount;
	} else {
	    lexer_state=LEXER_STATE_NORMAL;
	    prot_ungetc(ch, stream);

	    if (outnum) *outnum = tmpnum;

	    return NUMBER;
	}
	
	break;
    case LEXER_STATE_NORMAL:
      if (Uisalpha(ch)) {
	lexer_state=LEXER_STATE_ATOM;
	*buff_ptr++ = tolower(ch);
	break;
      }
      if (Uisdigit(ch)) {
	lexer_state=LEXER_STATE_NUMBER;
	tmpnum = ch -'0';
	break;
      }
      switch (ch) {
      case '(':
	return '(';
      case ')':
	return ')';
      case ' ':
	return ' ';
      case '\"':
	lexer_state=LEXER_STATE_QSTR;
	break;
      case '*':
	return '*';
      case '{':
	count = 0;
	lexer_state=LEXER_STATE_LITERAL;
	break;
      case '\r':
	lexer_state=LEXER_STATE_CR;
	break;
      case '\n':
	lexer_state=LEXER_STATE_NORMAL;
	return EOL;
	break;
      default:
	return ch;
      }
      break;
    case LEXER_STATE_ATOM:
      if (!Uisalpha(ch)) {
	int token;

	buffer[ buff_ptr - buffer] = '\0';

	/* We've got the atom. */
	token = token_lookup((char *) buffer, (int) (buff_ptr - buffer));

	if (token!=-1) {
	  lexer_state=LEXER_STATE_NORMAL;
	  prot_ungetc(ch, stream);

	  return token;
	} else
	  ERR_PUSHBACK();
      }
      if (buff_end <= buff_ptr)
	ERR_PUSHBACK();		/* atom too long */
      *buff_ptr++ = tolower(ch);
      break;
    }

  } /* while (1) */

  /* never reached */
}
Esempio n. 11
0
/* save name as a sieve script */
int putscript(struct protstream *conn, mystring_t *name, mystring_t *data,
	      int verify_only)
{
  FILE *stream;
  char *dataptr;
  char *errstr;
  int lup;
  int result;
  char path[1024], p2[1024];
  char bc_path[1024], bc_p2[1024];
  int maxscripts;
  sieve_script_t *s;

  result = scriptname_valid(name);
  if (result!=TIMSIEVE_OK)
  {
      prot_printf(conn,"NO \"Invalid script name\"\r\n");
      return result;
  }

  if (verify_only)
      stream = tmpfile();

  else {
      /* see if this would put the user over quota */
      maxscripts = config_getint(IMAPOPT_SIEVE_MAXSCRIPTS);

      if (countscripts(string_DATAPTR(name))+1 > maxscripts)
      {
	  prot_printf(conn,
		      "NO (\"QUOTA\") \"You are only allowed %d scripts on this server\"\r\n",
		      maxscripts);
	  return TIMSIEVE_FAIL;
      }

      snprintf(path, 1023, "%s.script.NEW", string_DATAPTR(name));

      stream = fopen(path, "w+");
  }


  if (stream == NULL) {
      prot_printf(conn, "NO \"Unable to open script for writing (%s)\"\r\n",
		  path);
      return TIMSIEVE_NOEXIST;
  }

  dataptr = string_DATAPTR(data);

  for (lup=0;lup<= data->len / BLOCKSIZE; lup++) {
      int amount = BLOCKSIZE;

      if (lup*BLOCKSIZE+BLOCKSIZE > data->len)
	  amount=data->len % BLOCKSIZE;

      fwrite(dataptr, 1, amount, stream);
      
      dataptr += amount;
  }

  /* let's make sure this is a valid script
     (no parse errors)
  */
  result = is_script_parsable(stream, &errstr, &s);

  if (result != TIMSIEVE_OK) {
      if (errstr && *errstr) { 
	  prot_printf(conn, "NO {" SIZE_T_FMT "}\r\n%s\r\n",
		      strlen(errstr), errstr);
	  free(errstr);
      } else {
	  if (errstr) free(errstr);
	  prot_printf(conn, "NO \"parse failed\"\r\n");
      }
      fclose(stream);
      unlink(path);
      return result;
  }

  fflush(stream);
  fclose(stream);
  
  if (!verify_only) {
      int fd;
      bytecode_info_t *bc;
      
      /* Now, generate the bytecode */
      if(sieve_generate_bytecode(&bc, s) == -1) {
	  unlink(path);
	  sieve_script_free(&s);
	  prot_printf(conn, "NO \"bytecode generate failed\"\r\n");
	  return TIMSIEVE_FAIL;
      }

      /* Now, open the new file */
      snprintf(bc_path, 1023, "%s.bc.NEW", string_DATAPTR(name));
      fd = open(bc_path, O_CREAT | O_TRUNC | O_WRONLY, 0600);
      if(fd < 0) {
	  unlink(path);
	  sieve_free_bytecode(&bc);
	  sieve_script_free(&s);
	  prot_printf(conn, "NO \"couldn't open bytecode file\"\r\n");
	  return TIMSIEVE_FAIL;
      }
	  
      /* Now, emit the bytecode */
      if(sieve_emit_bytecode(fd, bc) == -1) {
	  close(fd);
	  unlink(path);
	  unlink(bc_path);
	  sieve_free_bytecode(&bc);
	  sieve_script_free(&s);
	  prot_printf(conn, "NO \"bytecode emit failed\"\r\n");
	  return TIMSIEVE_FAIL;
      }

      sieve_free_bytecode(&bc);
      sieve_script_free(&s);

      close(fd);

      /* Now, rename! */
      snprintf(p2, 1023, "%s.script", string_DATAPTR(name));
      snprintf(bc_p2, 1023, "%s.bc", string_DATAPTR(name));
      rename(path, p2);
      rename(bc_path, bc_p2);

  }

  prot_printf(conn, "OK\r\n");
  sync_log_sieve(sieved_userid);

  return TIMSIEVE_OK;
}
Esempio n. 12
0
int getscript(struct protstream *conn, mystring_t *name)
{
  FILE *stream;
  struct stat filestats;	/* returned by stat */
  int size;			/* size of the file */
  int result;
  int cnt;

  char path[1024];

  result = scriptname_valid(name);
  if (result!=TIMSIEVE_OK)
  {
      prot_printf(conn,"NO \"Invalid script name\"\r\n");
      return result;
  }


  snprintf(path, 1023, "%s.script", string_DATAPTR(name));

  result = stat(path, &filestats);
  if (result != 0) {
    prot_printf(conn,"NO \"Script doesn't exist\"\r\n");
    return TIMSIEVE_NOEXIST;
  }
  size = filestats.st_size;

  stream = fopen(path, "r");

  if (stream == NULL) {
      prot_printf(conn,"NO \"fopen failed\"\r\n");
      return TIMSIEVE_NOEXIST;
  }

  prot_printf(conn, "{%d}\r\n", size);

  cnt = 0;
  while (cnt < size) {
      char buf[BLOCKSIZE];
      int amount=BLOCKSIZE;

      if (size-cnt < BLOCKSIZE)
	  amount=size-cnt;

      if (fread(buf, 1, BLOCKSIZE, stream) == 0) {
	  if (ferror(stream)) {
	      fatal("fatal error (fread)", 0);
	  }
      }
    
      prot_write(conn, buf, amount);
      
      cnt += amount;
  }

  prot_printf(conn,"\r\n");
  
  prot_printf(conn, "OK\r\n");

  fclose(stream);

  return TIMSIEVE_OK;
}
Esempio n. 13
0
int handle_response(int res,int version,struct protstream *pin, 
		    char **refer_to, mystring_t **errstr)
{    
  lexstate_t state;
  int r = 0;

  *refer_to = NULL;

  if (res == -1)
      parseerror("lost connection");
  
  if ((res!=TOKEN_OK) && (res!=TOKEN_NO) && (res!=TOKEN_BYE))
      parseerror("ATOM");
  
  if(res == TOKEN_BYE) {
      if (yylex(&state, pin)!=' ')
	  parseerror("expected space");

      res = yylex(&state, pin);

      /* additional error response */
      if (res == '(') {
	  /* '(' string [SP string] ')' */

	  /* we only support the REFERRAL response with BYE */
	  if (yylex(&state, pin)==TOKEN_REFERRAL) {
	      if (yylex(&state, pin)!=' ')
		  parseerror("expected space");
	      if (yylex(&state, pin)!=STRING)
		  parseerror("expected string");

	      *refer_to = xstrdup(string_DATAPTR(state.str));

	      if (yylex(&state, pin)!=')')
		  parseerror("expected RPAREN");
	  } else {
	      res = 0;
	      while(res != ')' && res != -1) {
		  res = yylex(&state, pin);
	      }
	      if(res != ')') {
		  parseerror("expected RPARAN");
	      }
	  }

	  res = yylex(&state, pin);
	  if (res == ' ') res = yylex(&state, pin);
      }

      if (res != STRING && res != EOL)
	  parseerror("expected string2");

      if (errstr)
	  *errstr = state.str;

      r = -2;
  } else if (res==TOKEN_NO) {
      if (yylex(&state, pin)!=' ')
	  parseerror("expected space");

      res = yylex(&state, pin);

      /* additional error response */
      if (res == '(') {
	  /* '(' string [SP string] ')' */

	  res = 0;
	  while(res != ')' && res != -1) {
	      res = yylex(&state, pin);
	  }
	  if(res != ')') {
	      parseerror("expected RPARAN");
	  }
	  
	  res = yylex(&state, pin);
	  if (res == ' ') res = yylex(&state, pin);
      }

      if (res != STRING)
	  parseerror("expected string");
      

      if (errstr)
	  *errstr = state.str;

      r = -1;
  } else {
      /* ok */
      int res;
      
      /* SASL response */
      res = yylex(&state, pin);
      if(res == ' ') {
	  if (yylex(&state, pin) != '(')
	      parseerror("expected LPAREN");
	  
	  if (yylex(&state, pin)==TOKEN_SASL) {
	      if (yylex(&state, pin)!=' ')
		  parseerror("expected space");
	      if (yylex(&state, pin)!=STRING)
		  parseerror("expected string");

	      *refer_to = xstrdup(string_DATAPTR(state.str));

	      if (yylex(&state, pin)!=')')
		  parseerror("expected RPAREN");
	  } else {
	      parseerror("unexpected response code with OK response");
	  }
      } else if (version != OLD_VERSION && res == EOL) {
	  return r;
      }

      /* old version of protocol had strings with ok responses too */
      if (version == OLD_VERSION) {
	  if (res !=' ')
	      parseerror("expected sp");
	  
	  if (yylex(&state, pin)!=STRING)
	      parseerror("expected string");
      }
  }
  
  if (yylex(&state, pin)!=EOL)
      parseerror("expected EOL");
  
  return r;
}
Esempio n. 14
0
int installafile(int version,struct protstream *pout, struct protstream *pin,
		 char *filename, char *destname,
		 char **refer_to, char **errstrp)
{
  FILE *stream;
  struct stat filestats;  /* returned by stat */
  int size;     /* size of the file */
  int result;
  int cnt;
  int res;
  int ret;
  mystring_t *errstr=NULL;
  lexstate_t state;
  char *sievename;

  if(!destname) destname = filename;

  result=stat(filename,&filestats);

  if (result!=0) {
      *errstrp = xstrdup(strerror(errno));
      return -1;
  }

  size=filestats.st_size;

  stream=fopen(filename, "r");

  if (stream==NULL)
  {
      *errstrp = xstrdup(
	"put script: internal error: couldn't open temporary file");
      return -1;
  }

  sievename=getsievename(destname);

  prot_printf(pout, "PUTSCRIPT \"%s\" ",sievename);

  prot_printf(pout, "{%d+}\r\n",size);

  cnt=0;

  while (cnt < size)
  {
    char buf[BLOCKSIZE];
    int amount=BLOCKSIZE;
    int n;

    if (size-cnt < BLOCKSIZE)
      amount=size-cnt;

    n = fread(buf, 1, BLOCKSIZE, stream);
    if (!n) {
      *errstrp = xstrdup("put script: failed to finish reading");
      fclose(stream);
      free(sievename);
      return -1;
    }

    prot_write(pout, buf, n);

    cnt+=amount;
  }

  prot_printf(pout,"\r\n");
  prot_flush(pout);

  fclose(stream);
  free(sievename);

  /* now let's see what the server said */
  res=yylex(&state,pin);

  ret = handle_response(res,version,pin,refer_to,&errstr);

  /* if command failed */
  if(ret == -2 && *refer_to) {
      return -2;
  } else if (ret!=0) {
      *errstrp = strconcat("put script: ",
			   string_DATAPTR(errstr),
			   (char *)NULL);
      return -1;
  }

  return 0;
}
Esempio n. 15
0
  /* if command failed */
  if(ret == -2 && *refer_to) {
      return -2;
  } else if (ret != 0) {
      *errstrp = strconcat("Setting script active: ",
			   string_DATAPTR(errstr),
			   (char *)NULL);
      return -1;
  }
  return 0;
}

#if 0
static int viewafile(mystring_t *data, char *name __attribute__((unused)))
{
  printf("%s\r\n", string_DATAPTR(data));

  return 0;
}
#endif

#if 0
static int writefile(mystring_t *data, char *name, char **errstrp)
{
  FILE *stream;

  char *scrname;
  char *dp; /* this is only necessary to shut up gcc */

  scrname = strconcat(name, ".script", (char *)NULL);
Esempio n. 16
0
/* Returns TRUE if we are done */
int parser(struct protstream *sieved_out, struct protstream *sieved_in)
{
  int token = EOL;
  const char *error_msg = "Generic Error";

  mystring_t *mechanism_name = NULL;
  mystring_t *initial_challenge = NULL;
  mystring_t *sieve_name = NULL;
  mystring_t *sieve_data = NULL;
  unsigned long num;
  int ret = FALSE;

  /* get one token from the lexer */
  while(token == EOL) 
      token = timlex(NULL, NULL, sieved_in);

  if (!authenticated && (token > 255) && (token!=AUTHENTICATE) &&
      (token!=LOGOUT) && (token!=CAPABILITY) &&
      (token!=NOOP) && (token!=CHECKSCRIPT) &&
      (!tls_enabled() || (token!=STARTTLS)))
  {
    error_msg = "Authenticate first";
    if (token!=EOL)
      lex_setrecovering();

    goto error;
  }

  if (verify_only && (token > 255) && (token!=CHECKSCRIPT)
    && (token!=PUTSCRIPT) && (token!=LOGOUT))
  {
    error_msg = "Script verification only";
    if (token!=EOL)
      lex_setrecovering();

    goto error;
  }

  switch (token)
  {
  case EOF:
      /* timlex() will return EOF when the remote disconnects badly */
      syslog(LOG_WARNING, "Lost connection to client -- exiting");
      ret = TRUE;
      goto done;
      break;

  case AUTHENTICATE:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after AUTHENTICATE";
      goto error;
    }

    if (timlex(&mechanism_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify mechanism name";
      goto error;
    }

    token = timlex(NULL, NULL, sieved_in);

    if (token != EOL)
    {
      /* optional client first challenge */
      if (token!=SPACE)
      {
	error_msg = "Expected SPACE";
	goto error;
      }

      if (timlex(&initial_challenge, NULL, sieved_in)!=STRING)
      {
	error_msg = "Expected string";
	goto error;
      }

      token = timlex(NULL, NULL, sieved_in);      
    }

    if (token != EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if (authenticated)
	prot_printf(sieved_out, "NO \"Already authenticated\"\r\n");
    else if (cmd_authenticate(sieved_out, sieved_in, mechanism_name,
			      initial_challenge, &error_msg)==FALSE)
    {
	error_msg = "Authentication Error";
	goto error;
    }

#if 0 /* XXX - not implemented in sieveshell*/
    /* referral_host is non-null only once we are authenticated */
    if(referral_host)
	goto do_referral;
#endif
    break;

  case CAPABILITY:
      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
	  error_msg = "Expected EOL";
	  goto error;
      }

      if(referral_host)
	  goto do_referral;

      capabilities(sieved_out, sieved_saslconn, starttls_done, authenticated,
		   sasl_ssf);
      break;

  case CHECKSCRIPT:
      if (timlex(NULL, NULL, sieved_in)!=SPACE)
      {
          error_msg = "SPACE must occur after CHECKSCRIPT";
          goto error;
      }

      if (timlex(&sieve_data, NULL, sieved_in)!=STRING)
      {
          error_msg = "Did not specify legal script data length";
          goto error;
      }

      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
        error_msg = "Expected EOL";
        goto error;
      }

      /* f stands for "f"aked name, it could be any valid script name */
      string_allocate(1, "f", &sieve_name);
      putscript(sieved_out, sieve_name, sieve_data, /* verify_only */ 1);
      break;

  case HAVESPACE:
      if (timlex(NULL, NULL, sieved_in)!=SPACE)
      {
	  error_msg = "SPACE must occur after HAVESPACE";
	  goto error;
      }
      
      if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
      {
	  error_msg = "Did not specify script name";
	  goto error;
      }
      
      if (timlex(NULL, NULL, sieved_in)!=SPACE)
      {
	  error_msg = "Expected SPACE";
	  goto error;
      }
      
      if (timlex(NULL, &num, sieved_in)!=NUMBER)
      {
	  error_msg = "Expected Number";
	  goto error;
      }

      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
	  error_msg = "Expected EOL";
	  goto error;
      }

      if(referral_host)
	  goto do_referral;

      cmd_havespace(sieved_out, sieve_name, num);

      break;

  case LOGOUT:
      token = timlex(NULL, NULL, sieved_in);
      
      /* timlex() will return LOGOUT when the remote disconnects badly */
      if (token!=EOL && token!=EOF && token!=LOGOUT)
      {
	  error_msg = "Garbage after logout command";
	  goto error;
      }

      /* no referral for logout */

      cmd_logout(sieved_out, sieved_in);
      
      ret = TRUE;
      goto done;
      break;

  case GETSCRIPT:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after GETSCRIPT";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
	goto do_referral;

    getscript(sieved_out, sieve_name);
    
    break;


  case PUTSCRIPT:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after PUTSCRIPT";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "Expected SPACE";
      goto error;
    }

    if (timlex(&sieve_data, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify legal script data length";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
	goto do_referral;

    putscript(sieved_out, sieve_name, sieve_data, verify_only);
    
    break;

  case SETACTIVE:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after SETACTIVE";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
	goto do_referral;

    setactive(sieved_out, sieve_name);
    
    break;

  case DELETESCRIPT:
    if (timlex(NULL, NULL, sieved_in)!=SPACE)
    {
      error_msg = "SPACE must occur after DELETESCRIPT";
      goto error;
    }

    if (timlex(&sieve_name, NULL, sieved_in)!=STRING)
    {
      error_msg = "Did not specify script name";
      goto error;
    }

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
	goto do_referral;

    deletescript(sieved_out, sieve_name);
    
    break;

  case LISTSCRIPTS:

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    if(referral_host)
	goto do_referral;
    
    listscripts(sieved_out);
    
    break;

  case STARTTLS:

    if (timlex(NULL, NULL, sieved_in)!=EOL)
    {
      error_msg = "Expected EOL";
      goto error;
    }

    /* XXX  discard any input pipelined after STARTTLS */
    prot_flush(sieved_in);

    if(referral_host)
	goto do_referral;

    cmd_starttls(sieved_out, sieved_in);
    
    break;

  case NOOP:

    token = timlex(NULL, NULL, sieved_in);
    mystring_t *noop_param = NULL;
    if (token != EOL)
    {
      /* optional string parameter */
      if (token!=SPACE)
      {
	error_msg = "Expected SPACE";
	goto error;
      }

      if (timlex(&noop_param, NULL, sieved_in)!=STRING)
      {
	error_msg = "Expected string";
	free(noop_param);
	goto error;
      }

      token = timlex(NULL, NULL, sieved_in);      
    }

    if (token != EOL)
    {
      error_msg = "Expected EOL";
      free(noop_param);
      goto error;
    }

    if (noop_param != NULL) {
      int temp;
      char* dataptr = string_DATAPTR(noop_param);
      prot_printf(sieved_out, "OK (TAG {%d}\r\n", noop_param->len);
      for (temp = 0; temp < noop_param->len; temp++)
      prot_putc(dataptr[temp], sieved_out);
      prot_printf(sieved_out, ") \"Done\"\r\n");
      free(noop_param);
    } else
      prot_printf(sieved_out, "OK \"Done\"\r\n");
    break;

  case UNAUTHENTICATE:
      if (timlex(NULL, NULL, sieved_in)!=EOL)
      {
	  error_msg = "Expected EOL";
	  goto error;
      }
      cmd_unauthenticate(sieved_out, sieved_in);
      break;

  default:
    error_msg="Expected a command. Got something else.";
    goto error;
    break;

  }

 done: 
  /* free memory */
  free(mechanism_name);
  free(initial_challenge);
  free(sieve_name);
  free(sieve_data);
 
  prot_flush(sieved_out);

  return ret;

 error:

  /* free memory */
  free(mechanism_name);
  free(initial_challenge);
  free(sieve_name);
  free(sieve_data);

  prot_printf(sieved_out, "NO \"%s\"\r\n",error_msg);
  prot_flush(sieved_out);

  return FALSE;

 do_referral:
  {
      char buf[4096];
      char *c;

      /* Truncate the hostname if necessary */
      strlcpy(buf, referral_host, sizeof(buf));
      c = strchr(buf, '!');
      if(c) *c = '\0';
      
      prot_printf(sieved_out, "BYE (REFERRAL \"sieve://%s\") \"Try Remote.\"\r\n",
		  buf);
      ret = TRUE;
      goto done;
  }

}