X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/0756eb3cb50d73a77b486e47528f7cb1bffdb299..184e88237dea64ce48076cdd0184612d057cbafd:/src/src/auths/plaintext.c diff --git a/src/src/auths/plaintext.c b/src/src/auths/plaintext.c index b15a08d51..cacb91f7d 100644 --- a/src/src/auths/plaintext.c +++ b/src/src/auths/plaintext.c @@ -1,10 +1,10 @@ -/* $Cambridge: exim/src/src/auths/plaintext.c,v 1.1 2004/10/07 13:10:01 ph10 Exp $ */ +/* $Cambridge: exim/src/src/auths/plaintext.c,v 1.7 2007/01/08 10:50:19 ph10 Exp $ */ /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2004 */ +/* Copyright (c) University of Cambridge 1995 - 2007 */ /* See the file NOTICE for conditions of use and distribution. */ #include "../exim.h" @@ -14,10 +14,10 @@ /* Options specific to the plaintext authentication mechanism. */ optionlist auth_plaintext_options[] = { + { "client_ignore_invalid_base64", opt_bool, + (void *)(offsetof(auth_plaintext_options_block, client_ignore_invalid_base64)) }, { "client_send", opt_stringptr, (void *)(offsetof(auth_plaintext_options_block, client_send)) }, - { "server_condition", opt_stringptr, - (void *)(offsetof(auth_plaintext_options_block, server_condition)) }, { "server_prompts", opt_stringptr, (void *)(offsetof(auth_plaintext_options_block, server_prompts)) } }; @@ -31,9 +31,9 @@ int auth_plaintext_options_count = /* Default private options block for the plaintext authentication method. */ auth_plaintext_options_block auth_plaintext_option_defaults = { - NULL, /* server_condition */ NULL, /* server_prompts */ - NULL /* client_send */ + NULL, /* client_send */ + FALSE /* client_ignore_invalid_base64 */ }; @@ -51,7 +51,7 @@ auth_plaintext_init(auth_instance *ablock) auth_plaintext_options_block *ob = (auth_plaintext_options_block *)(ablock->options_block); if (ablock->public_name == NULL) ablock->public_name = ablock->name; -if (ob->server_condition != NULL) ablock->server = TRUE; +if (ablock->server_condition != NULL) ablock->server = TRUE; if (ob->client_send != NULL) ablock->client = TRUE; } @@ -69,7 +69,7 @@ auth_plaintext_server(auth_instance *ablock, uschar *data) auth_plaintext_options_block *ob = (auth_plaintext_options_block *)(ablock->options_block); uschar *prompts = ob->server_prompts; -uschar *clear, *cond, *end, *s; +uschar *clear, *end, *s; int number = 1; int len, rc; int sep = 0; @@ -87,14 +87,16 @@ if (prompts != NULL) } /* If data was supplied on the AUTH command, decode it, and split it up into -multiple items at binary zeros. If the data consists of the string "=" it -indicates a single, empty string. */ +multiple items at binary zeros. The strings are put into $auth1, $auth2, etc, +up to a maximum. To retain backwards compatibility, they are also put int $1, +$2, etc. If the data consists of the string "=" it indicates a single, empty +string. */ if (*data != 0) { if (Ustrcmp(data, "=") == 0) { - expand_nstring[++expand_nmax] = US""; + auth_vars[0] = expand_nstring[++expand_nmax] = US""; expand_nlength[expand_nmax] = 0; } else @@ -103,6 +105,7 @@ if (*data != 0) end = clear + len; while (clear < end && expand_nmax < EXPAND_MAXN) { + if (expand_nmax < AUTH_VARS) auth_vars[expand_nmax] = clear; expand_nstring[++expand_nmax] = clear; while (*clear != 0) clear++; expand_nlength[expand_nmax] = clear++ - expand_nstring[expand_nmax]; @@ -126,6 +129,7 @@ while ((s = string_nextinlist(&prompts, &sep, big_buffer, big_buffer_size)) /* This loop must run at least once, in case the length is zero */ do { + if (expand_nmax < AUTH_VARS) auth_vars[expand_nmax] = clear; expand_nstring[++expand_nmax] = clear; while (*clear != 0) clear++; expand_nlength[expand_nmax] = clear++ - expand_nstring[expand_nmax]; @@ -133,55 +137,13 @@ while ((s = string_nextinlist(&prompts, &sep, big_buffer, big_buffer_size)) while (clear < end && expand_nmax < EXPAND_MAXN); } -/* We now have a number of items of data in $1, $2, etc. Match against the -decoded data by expanding the condition. Also expand the id to set if -authentication succeeds. */ +/* We now have a number of items of data in $auth1, $auth2, etc (and also, for +compatibility, in $1, $2, etc). Authentication and authorization are handled +together for this authenticator by expanding the server_condition option. Note +that ablock->server_condition is always non-NULL because that's what configures +this authenticator as a server. */ -cond = expand_string(ob->server_condition); - -HDEBUG(D_auth) - { - int i; - debug_printf("%s authenticator:\n", ablock->name); - for (i = 1; i <= expand_nmax; i++) - debug_printf(" $%d = %.*s\n", i, expand_nlength[i], expand_nstring[i]); - debug_print_string(ablock->server_debug_string); /* customized debug */ - if (cond == NULL) - debug_printf("expansion failed: %s\n", expand_string_message); - else - debug_printf("expanded string: %s\n", cond); - } - -/* A forced expansion failure causes authentication to fail. Other expansion -failures yield DEFER, which will cause a temporary error code to be returned to -the AUTH command. The problem is at the server end, so the client should try -again later. */ - -if (cond == NULL) - { - if (expand_string_forcedfail) return FAIL; - auth_defer_msg = expand_string_message; - return DEFER; - } - -/* Return FAIL for empty string, "0", "no", and "false"; return OK for -"1", "yes", and "true"; return DEFER for anything else, with the string -available as an error text for the user. */ - -if (*cond == 0 || - Ustrcmp(cond, "0") == 0 || - strcmpic(cond, US"no") == 0 || - strcmpic(cond, US"false") == 0) - return FAIL; - -if (Ustrcmp(cond, "1") == 0 || - strcmpic(cond, US"yes") == 0 || - strcmpic(cond, US"true") == 0) - return OK; - -auth_defer_msg = cond; -auth_defer_user_msg = string_sprintf(": %s", cond); -return DEFER; +return auth_check_serv_cond(ablock); } @@ -207,6 +169,7 @@ uschar *text = ob->client_send; uschar *s; BOOL first = TRUE; int sep = 0; +int auth_var_idx = 0; /* The text is broken up into a number of different data items, which are sent one by one. The first one is sent with the AUTH command; the remainder are @@ -214,8 +177,9 @@ sent in response to subsequent prompts. Each is expanded before being sent. */ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL) { - int i, len; + int i, len, clear_len; uschar *ss = expand_string(s); + uschar *clear; /* Forced expansion failure is not an error; authentication is abandoned. On all but the first string, we have to abandon the authentication attempt by @@ -230,7 +194,11 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0) (void) smtp_read_response(inblock, US buffer, buffsize, '2', timeout); } - if (expand_string_forcedfail) return CANCELLED; + if (expand_string_forcedfail) + { + *buffer = 0; /* No message */ + return CANCELLED; + } string_format(buffer, buffsize, "expansion of \"%s\" failed in %s " "authenticator: %s", ssave, ablock->name, expand_string_message); return ERROR; @@ -295,6 +263,34 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL "authenticator", ablock->name); return ERROR; } + + /* Now that we know we'll continue, we put the received data into $auth, + if possible. First, decode it: buffer+4 skips over the SMTP status code. */ + + clear_len = auth_b64decode(buffer+4, &clear); + + /* If decoding failed, the default is to terminate the authentication, and + return FAIL, with the SMTP response still in the buffer. However, if client_ + ignore_invalid_base64 is set, we ignore the error, and put an empty string + into $auth. */ + + if (clear_len < 0) + { + uschar *save_bad = string_copy(buffer); + if (!ob->client_ignore_invalid_base64) + { + if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0) + (void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout); + string_format(buffer, buffsize, "Invalid base64 string in server " + "response \"%s\"", save_bad); + return CANCELLED; + } + clear = US""; + clear_len = 0; + } + + if (auth_var_idx < AUTH_VARS) + auth_vars[auth_var_idx++] = string_copy(clear); } /* Control should never actually get here. */