From ff68deaa08cd74acfbaeb97be8b8b8884f0cf5b5 Mon Sep 17 00:00:00 2001 From: Aki Tuomi Date: Tue, 20 Aug 2024 14:52:37 +0300 Subject: [PATCH] login-common: Use new var_expand --- src/login-common/client-common.c | 358 +++++++++++++++--------------- src/login-common/login-settings.c | 4 +- 2 files changed, 185 insertions(+), 177 deletions(-) diff --git a/src/login-common/client-common.c b/src/login-common/client-common.c index 618c6beae8..e9573ea9c5 100644 --- a/src/login-common/client-common.c +++ b/src/login-common/client-common.c @@ -21,8 +21,8 @@ #include "str-sanitize.h" #include "safe-memset.h" #include "time-util.h" -#include "var-expand.h" #include "settings.h" +#include "var-expand-new.h" #include "master-interface.h" #include "master-service.h" #include "login-client.h" @@ -77,8 +77,10 @@ static_assert_array_size(client_auth_fail_code_event_reasons, CLIENT_AUTH_FAIL_CODE_COUNT); static const char *client_get_log_str(struct client *client, const char *msg); -static const struct var_expand_table * -get_var_expand_table(struct client *client); +static const struct var_expand_params * +get_var_expand_params(struct client *client); +static void +client_var_expand_callback(void *context, struct var_expand_params *params_r); void login_client_hooks_add(struct module *module, const struct login_client_hooks *hooks) @@ -196,13 +198,6 @@ static bool client_is_trusted(struct client *client) return FALSE; } -static void -client_var_expand_callback(void *context, struct var_expand_params *params_r) -{ - struct client *client = context; - params_r->table = get_var_expand_table(client); -} - static int client_settings_get(struct client *client, const char **error_r) { i_assert(client->set == NULL); @@ -978,38 +973,79 @@ const char *client_get_session_id(struct client *client) } static struct var_expand_table login_var_expand_empty_tab[] = { - { 'u', NULL, "user" }, - { 'n', NULL, "username" }, - { 'd', NULL, "domain" }, - - { '\0', NULL, "protocol" }, - { 'h', NULL, "home" }, - { 'l', NULL, "local_ip" }, - { 'r', NULL, "remote_ip" }, - { 'm', NULL, "mechanism" }, - { 'a', NULL, "local_port" }, - { 'b', NULL, "remote_port" }, - { 'c', NULL, "secured" }, - { 'k', NULL, "ssl_security" }, - { 'e', NULL, "mail_pid" }, - { '\0', NULL, "session" }, - { '\0', NULL, "real_local_ip" }, - { '\0', NULL, "real_remote_ip" }, - { '\0', NULL, "real_local_port" }, - { '\0', NULL, "real_remote_port" }, - { '\0', NULL, "original_user" }, - { '\0', NULL, "original_username" }, - { '\0', NULL, "original_domain" }, - { '\0', NULL, "auth_user" }, - { '\0', NULL, "auth_username" }, - { '\0', NULL, "auth_domain" }, - { '\0', NULL, "listener" }, - { '\0', NULL, "local_name" }, - { '\0', NULL, "ssl_ja3" }, - - { '\0', NULL, NULL } + { .key = "user", .value = NULL }, + { .key = "username", .value = NULL }, + { .key = "domain", .value = NULL }, + + { .key = "protocol", .value = NULL }, + { .key = "home", .value = NULL }, + { .key = "local_ip", .value = NULL }, + { .key = "remote_ip", .value = NULL }, + { .key = "mechanism", .value = NULL }, + { .key = "local_port", .value = NULL }, + { .key = "remote_port", .value = NULL }, + { .key = "secured", .value = NULL }, + { .key = "ssl_security", .value = NULL }, + { .key = "mail_pid", .value = NULL }, + { .key = "session", .value = NULL }, + { .key = "real_local_ip", .value = NULL }, + { .key = "real_remote_ip", .value = NULL }, + { .key = "real_local_port", .value = NULL }, + { .key = "real_remote_port", .value = NULL }, + { .key = "original_user", .value = NULL }, + { .key = "original_username", .value = NULL }, + { .key = "original_domain", .value = NULL }, + { .key = "auth_user", .value = NULL }, + { .key = "auth_username", .value = NULL }, + { .key = "auth_domain", .value = NULL }, + { .key = "listener", .value = NULL }, + { .key = "local_name", .value = NULL }, + { .key = "ssl_ja3", .value = NULL }, + { .key = "ssl_ja3_hash", .value = NULL }, + + VAR_EXPAND_TABLE_END }; +static const char * +client_ssl_ja3_hash(struct client *client) +{ + if (client->ssl_iostream == NULL) + return ""; + + unsigned char hash[MD5_RESULTLEN]; + const char *ja3 = ssl_iostream_get_ja3(client->ssl_iostream); + if (ja3 == NULL) + return ""; + md5_get_digest(ja3, strlen(ja3), hash); + return binary_to_hex(hash, sizeof(hash)); +} + +static int +client_var_expand_func_passdb(const char *field_name, const char **value_r, + void *context, + const char **error_r ATTR_UNUSED) +{ + struct client *client = context; + unsigned int i; + size_t field_name_len; + + *value_r = ""; + + if (client->auth_passdb_args == NULL) + return 0; + + field_name_len = strlen(field_name); + for (i = 0; client->auth_passdb_args[i] != NULL; i++) { + if (strncmp(client->auth_passdb_args[i], field_name, + field_name_len) == 0 && + client->auth_passdb_args[i][field_name_len] == '=') { + *value_r = client->auth_passdb_args[i] + field_name_len+1; + break; + } + } + return 0; +} + static void get_var_expand_users(struct var_expand_table *tab, const char *user) { @@ -1023,8 +1059,13 @@ get_var_expand_users(struct var_expand_table *tab, const char *user) tab[i].value = str_sanitize(tab[i].value, 80); } -static const struct var_expand_table * -get_var_expand_table(struct client *client) +static const struct var_expand_provider client_common_providers[] = { + { .key = "passdb", client_var_expand_func_passdb }, + VAR_EXPAND_TABLE_END +}; + +static const struct var_expand_params * +get_var_expand_params(struct client *client) { struct var_expand_table *tab; @@ -1033,192 +1074,159 @@ get_var_expand_table(struct client *client) sizeof(login_var_expand_empty_tab)); if (client->virtual_user != NULL) - get_var_expand_users(tab, client->virtual_user); - tab[3].value = login_binary->protocol; - tab[4].value = getenv("HOME"); - tab[5].value = net_ip2addr(&client->local_ip); - tab[6].value = net_ip2addr(&client->ip); - tab[7].value = client->auth_mech_name == NULL ? NULL : - str_sanitize(client->auth_mech_name, MAX_MECH_NAME); - tab[8].value = dec2str(client->local_port); - tab[9].value = dec2str(client->remote_port); + get_var_expand_users(&tab[0], client->virtual_user); + var_expand_table_set_value(tab, "protocol", login_binary->protocol); + var_expand_table_set_value(tab, "home", getenv("HOME")); + var_expand_table_set_value(tab, "local_ip", net_ip2addr(&client->local_ip)); + var_expand_table_set_value(tab, "remote_ip", net_ip2addr(&client->ip)); + if (client->auth_mech_name != NULL) + var_expand_table_set_value(tab, "mechanism", + str_sanitize(client->auth_mech_name, MAX_MECH_NAME)); + var_expand_table_set_value(tab, "local_port", dec2str(client->local_port)); + var_expand_table_set_value(tab, "remote_port", dec2str(client->remote_port)); if (client->haproxy_terminated_tls) { - tab[10].value = "TLS"; - tab[11].value = "(proxied)"; + var_expand_table_set_value(tab, "secured", "TLS"); + var_expand_table_set_value(tab, "ssl_security", "(proxied)"); } else if (!client->connection_tls_secured) { - tab[10].value = client->connection_secured ? "secured" : NULL; - tab[11].value = ""; + if (client->connection_secured) + var_expand_table_set_value(tab, "secured", "secured"); } else if (client->ssl_iostream != NULL) { const char *ssl_state = ssl_iostream_is_handshaked(client->ssl_iostream) ? "TLS" : "TLS handshaking"; const char *ssl_error = ssl_iostream_get_last_error(client->ssl_iostream); - - tab[10].value = ssl_error == NULL ? ssl_state : - t_strdup_printf("%s: %s", ssl_state, ssl_error); - tab[11].value = - ssl_iostream_get_security_string(client->ssl_iostream); - tab[26].value = - ssl_iostream_get_ja3(client->ssl_iostream); + if (ssl_error != NULL) + ssl_state = t_strdup_printf("%s: %s", ssl_state, ssl_error); + var_expand_table_set_value(tab, "secured", ssl_state); + var_expand_table_set_value(tab, "ssl_security", + ssl_iostream_get_security_string(client->ssl_iostream)); + var_expand_table_set_value(tab, "ssl_ja3", + ssl_iostream_get_ja3(client->ssl_iostream)); + var_expand_table_set_value(tab, "ssl_ja3_hash", + client_ssl_ja3_hash(client)); } else { - tab[10].value = "TLS"; - tab[11].value = ""; + var_expand_table_set_value(tab, "secured", "TSL"); + var_expand_table_set_value(tab, "ssl_security", ""); } - tab[12].value = client->mail_pid == 0 ? "" : + + const char *mail_pid = client->mail_pid == 0 ? "" : dec2str(client->mail_pid); - tab[13].value = client_get_session_id(client); - tab[14].value = net_ip2addr(&client->real_local_ip); - tab[15].value = net_ip2addr(&client->real_remote_ip); - tab[16].value = dec2str(client->real_local_port); - tab[17].value = dec2str(client->real_remote_port); + var_expand_table_set_value(tab, "mail_pid", mail_pid); + var_expand_table_set_value(tab, "session", client_get_session_id(client)); + var_expand_table_set_value(tab, "real_local_ip", + net_ip2addr(&client->real_local_ip)); + var_expand_table_set_value(tab, "real_remote_ip", + net_ip2addr(&client->real_local_ip)); + var_expand_table_set_value(tab, "real_local_port", + dec2str(client->real_local_port)); + var_expand_table_set_value(tab, "real_remote_port", + dec2str(client->real_remote_port)); if (client->virtual_user_orig != NULL) - get_var_expand_users(tab+18, client->virtual_user_orig); + get_var_expand_users(&tab[18], client->virtual_user_orig); else { - tab[18].value = tab[0].value; - tab[19].value = tab[1].value; - tab[20].value = tab[2].value; + var_expand_table_copy(tab, "original_user", "user"); + var_expand_table_copy(tab, "original_username", "username"); + var_expand_table_copy(tab, "original_domain", "domain"); } + if (client->virtual_auth_user != NULL) - get_var_expand_users(tab+21, client->virtual_auth_user); + get_var_expand_users(&tab[21], client->virtual_auth_user); else { - tab[21].value = tab[18].value; - tab[22].value = tab[19].value; - tab[23].value = tab[20].value; + var_expand_table_copy(tab, "auth_user", "user"); + var_expand_table_copy(tab, "auth_username", "username"); + var_expand_table_copy(tab, "auth_domain", "domain"); } - tab[24].value = client->listener_name; - tab[25].value = str_sanitize(client->local_name, 256); - return tab; -} -static bool have_username_key(const char *str) -{ - char key; - - for (; *str != '\0'; str++) { - if (str[0] == '%' && str[1] != '\0') { - str++; - key = var_get_key(str); - if (key == 'u' || key == 'n') - return TRUE; - } - } - return FALSE; -} + var_expand_table_set_value(tab, "listener", client->listener_name); + var_expand_table_set_value(tab, "local_name", + str_sanitize(client->local_name, 256)); -static int -client_var_expand_func_passdb(const char *data, void *context, - const char **value_r, - const char **error_r ATTR_UNUSED) -{ - struct client *client = context; - const char *field_name = data; - unsigned int i; - size_t field_name_len; + struct var_expand_params *params = t_new(struct var_expand_params, 1); + params->table = tab; + params->providers = client_common_providers; + params->context = client; - *value_r = NULL; - - if (client->auth_passdb_args == NULL) - return 1; - - field_name_len = strlen(field_name); - for (i = 0; client->auth_passdb_args[i] != NULL; i++) { - if (strncmp(client->auth_passdb_args[i], field_name, - field_name_len) == 0 && - client->auth_passdb_args[i][field_name_len] == '=') { - *value_r = client->auth_passdb_args[i] + field_name_len+1; - return 1; - } - } - return 1; + return params; } -static int client_var_expand_func_ssl_ja3_hash(const char *data ATTR_UNUSED, - void *context, - const char **value_r, - const char **error_r ATTR_UNUSED) +static void +client_var_expand_callback(void *context, struct var_expand_params *params_r) { struct client *client = context; - - if (client->ssl_iostream == NULL) { - *value_r = NULL; - return 1; - } - - unsigned char hash[MD5_RESULTLEN]; - const char *ja3 = ssl_iostream_get_ja3(client->ssl_iostream); - if (ja3 == NULL) { - *value_r = NULL; - } else { - md5_get_digest(ja3, strlen(ja3), hash); - *value_r = binary_to_hex(hash, sizeof(hash)); - } - return 1; + const struct var_expand_params *params = get_var_expand_params(client); + *params_r = *params; } static const char * client_get_log_str(struct client *client, const char *msg) { - static const struct var_expand_func_table func_table[] = { - { "passdb", client_var_expand_func_passdb }, - { "ssl_ja3_hash", client_var_expand_func_ssl_ja3_hash }, - { NULL, NULL } + struct client empty_client; + i_zero(&empty_client); + const struct var_expand_params *params = get_var_expand_params(client); + const struct var_expand_params empty_params = { + .table = login_var_expand_empty_tab, + .providers = client_common_providers, + .context = &empty_client, + .event = client->event, }; static bool expand_error_logged = FALSE; - const struct var_expand_table *client_tab; char *const *e; const char *error; string_t *str, *str2; - unsigned int pos; - - client_tab = get_var_expand_table(client); str = t_str_new(256); - str2 = t_str_new(128); + str2 = t_str_new(256); + size_t pos = 0; for (e = client->set->log_format_elements_split; *e != NULL; e++) { - pos = str_len(str); - if (var_expand_with_funcs(str, *e, client_tab, - func_table, client, &error) <= 0 && - !expand_error_logged) { - /* NOTE: Don't log via client->event - it would cause - recursion */ - i_error("Failed to expand log_format_elements=%s: %s", - *e, error); - expand_error_logged = TRUE; + pos = str->used; + struct var_expand_program *prog; + if (var_expand_program_create(*e, &prog, &error) < 0 || + var_expand_program_execute(str, prog, params, &error) < 0) { + if (!expand_error_logged) { + /* NOTE: Don't log via client->event - + it would cause recursion. */ + i_error("Failed to expand log_format_elements=%s: %s", + *e, error); + expand_error_logged = TRUE; + } } - if (have_username_key(*e)) { + const char *const *vars = var_expand_program_variables(prog); + if (str_array_find(vars, "user") || + str_array_find(vars, "username")) { /* username is added even if it's empty */ + var_expand_program_free(&prog); } else { str_truncate(str2, 0); - if (var_expand_with_table(str2, *e, - login_var_expand_empty_tab, - &error) <= 0) { + int ret = var_expand_program_execute(str2, prog, + &empty_params, &error); + var_expand_program_free(&prog); + if (ret < 0 || strcmp(str_c(str)+pos, str_c(str2)) == 0) { /* we just logged this error above. no need to do it again. */ - } - if (strcmp(str_c(str)+pos, str_c(str2)) == 0) { - /* empty %variables, don't add */ str_truncate(str, pos); continue; } } - + pos = str->used; if (str_len(str) > 0) str_append(str, ", "); } - - if (str_len(str) > 0) - str_truncate(str, str_len(str)-2); - - const struct var_expand_table tab[3] = { - { 's', t_strdup(str_c(str)), NULL }, - { '$', msg, NULL }, - { '\0', NULL, NULL } + /* remove the trailing comma */ + str_truncate(str, pos); + + const struct var_expand_params params2 = { + .table = (const struct var_expand_table[]){ + { .key = "elements", .value = t_strdup(str_c(str)) }, + { .key = "message", .value = msg, }, + VAR_EXPAND_TABLE_END + }, + .event = client->event, }; str_truncate(str, 0); - if (var_expand_with_table(str, client->set->login_log_format, tab, - &error) <= 0) { + if (var_expand_new(str, client->set->login_log_format, ¶ms2, + &error) < 0) { /* NOTE: Don't log via client->event - it would cause recursion */ i_error("Failed to expand login_log_format=%s: %s", diff --git a/src/login-common/login-settings.c b/src/login-common/login-settings.c index c4b36c20b8..3784f016fd 100644 --- a/src/login-common/login-settings.c +++ b/src/login-common/login-settings.c @@ -47,8 +47,8 @@ static const struct login_settings login_default_settings = { .login_trusted_networks = ARRAY_INIT, .login_source_ips = ARRAY_INIT, .login_greeting = PACKAGE_NAME" ready.", - .login_log_format_elements = "user=<%u> method=%m rip=%r lip=%l mpid=%e %c session=<%{session}>", - .login_log_format = "%$: %s", + .login_log_format_elements = "user=<%{user}> method=%{mech} rip=%{rip} lip=%{lip} mpid=%{mail_pid} %{secured} session=<%{session}>", + .login_log_format = "%{message}: %{elements}", .login_proxy_notify_path = "proxy-notify", .login_plugin_dir = MODULEDIR"/login", .login_plugins = ARRAY_INIT, -- 2.47.3