Exemple #1
0
/**
 * escape_string - Write a string to a buffer, escaping special characters
 * @param buf Buffer to write to
 * @param src String to write
 * @retval num Bytes written to buffer
 */
size_t escape_string(struct Buffer *buf, const char *src)
{
  if (!buf || !src)
    return 0;

  size_t len = 0;
  for (; *src; src++)
  {
    switch (*src)
    {
      case '\n':
        len += mutt_buffer_addstr(buf, "\\n");
        break;
      case '\r':
        len += mutt_buffer_addstr(buf, "\\r");
        break;
      case '\t':
        len += mutt_buffer_addstr(buf, "\\t");
        break;
      default:
        if ((*src == '\\') || (*src == '"'))
          len += mutt_buffer_addch(buf, '\\');
        len += mutt_buffer_addch(buf, src[0]);
    }
  }
  return len;
}
Exemple #2
0
/**
 * pretty_var - Escape and stringify a config item value
 * @param str    String to escape
 * @param buf    Buffer to write to
 * @retval num Number of bytes written to buffer
 */
size_t pretty_var(const char *str, struct Buffer *buf)
{
  if (!buf || !str)
    return 0;

  int len = 0;

  len += mutt_buffer_addch(buf, '"');
  len += escape_string(buf, str);
  len += mutt_buffer_addch(buf, '"');

  return len;
}
Exemple #3
0
int imap_mailbox_rename (const char* url, const char* parent, 
                         const char* subfolder, int subscribe)
{
  IMAP_DATA* idata;
  IMAP_MBOX mx;
  char buf[LONG_STRING];
  short n;
  BUFFER new_url;

  memset (&new_url, 0, sizeof (new_url));
  if (imap_parse_path (url, &mx) < 0)
  {
    dprint (1, (debugfile, "imap_mailbox_rename: Bad path %s\n", url));
    return -1;
  }

  if (!(idata = imap_conn_find (&mx.account, M_IMAP_CONN_NONEW)))
  {
    dprint (1, (debugfile, "imap_mailbox_rename: Couldn't find open connection to %s", mx.account.host));
    goto fail;
  }
  
  strfcpy (buf, parent, sizeof (buf));

  /* append a delimiter if necessary */
  n = mutt_strlen (buf);
  if (n && (n < sizeof (buf) - 1) && (buf[n-1] != idata->delim))
  {
    buf[n++] = idata->delim;
    buf[n] = '\0';
  }
  
  strfcpy (buf + n, subfolder, sizeof (buf) - n);

  imap_subscribe(url, 0);
  if (imap_rename_mailbox (idata, mx.mbox, buf) < 0)
    goto fail;

  if (subscribe) {
    char* slash = strchr(url+8, '/');
    if(slash) {
      mutt_buffer_add(&new_url, url, slash-url+1);
      mutt_buffer_addstr(&new_url, parent);
      mutt_buffer_addch (&new_url, idata->delim);
      mutt_buffer_addstr(&new_url, subfolder);
      if (imap_subscribe(new_url.data, 1) < 0)
        goto fail;
    }
  }

  FREE (&new_url.data);
  FREE (&mx.mbox);
  return 0;

 fail:
  FREE (&new_url.data);
  FREE (&mx.mbox);
  return -1;
}
Exemple #4
0
/**
 * dump_all_menus - Dumps all the binds or macros inside every menu
 * @param buf  Output buffer
 * @param bind If true it's :bind, else :macro
 */
static void dump_all_menus(struct Buffer *buf, bool bind)
{
  bool empty;
  for (int i = 0; i < MENU_MAX; i++)
  {
    const char *menu_name = mutt_map_get_name(i, Menus);
    struct Mapping menu = { menu_name, i };

    empty = dump_menu(buf, &menu, bind);

    /* Add a new line for readability between menus. */
    if (!empty && (i < (MENU_MAX - 1)))
      mutt_buffer_addch(buf, '\n');
  }
}
Exemple #5
0
/**
 * imap_auth_gss - GSS Authentication support
 * @param adata Imap Account data
 * @param method Name of this authentication method
 * @retval enum Result, e.g. #IMAP_AUTH_SUCCESS
 */
enum ImapAuthRes imap_auth_gss(struct ImapAccountData *adata, const char *method)
{
  gss_buffer_desc request_buf, send_token;
  gss_buffer_t sec_token;
  gss_name_t target_name;
  gss_ctx_id_t context;
  gss_OID mech_name;
  char server_conf_flags;
  gss_qop_t quality;
  int cflags;
  OM_uint32 maj_stat, min_stat;
  unsigned long buf_size;
  int rc, retval = IMAP_AUTH_FAILURE;

  if (!(adata->capabilities & IMAP_CAP_AUTH_GSSAPI))
    return IMAP_AUTH_UNAVAIL;

  if (mutt_account_getuser(&adata->conn->account) < 0)
    return IMAP_AUTH_FAILURE;

  struct Buffer *buf1 = mutt_buffer_pool_get();
  struct Buffer *buf2 = mutt_buffer_pool_get();

  /* get an IMAP service ticket for the server */
  mutt_buffer_printf(buf1, "imap@%s", adata->conn->account.host);
  request_buf.value = buf1->data;
  request_buf.length = mutt_buffer_len(buf1);

  maj_stat = gss_import_name(&min_stat, &request_buf, gss_nt_service_name, &target_name);
  if (maj_stat != GSS_S_COMPLETE)
  {
    mutt_debug(LL_DEBUG2, "Couldn't get service name for [%s]\n", buf1);
    retval = IMAP_AUTH_UNAVAIL;
    goto cleanup;
  }
  else if (C_DebugLevel >= 2)
  {
    gss_display_name(&min_stat, target_name, &request_buf, &mech_name);
    mutt_debug(LL_DEBUG2, "Using service name [%s]\n", (char *) request_buf.value);
    gss_release_buffer(&min_stat, &request_buf);
  }
  /* Acquire initial credentials - without a TGT GSSAPI is UNAVAIL */
  sec_token = GSS_C_NO_BUFFER;
  context = GSS_C_NO_CONTEXT;

  /* build token */
  maj_stat = gss_init_sec_context(&min_stat, GSS_C_NO_CREDENTIAL, &context, target_name,
                                  GSS_C_NO_OID, GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG,
                                  0, GSS_C_NO_CHANNEL_BINDINGS, sec_token, NULL,
                                  &send_token, (unsigned int *) &cflags, NULL);
  if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
  {
    print_gss_error(maj_stat, min_stat);
    mutt_debug(LL_DEBUG1, "Error acquiring credentials - no TGT?\n");
    gss_release_name(&min_stat, &target_name);

    retval = IMAP_AUTH_UNAVAIL;
    goto cleanup;
  }

  /* now begin login */
  mutt_message(_("Authenticating (GSSAPI)..."));

  imap_cmd_start(adata, "AUTHENTICATE GSSAPI");

  /* expect a null continuation response ("+") */
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_RESPOND)
  {
    mutt_debug(LL_DEBUG2, "Invalid response from server: %s\n", buf1);
    gss_release_name(&min_stat, &target_name);
    goto bail;
  }

  /* now start the security context initialisation loop... */
  mutt_debug(LL_DEBUG2, "Sending credentials\n");
  mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
  gss_release_buffer(&min_stat, &send_token);
  mutt_buffer_addstr(buf1, "\r\n");
  mutt_socket_send(adata->conn, mutt_b2s(buf1));

  while (maj_stat == GSS_S_CONTINUE_NEEDED)
  {
    /* Read server data */
    do
      rc = imap_cmd_step(adata);
    while (rc == IMAP_CMD_CONTINUE);

    if (rc != IMAP_CMD_RESPOND)
    {
      mutt_debug(LL_DEBUG1, "#1 Error receiving server response\n");
      gss_release_name(&min_stat, &target_name);
      goto bail;
    }

    if (mutt_b64_buffer_decode(buf2, adata->buf + 2) < 0)
    {
      mutt_debug(LL_DEBUG1, "Invalid base64 server response\n");
      gss_release_name(&min_stat, &target_name);
      goto err_abort_cmd;
    }
    request_buf.value = buf2->data;
    request_buf.length = mutt_buffer_len(buf2);
    sec_token = &request_buf;

    /* Write client data */
    maj_stat = gss_init_sec_context(
        &min_stat, GSS_C_NO_CREDENTIAL, &context, target_name, GSS_C_NO_OID,
        GSS_C_MUTUAL_FLAG | GSS_C_SEQUENCE_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS,
        sec_token, NULL, &send_token, (unsigned int *) &cflags, NULL);
    if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED))
    {
      print_gss_error(maj_stat, min_stat);
      mutt_debug(LL_DEBUG1, "Error exchanging credentials\n");
      gss_release_name(&min_stat, &target_name);

      goto err_abort_cmd;
    }
    mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
    gss_release_buffer(&min_stat, &send_token);
    mutt_buffer_addstr(buf1, "\r\n");
    mutt_socket_send(adata->conn, mutt_b2s(buf1));
  }

  gss_release_name(&min_stat, &target_name);

  /* get security flags and buffer size */
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);

  if (rc != IMAP_CMD_RESPOND)
  {
    mutt_debug(LL_DEBUG1, "#2 Error receiving server response\n");
    goto bail;
  }
  if (mutt_b64_buffer_decode(buf2, adata->buf + 2) < 0)
  {
    mutt_debug(LL_DEBUG1, "Invalid base64 server response\n");
    goto err_abort_cmd;
  }
  request_buf.value = buf2->data;
  request_buf.length = mutt_buffer_len(buf2);

  maj_stat = gss_unwrap(&min_stat, context, &request_buf, &send_token, &cflags, &quality);
  if (maj_stat != GSS_S_COMPLETE)
  {
    print_gss_error(maj_stat, min_stat);
    mutt_debug(LL_DEBUG2, "Couldn't unwrap security level data\n");
    gss_release_buffer(&min_stat, &send_token);
    goto err_abort_cmd;
  }
  mutt_debug(LL_DEBUG2, "Credential exchange complete\n");

  /* first octet is security levels supported. We want NONE */
  server_conf_flags = ((char *) send_token.value)[0];
  if (!(((char *) send_token.value)[0] & GSS_AUTH_P_NONE))
  {
    mutt_debug(LL_DEBUG2, "Server requires integrity or privacy\n");
    gss_release_buffer(&min_stat, &send_token);
    goto err_abort_cmd;
  }

  /* we don't care about buffer size if we don't wrap content. But here it is */
  ((char *) send_token.value)[0] = '\0';
  buf_size = ntohl(*((long *) send_token.value));
  gss_release_buffer(&min_stat, &send_token);
  mutt_debug(LL_DEBUG2, "Unwrapped security level flags: %c%c%c\n",
             (server_conf_flags & GSS_AUTH_P_NONE) ? 'N' : '-',
             (server_conf_flags & GSS_AUTH_P_INTEGRITY) ? 'I' : '-',
             (server_conf_flags & GSS_AUTH_P_PRIVACY) ? 'P' : '-');
  mutt_debug(LL_DEBUG2, "Maximum GSS token size is %ld\n", buf_size);

  /* agree to terms (hack!) */
  buf_size = htonl(buf_size); /* not relevant without integrity/privacy */
  mutt_buffer_reset(buf1);
  mutt_buffer_addch(buf1, GSS_AUTH_P_NONE);
  mutt_buffer_addstr_n(buf1, ((char *) &buf_size) + 1, 3);
  /* server decides if principal can log in as user */
  mutt_buffer_addstr(buf1, adata->conn->account.user);
  request_buf.value = buf1->data;
  request_buf.length = mutt_buffer_len(buf1);
  maj_stat = gss_wrap(&min_stat, context, 0, GSS_C_QOP_DEFAULT, &request_buf,
                      &cflags, &send_token);
  if (maj_stat != GSS_S_COMPLETE)
  {
    mutt_debug(LL_DEBUG2, "Error creating login request\n");
    goto err_abort_cmd;
  }

  mutt_b64_buffer_encode(buf1, send_token.value, send_token.length);
  mutt_debug(LL_DEBUG2, "Requesting authorisation as %s\n", adata->conn->account.user);
  mutt_buffer_addstr(buf1, "\r\n");
  mutt_socket_send(adata->conn, mutt_b2s(buf1));

  /* Joy of victory or agony of defeat? */
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);
  if (rc == IMAP_CMD_RESPOND)
  {
    mutt_debug(LL_DEBUG1, "Unexpected server continuation request\n");
    goto err_abort_cmd;
  }
  if (imap_code(adata->buf))
  {
    /* flush the security context */
    mutt_debug(LL_DEBUG2, "Releasing GSS credentials\n");
    maj_stat = gss_delete_sec_context(&min_stat, &context, &send_token);
    if (maj_stat != GSS_S_COMPLETE)
      mutt_debug(LL_DEBUG1, "Error releasing credentials\n");

    /* send_token may contain a notification to the server to flush
     * credentials. RFC1731 doesn't specify what to do, and since this
     * support is only for authentication, we'll assume the server knows
     * enough to flush its own credentials */
    gss_release_buffer(&min_stat, &send_token);

    retval = IMAP_AUTH_SUCCESS;
    goto cleanup;
  }
  else
    goto bail;

err_abort_cmd:
  mutt_socket_send(adata->conn, "*\r\n");
  do
    rc = imap_cmd_step(adata);
  while (rc == IMAP_CMD_CONTINUE);

bail:
  mutt_error(_("GSSAPI authentication failed"));
  retval = IMAP_AUTH_FAILURE;

cleanup:
  mutt_buffer_pool_release(&buf1);
  mutt_buffer_pool_release(&buf2);

  return retval;
}
Exemple #6
0
int mutt_extract_token (BUFFER *dest, BUFFER *tok, int flags)
{
  char		ch;
  char		qc = 0; /* quote char */
  char		*pc;

  /* reset the destination pointer to the beginning of the buffer */
  dest->dptr = dest->data;

  SKIPWS (tok->dptr);
  while ((ch = *tok->dptr))
  {
    if (!qc)
    {
      if ((ISSPACE (ch) && !(flags & M_TOKEN_SPACE)) ||
	  (ch == '#' && !(flags & M_TOKEN_COMMENT)) ||
	  (ch == '=' && (flags & M_TOKEN_EQUAL)) ||
	  (ch == ';' && !(flags & M_TOKEN_SEMICOLON)) ||
	  ((flags & M_TOKEN_PATTERN) && strchr ("~!|", ch)))
	break;
    }

    tok->dptr++;

    if (ch == qc)
      qc = 0; /* end of quote */
    else if (!qc && (ch == '\'' || ch == '"') && !(flags & M_TOKEN_QUOTE))
      qc = ch;
    else if (ch == '\\' && qc != '\'')
    {
      if (!*tok->dptr)
	return -1; /* premature end of token */
      switch (ch = *tok->dptr++)
      {
	case 'c':
	case 'C':
	  if (!*tok->dptr)
	    return -1; /* premature end of token */
	  mutt_buffer_addch (dest, (toupper (*tok->dptr) - '@') & 0x7f);
	  tok->dptr++;
	  break;
	case 'r':
	  mutt_buffer_addch (dest, '\r');
	  break;
	case 'n':
	  mutt_buffer_addch (dest, '\n');
	  break;
	case 't':
	  mutt_buffer_addch (dest, '\t');
	  break;
	case 'f':
	  mutt_buffer_addch (dest, '\f');
	  break;
	case 'e':
	  mutt_buffer_addch (dest, '\033');
	  break;
	default:
	  if (isdigit ((unsigned char) ch) &&
	      isdigit ((unsigned char) *tok->dptr) &&
	      isdigit ((unsigned char) *(tok->dptr + 1)))
	  {

	    mutt_buffer_addch (dest, (ch << 6) + (*tok->dptr << 3) + *(tok->dptr + 1) - 3504);
	    tok->dptr += 2;
	  }
	  else
	    mutt_buffer_addch (dest, ch);
      }
    }
    else if (ch == '^' && (flags & M_TOKEN_CONDENSE))
    {
      if (!*tok->dptr)
	return -1; /* premature end of token */
      ch = *tok->dptr++;
      if (ch == '^')
	mutt_buffer_addch (dest, ch);
      else if (ch == '[')
	mutt_buffer_addch (dest, '\033');
      else if (isalpha ((unsigned char) ch))
	mutt_buffer_addch (dest, toupper (ch) - '@');
      else
      {
	mutt_buffer_addch (dest, '^');
	mutt_buffer_addch (dest, ch);
      }
    }
    else if (ch == '`' && (!qc || qc == '"'))
    {
#ifndef LIBMUTT
      FILE	*fp;
      pid_t	pid;
      char	*cmd, *ptr;
      size_t	expnlen;
      BUFFER	expn;
      int	line = 0;

      pc = tok->dptr;
      do {
	if ((pc = strpbrk (pc, "\\`")))
	{
	  /* skip any quoted chars */
	  if (*pc == '\\')
	    pc += 2;
	}
      } while (pc && *pc != '`');
      if (!pc)
      {
	dprint (1, (debugfile, "mutt_get_token: mismatched backtics\n"));
	return (-1);
      }
      cmd = mutt_substrdup (tok->dptr, pc);
      if ((pid = mutt_create_filter (cmd, NULL, &fp, NULL)) < 0)
      {
	dprint (1, (debugfile, "mutt_get_token: unable to fork command: %s", cmd));
	return (-1);
      }
      FREE (&cmd);

      tok->dptr = pc + 1;

      /* read line */
      memset (&expn, 0, sizeof (expn));
      expn.data = mutt_read_line (NULL, &expn.dsize, fp, &line);
      fclose (fp);
      mutt_wait_filter (pid);

      /* if we got output, make a new string consiting of the shell ouptput
	 plus whatever else was left on the original line */
      /* BUT: If this is inside a quoted string, directly add output to 
       * the token */
      if (expn.data && qc)
      {
	mutt_buffer_addstr (dest, expn.data);
	FREE (&expn.data);
      }
      else if (expn.data)
      {
	expnlen = mutt_strlen (expn.data);
	tok->dsize = expnlen + mutt_strlen (tok->dptr) + 1;
	ptr = safe_malloc (tok->dsize);
	memcpy (ptr, expn.data, expnlen);
	strcpy (ptr + expnlen, tok->dptr);
	if (tok->destroy)
	  FREE (&tok->data);
	tok->data = ptr;
	tok->dptr = ptr;
	tok->destroy = 1; /* mark that the caller should destroy this data */
	ptr = NULL;
	FREE (&expn.data);
      }
#else
      int backtick_not_supported__file_bug = 0;
      assert(backtick_not_supported__file_bug);
#endif
    }
    else if (ch == '$' && (!qc || qc == '"') && (*tok->dptr == '{' || isalpha ((unsigned char) *tok->dptr)))
    {
      char *env = NULL, *var = NULL;

      if (*tok->dptr == '{')
      {
	tok->dptr++;
	if ((pc = strchr (tok->dptr, '}')))
	{
	  var = mutt_substrdup (tok->dptr, pc);
	  tok->dptr = pc + 1;
	}
      }
      else
      {
	for (pc = tok->dptr; isalpha ((unsigned char) *pc) || *pc == '_'; pc++)
	  ;
	var = mutt_substrdup (tok->dptr, pc);
	tok->dptr = pc;
      }
      if (var && (env = getenv (var)))
	mutt_buffer_addstr (dest, env);
      FREE (&var);
    }
    else
      mutt_buffer_addch (dest, ch);
  }
  mutt_buffer_addch (dest, 0); /* terminate the string */
  SKIPWS (tok->dptr);
  return 0;
}