/** * 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; }
/** * 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; }
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; }
/** * 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'); } }
/** * 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; }
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; }