bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2003-2018 Dovecot authors, see the included COPYING file */
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen#include "lib.h"
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen#include "array.h"
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen#include "md5.h"
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen#include "hash.h"
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen#include "hex-binary.h"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi#include "base64.h"
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen#include "hostpid.h"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi#include "hmac.h"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi#include "pkcs5.h"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi#include "hash-method.h"
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen#include "str.h"
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen#include "strescape.h"
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen#include "var-expand.h"
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi#include "var-expand-private.h"
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
d758298b3b6f1ebcd494392c0f20b0e119a9e85eTimo Sirainen#include <unistd.h>
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen#include <ctype.h>
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen#define TABLE_LAST(t) \
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen ((t)->key == '\0' && (t)->long_key == NULL)
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainenstruct var_expand_modifier {
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen char key;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen const char *(*func)(const char *, struct var_expand_context *);
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen};
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomistatic ARRAY(struct var_expand_extension_func_table) var_expand_extensions;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenm_str_lcase(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen return t_str_lcase(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenm_str_ucase(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
cd700cc7be045389dd1c948b2372b30ee99c5795Timo Sirainen return t_str_ucase(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenm_str_escape(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen return str_escape(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenm_str_hex(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen{
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen unsigned long long l;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch if (str_to_ullong(str, &l) < 0)
e48f289d2e5b2546a2c5dcc90f7ab624cc58cca2Stephan Bosch l = 0;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen return t_strdup_printf("%llx", l);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen}
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainenstatic const char *
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenm_str_reverse(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen{
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen size_t len = strlen(str);
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen char *p, *rev;
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen
0175d37a5ae5a4d146ca41b684bd38d9b03683cbMartti Rannanjärvi rev = t_malloc_no0(len + 1);
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen rev[len] = '\0';
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen for (p = rev + len - 1; *str != '\0'; str++)
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen *p-- = *str;
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen return rev;
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen}
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainenstatic const char *m_str_hash(const char *str, struct var_expand_context *ctx)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen{
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen unsigned int value = str_hash(str);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen string_t *hash = t_str_new(20);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen if (ctx->width != 0) {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen value %= ctx->width;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx->width = 0;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen }
869b0fa6ef7fc0326c9f75ae449e5a9f97a796e2Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen str_printfa(hash, "%x", value);
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen while ((int)str_len(hash) < ctx->offset)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen str_insert(hash, 0, "0");
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi ctx->offset = 0;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen return str_c(hash);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen}
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainenstatic const char *
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainenm_str_newhash(const char *str, struct var_expand_context *ctx)
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen{
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen string_t *hash = t_str_new(20);
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen unsigned char result[MD5_RESULTLEN];
9217571849eb99d1003e150e3165aedf06b07521Timo Sirainen unsigned int i;
5ef75c870a01703df34ce44ab9a5324b2beabc78Timo Sirainen uint64_t value = 0;
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen md5_get_digest(str, strlen(str), result);
9217571849eb99d1003e150e3165aedf06b07521Timo Sirainen for (i = 0; i < sizeof(value); i++) {
9217571849eb99d1003e150e3165aedf06b07521Timo Sirainen value <<= 8;
9217571849eb99d1003e150e3165aedf06b07521Timo Sirainen value |= result[i];
9217571849eb99d1003e150e3165aedf06b07521Timo Sirainen }
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen if (ctx->width != 0) {
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen value %= ctx->width;
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen ctx->width = 0;
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen }
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen
9217571849eb99d1003e150e3165aedf06b07521Timo Sirainen str_printfa(hash, "%x", (unsigned int)value);
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen while ((int)str_len(hash) < ctx->offset)
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen str_insert(hash, 0, "0");
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi ctx->offset = 0;
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen return str_c(hash);
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen}
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainenstatic const char *
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainenm_str_md5(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen{
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen unsigned char digest[16];
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen md5_get_digest(str, strlen(str), digest);
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen return binary_to_hex(digest, sizeof(digest));
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen}
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainenstatic const char *
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainenm_str_ldap_dn(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen{
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen string_t *ret = t_str_new(256);
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen while (*str != '\0') {
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen if (*str == '.')
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen str_append(ret, ",dc=");
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen else
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen str_append_c(ret, *str);
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen str++;
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen }
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen return str_free_without_data(&ret);
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen}
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainenstatic const char *
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainenm_str_trim(const char *str, struct var_expand_context *ctx ATTR_UNUSED)
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen{
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen len = strlen(str);
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen while (len > 0 && i_isspace(str[len-1]))
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen len--;
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen return t_strndup(str, len);
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen}
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen#define MAX_MODIFIER_COUNT 10
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainenstatic const struct var_expand_modifier modifiers[] = {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'L', m_str_lcase },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'U', m_str_ucase },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'E', m_str_escape },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'X', m_str_hex },
8e0f89885f2ce60961da9ae2d96d71c7109e6032Timo Sirainen { 'R', m_str_reverse },
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen { 'H', m_str_hash },
e95bc848767afa2e52cb988a6d3f5e5cc5933885Timo Sirainen { 'N', m_str_newhash },
1036d2db2b718bdc5b10f0773dd01d62638e9ba9Timo Sirainen { 'M', m_str_md5 },
28a57cc7b6f29cc55a4a586c80902b21daf5d55bTimo Sirainen { 'D', m_str_ldap_dn },
546d3609e0811a147269ee9979eb90649445f5acTimo Sirainen { 'T', m_str_trim },
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen { '\0', NULL }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen};
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenstatic int
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenvar_expand_short(const struct var_expand_table *table, char key,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char **var_r, const char **error_r)
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen{
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi const struct var_expand_table *t;
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen if (table != NULL) {
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen for (t = table; !TABLE_LAST(t); t++) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (t->key == key) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = t->value != NULL ? t->value : "";
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 1;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen }
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen }
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen /* not found */
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (key == '%') {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = "%";
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 1;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (*error_r == NULL)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *error_r = t_strdup_printf("Unknown variable '%%%c'", key);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 0;
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen}
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomistatic int
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivar_expand_hash(struct var_expand_context *ctx,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const char *key, const char *field,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const char **result_r, const char **error_r)
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi{
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi enum {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi FORMAT_HEX,
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi FORMAT_HEX_UC,
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi FORMAT_BASE64
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } format = FORMAT_HEX;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const char *p = strchr(key, ';');
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const char *const *args = NULL;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const char *algo = key;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const char *value;
0306a3100b0fd42f00004bb728e2a9039e0a4846Aki Tuomi int ret;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (p != NULL) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi algo = t_strcut(key, ';');
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi args = t_strsplit(p+1, ",");
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const struct hash_method *method;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (strcmp(algo, "pkcs5") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi method = hash_method_lookup("sha256");
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else if ((method = hash_method_lookup(algo)) == NULL) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return 0;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi string_t *field_value = t_str_new(64);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi string_t *salt = t_str_new(64);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi string_t *tmp = t_str_new(method->digest_size);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if ((ret = var_expand_long(ctx, field, strlen(field),
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi &value, error_r)) < 1) {
0306a3100b0fd42f00004bb728e2a9039e0a4846Aki Tuomi return ret;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi str_append(field_value, value);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi /* default values */
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi unsigned int rounds = 1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi unsigned int truncbits = 0;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (strcmp(algo, "pkcs5") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi rounds = 2048;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi str_append(salt, field);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi while(args != NULL && *args != NULL) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const char *k = t_strcut(*args, '=');
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi const char *value = strchr(*args, '=');
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (value == NULL) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi args++;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi continue;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi value++;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (strcmp(k, "rounds") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (str_to_uint(value, &rounds)<0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *error_r = t_strdup_printf(
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "Cannot parse hash arguments:"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "'%s' is not number for rounds",
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi value);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return -1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (rounds < 1) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *error_r = t_strdup_printf(
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "Cannot parse hash arguments:"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "rounds must be at least 1");
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return -1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else if (strcmp(k, "truncate") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (str_to_uint(value, &truncbits)<0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *error_r = t_strdup_printf(
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "Cannot parse hash arguments:"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "'%s' is not number for truncbits",
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi value);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return -1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi truncbits = I_MIN(truncbits, method->digest_size*8);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else if (strcmp(k, "salt") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi str_truncate(salt, 0);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if (var_expand_with_funcs(salt, value, ctx->table,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx->func_table, ctx->context,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi error_r) < 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return -1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi break;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else if (strcmp(k, "format") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (strcmp(value, "hex") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi format = FORMAT_HEX;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else if (strcmp(value, "hexuc") == 0){
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi format = FORMAT_HEX_UC;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else if (strcmp(value, "base64") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi format = FORMAT_BASE64;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *error_r = t_strdup_printf(
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "Cannot parse hash arguments:"
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi "'%s' is not supported format",
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi value);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return -1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi args++;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi str_truncate(tmp, 0);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (strcmp(algo, "pkcs5") == 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (pkcs5_pbkdf(PKCS5_PBKDF2, method,
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi field_value->data, field_value->used,
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi salt->data, salt->used,
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi rounds, HMAC_MAX_CONTEXT_SIZE, tmp) != 0) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *error_r = "Cannot hash: PKCS5_PBKDF2 failed";
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return -1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi } else {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi void *context = t_malloc_no0(method->context_size);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi str_append_str(tmp, field_value);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi for(;rounds>0;rounds--) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi method->init(context);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (salt->used > 0)
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi method->loop(context, salt->data, salt->used);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi method->loop(context, tmp->data, tmp->used);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi unsigned char *digest =
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi buffer_get_modifiable_data(tmp, NULL);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi method->result(context, digest);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (tmp->used != method->digest_size)
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi buffer_set_used_size(tmp, method->digest_size);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi if (truncbits > 0)
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi buffer_truncate_rshift_bits(tmp, truncbits);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi switch(format) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi case FORMAT_HEX:
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *result_r = binary_to_hex(tmp->data, tmp->used);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return 1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi case FORMAT_HEX_UC:
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *result_r = binary_to_hex(tmp->data, tmp->used);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return 1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi case FORMAT_BASE64: {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi string_t *dest = t_str_new(64);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi base64_encode(tmp->data, tmp->used, dest);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi *result_r = str_c(dest);
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi return 1;
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi i_unreached();
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi}
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenstatic int
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainenvar_expand_func(const struct var_expand_func_table *func_table,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char *key, const char *data, void *context,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char **var_r, const char **error_r)
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen{
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen const char *value = NULL;
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen int ret;
654b46078129456bda90c5eb18014fb2858c302eTimo Sirainen
654b46078129456bda90c5eb18014fb2858c302eTimo Sirainen if (strcmp(key, "env") == 0) {
654b46078129456bda90c5eb18014fb2858c302eTimo Sirainen value = getenv(data);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = value != NULL ? value : "";
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 1;
654b46078129456bda90c5eb18014fb2858c302eTimo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (func_table != NULL) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen for (; func_table->key != NULL; func_table++) {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (strcmp(func_table->key, key) == 0) {
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen ret = func_table->func(data, context, &value, error_r);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = value != NULL ? value : "";
bcf1cf2afb9692b0db555e6ecf662a2fbd19793dTimo Sirainen return ret;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen }
654b46078129456bda90c5eb18014fb2858c302eTimo Sirainen }
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (*error_r == NULL)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *error_r = t_strdup_printf("Unknown variable '%%%s'", key);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = t_strdup_printf("UNSUPPORTED_VARIABLE_%s", key);
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 0;
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen}
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenstatic int
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivar_expand_try_extension(struct var_expand_context *ctx,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const char *key, const char *data,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const char **var_r, const char **error_r)
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi{
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi int ret;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const char *sep = strchr(key, ';');
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if (sep == NULL) sep = key + strlen(key);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi /* try with extensions */
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const struct var_expand_extension_func_table *f;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_foreach(&var_expand_extensions, f) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi /* ensure we won't match abbreviations */
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi size_t len = sep-key;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if (strncasecmp(key, f->key, len) == 0 && f->key[len] == '\0')
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi return f->func(ctx, key, data, var_r, error_r);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if ((ret = var_expand_func(ctx->func_table, key, data,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx->context, var_r, error_r)) == 0) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi *error_r = t_strdup_printf("Unknown variable '%%%s'", key);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi return ret;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi}
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomiint
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivar_expand_long(struct var_expand_context *ctx,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const void *key_start, size_t key_len,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const char **var_r, const char **error_r)
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen{
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi const struct var_expand_table *t;
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen const char *key, *value = NULL;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen int ret = 1;
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if (ctx->table != NULL) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi for (t = ctx->table; !TABLE_LAST(t); t++) {
93794594bc682b12353d2d0db08d91ae3e7c56c6Timo Sirainen if (t->long_key != NULL &&
93794594bc682b12353d2d0db08d91ae3e7c56c6Timo Sirainen strncmp(t->long_key, key_start, key_len) == 0 &&
93794594bc682b12353d2d0db08d91ae3e7c56c6Timo Sirainen t->long_key[key_len] == '\0') {
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = t->value != NULL ? t->value : "";
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return 1;
93794594bc682b12353d2d0db08d91ae3e7c56c6Timo Sirainen }
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen }
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen }
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen key = t_strndup(key_start, key_len);
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen /* built-in variables: */
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen switch (key_len) {
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen case 3:
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen if (strcmp(key, "pid") == 0)
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen value = my_pid;
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen else if (strcmp(key, "uid") == 0)
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen value = dec2str(geteuid());
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen else if (strcmp(key, "gid") == 0)
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen value = dec2str(getegid());
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen break;
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen case 8:
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen if (strcmp(key, "hostname") == 0)
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen value = my_hostname;
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen break;
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen }
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen if (value == NULL) {
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen const char *data = strchr(key, ':');
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen if (data != NULL)
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen key = t_strdup_until(key, data++);
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen else
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen data = "";
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ret = var_expand_try_extension(ctx, key, data, &value, error_r);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi if (ret <= 0 && value == NULL) {
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi value = "";
7c4af1fdcb1aa5ece9fd6c8a893789666ae29dbbAki Tuomi }
3fc62f5a9b1646f0e385f0708c652fbd8b944ba9Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *var_r = value;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return ret;
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen}
927d3977d5598f12ae18d4fa3f22b9e913f7dd46Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenint var_expand_with_funcs(string_t *dest, const char *str,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const struct var_expand_table *table,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const struct var_expand_func_table *func_table,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen void *context, const char **error_r)
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen{
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi const struct var_expand_modifier *m;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen const char *var;
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi struct var_expand_context ctx;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen const char *(*modifier[MAX_MODIFIER_COUNT])
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen (const char *, struct var_expand_context *);
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen const char *end;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen unsigned int i, modifier_count;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen size_t len;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen int ret, final_ret = 1;
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen *error_r = NULL;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&ctx);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx.table = table;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx.func_table = func_table;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx.context = context;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen for (; *str != '\0'; str++) {
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen if (*str != '%')
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen str_append_c(dest, *str);
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen else {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen int sign = 1;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen str++;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi /* reset per-field modifiers */
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx.offset = 0;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx.width = 0;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ctx.zero_padding = FALSE;
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen /* [<offset>.]<width>[<modifiers>]<variable> */
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen if (*str == '-') {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen sign = -1;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen str++;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (*str == '0') {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen ctx.zero_padding = TRUE;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str++;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen while (*str >= '0' && *str <= '9') {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width = ctx.width*10 + (*str - '0');
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen str++;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen if (*str == '.') {
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen ctx.offset = sign * ctx.width;
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen sign = 1;
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width = 0;
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen str++;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen /* if offset was prefixed with zero (or it was
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen plain zero), just ignore that. zero padding
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen is done with the width. */
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen ctx.zero_padding = FALSE;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen if (*str == '0') {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen ctx.zero_padding = TRUE;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen str++;
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen }
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen if (*str == '-') {
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen sign = -1;
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen str++;
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen }
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen while (*str >= '0' && *str <= '9') {
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width = ctx.width*10 + (*str - '0');
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen str++;
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen }
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen ctx.width = sign * ctx.width;
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen }
55de1a4d11765e795ec96fddd4858b188be4b892Timo Sirainen
2c2bcffb5d26ebf0c7cc0c6586feda4ce7967e98Aki Tuomi modifier_count = 0;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen while (modifier_count < MAX_MODIFIER_COUNT) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier[modifier_count] = NULL;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen for (m = modifiers; m->key != '\0'; m++) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (m->key == *str) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen /* @UNSAFE */
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier[modifier_count] =
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen m->func;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str++;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen break;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen if (modifier[modifier_count] == NULL)
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen break;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen modifier_count++;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen if (*str == '\0')
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen break;
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen var = NULL;
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen if (*str == '{' && (end = strchr(str, '}')) != NULL) {
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen /* %{long_key} */
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi unsigned int ctr = 1;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi bool escape = FALSE;
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi end = str;
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi while(*++end != '\0' && ctr > 0) {
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi if (!escape && *end == '\\') {
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi escape = TRUE;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi continue;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi }
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi if (escape) {
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi escape = FALSE;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi continue;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi }
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi if (*end == '{') ctr++;
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi if (*end == '}') ctr--;
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi }
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi if (ctr == 0)
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi /* it needs to come back a bit */
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi end--;
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi /* if there is no } it will consume rest of the
e0dddec702cceb77536a659c71b1973a71c09192Aki Tuomi string */
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen len = end - (str + 1);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ret = var_expand_long(&ctx, str+1, len,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen &var, error_r);
800bb686016278426c18f0d1529cf359ecb5f950Timo Sirainen i_assert(var != NULL);
800bb686016278426c18f0d1529cf359ecb5f950Timo Sirainen str = end;
7c3a801caa8daa9a7f57e61b4d1e63f02a51e7e4Timo Sirainen } else {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ret = var_expand_short(ctx.table, *str,
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi &var, error_r);
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen if (final_ret > ret)
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen final_ret = ret;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen if (var != NULL) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen for (i = 0; i < modifier_count; i++)
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen var = modifier[i](var, &ctx);
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen if (ctx.offset < 0) {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen /* if offset is < 0 then we want to
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen start at the end */
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen size_t len = strlen(var);
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen if (len > (size_t)-ctx.offset)
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen var += len + ctx.offset;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen } else {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen while (*var != '\0' && ctx.offset > 0) {
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen ctx.offset--;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen var++;
a40649829bce4c8de6210a2cb4a4b4cf5bb40da8Timo Sirainen }
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen }
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen if (ctx.width == 0)
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen str_append(dest, var);
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen else if (!ctx.zero_padding) {
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen if (ctx.width < 0)
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen ctx.width = strlen(var) - (-ctx.width);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen str_append_n(dest, var, ctx.width);
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen } else {
d35364f4d7d139b4150d290e14717e10f1ede4cdTimo Sirainen /* %05d -like padding. no truncation. */
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen ssize_t len = strlen(var);
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen while (len < ctx.width) {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str_append_c(dest, '0');
bb979386852c7689dc66c0fce03319382f66d501Timo Sirainen ctx.width--;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen str_append(dest, var);
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen }
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return final_ret;
4cb2599c5cdf27362a66ac475ce295409c093c92Timo Sirainen}
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainenint var_expand(string_t *dest, const char *str,
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen const struct var_expand_table *table, const char **error_r)
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen{
0f5dc4da3982053036be65190e44bf28a67b1ca2Timo Sirainen return var_expand_with_funcs(dest, str, table, NULL, NULL, error_r);
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen}
e130dc7c712a10215b1e6be56403bbb934826251Timo Sirainen
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainenstatic bool
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainenvar_get_key_range_full(const char *str, unsigned int *idx_r,
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen unsigned int *size_r)
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen{
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen const struct var_expand_modifier *m;
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen unsigned int i = 0;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen /* [<offset>.]<width>[<modifiers>]<variable> */
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen while ((str[i] >= '0' && str[i] <= '9') || str[i] == '-')
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen i++;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen if (str[i] == '.') {
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen i++;
6eb191b58bc8553a516bd1c9b0eccaa696d0f41fTimo Sirainen while ((str[i] >= '0' && str[i] <= '9') || str[i] == '-')
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen i++;
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen }
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen do {
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen for (m = modifiers; m->key != '\0'; m++) {
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen if (m->key == str[i]) {
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen i++;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen break;
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen }
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen }
7cd08c67fde5371f662d8c95b30c341741950420Timo Sirainen } while (m->key != '\0');
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen if (str[i] != '{') {
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen /* short key */
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen *idx_r = i;
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen *size_r = str[i] == '\0' ? 0 : 1;
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen return FALSE;
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen } else {
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi unsigned int depth = 1;
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi bool escape = FALSE;
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen /* long key */
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen *idx_r = ++i;
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen for (; str[i] != '\0'; i++) {
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi if (!escape && str[i] == '\\') {
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi escape = TRUE;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi continue;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi }
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi if (escape) {
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi escape = FALSE;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi continue;
f5d1cfca5073424be87c85e40e893cea49257b75Aki Tuomi }
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi if (str[i] == '{')
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi depth++;
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi if (str[i] == '}') {
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi if (--depth==0)
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi break;
20a8a12657a29df1fb397ae2892856f3726bb652Aki Tuomi }
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen }
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen *size_r = i - *idx_r;
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen return TRUE;
b58cb4b59ccd78ee1c3e0df0bc13c300d1bec380Timo Sirainen }
ee3cb11d230d549367a1213aefe4598345796256Timo Sirainen}
3e859421cc59d28d4ba99f32830e3d0531334813Timo Sirainen
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainenchar var_get_key(const char *str)
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen{
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen unsigned int idx, size;
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen if (var_get_key_range_full(str, &idx, &size))
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen return '{';
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen return str[idx];
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen}
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainenvoid var_get_key_range(const char *str, unsigned int *idx_r,
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen unsigned int *size_r)
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen{
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen (void)var_get_key_range_full(str, idx_r, size_r);
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen}
7a556ac46f1f51ee29bc8aa92b5ffe05b004a8b8Timo Sirainen
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainenstatic bool var_has_long_key(const char **str, const char *long_key)
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen{
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen const char *start, *end;
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen start = strchr(*str, '{');
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen i_assert(start != NULL);
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen end = strchr(++start, '}');
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen if (end == NULL)
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen return FALSE;
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen if (strncmp(start, long_key, end-start) == 0 &&
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen long_key[end-start] == '\0')
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen return TRUE;
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen *str = end;
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen return FALSE;
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen}
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainenbool var_has_key(const char *str, char key, const char *long_key)
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen{
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen char c;
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen for (; *str != '\0'; str++) {
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen if (*str == '%' && str[1] != '\0') {
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen str++;
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen c = var_get_key(str);
e539ff946adcbc68793adb6d9d84621dce3bf46bTimo Sirainen if (c == key && key != '\0')
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen return TRUE;
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen if (c == '{' && long_key != NULL) {
771178a5c5285aa596723591271c8936c4007f1bTimo Sirainen if (var_has_long_key(&str, long_key))
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen return TRUE;
f77ffa31038d46ca9c6d24d93e3d76c9aa8d4d0cTimo Sirainen }
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen }
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen }
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen return FALSE;
5daf9fa081859b99c5082b680f3f8a70b82a76f0Timo Sirainen}
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivoid var_expand_extensions_deinit(void)
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi{
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_free(&var_expand_extensions);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi}
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivoid var_expand_extensions_init(void)
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi{
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi i_array_init(&var_expand_extensions, 32);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi /* put all hash methods there */
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi for(const struct hash_method **meth = hash_methods;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi *meth != NULL;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi meth++) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi struct var_expand_extension_func_table *func =
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_append_space(&var_expand_extensions);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi func->key = (*meth)->name;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi func->func = var_expand_hash;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi /* pkcs5 */
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi struct var_expand_extension_func_table *func =
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_append_space(&var_expand_extensions);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi func->key = "pkcs5";
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi func->func = var_expand_hash;
b3e71425659780a58cba2f1d84eceef5b4616762Aki Tuomi
b3e71425659780a58cba2f1d84eceef5b4616762Aki Tuomi /* if */
b3e71425659780a58cba2f1d84eceef5b4616762Aki Tuomi func = array_append_space(&var_expand_extensions);
b3e71425659780a58cba2f1d84eceef5b4616762Aki Tuomi func->key = "if";
b3e71425659780a58cba2f1d84eceef5b4616762Aki Tuomi func->func = var_expand_if;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi}
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivoid
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivar_expand_register_func_array(const struct var_expand_extension_func_table *funcs)
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi{
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi for(const struct var_expand_extension_func_table *ptr = funcs;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ptr->key != NULL;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ptr++) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi i_assert(*ptr->key != '\0');
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_insert(&var_expand_extensions, 0, ptr, 1);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi}
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivoid
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomivar_expand_unregister_func_array(const struct var_expand_extension_func_table *funcs)
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi{
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi for(const struct var_expand_extension_func_table *ptr = funcs;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ptr->key != NULL;
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi ptr++) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi i_assert(ptr->func != NULL);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi for(unsigned int i = 0; i < array_count(&var_expand_extensions); i++) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi const struct var_expand_extension_func_table *func =
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_idx(&var_expand_extensions, i);
75a6a96fd561e133189e232cfa52ce57121a6d49Aki Tuomi if (strcasecmp(func->key, ptr->key) == 0) {
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi array_delete(&var_expand_extensions, i, 1);
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi }
5c00a22fcca7f68479a8768fec7ace7f679b344dAki Tuomi}
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomistruct var_expand_table *
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomivar_expand_merge_tables(pool_t pool, const struct var_expand_table *a,
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi const struct var_expand_table *b)
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi{
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi ARRAY(struct var_expand_table) table;
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi size_t a_size = var_expand_table_size(a);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi size_t b_size = var_expand_table_size(b);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi p_array_init(&table, pool, a_size + b_size + 1);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi for(size_t i=0; i<a_size; i++) {
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi struct var_expand_table *entry =
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi array_append_space(&table);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi entry->key = a[i].key;
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi entry->value = p_strdup(pool, a[i].value);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi entry->long_key = p_strdup(pool, a[i].long_key);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi }
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi for(size_t i=0; i<b_size; i++) {
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi struct var_expand_table *entry =
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi array_append_space(&table);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi entry->key = b[i].key;
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi entry->value = p_strdup(pool, b[i].value);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi entry->long_key = p_strdup(pool, b[i].long_key);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi }
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi array_append_zero(&table);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi return array_idx_modifiable(&table, 0);
857a9e1f1cf3a2241403bfb201421bb1a66038b1Aki Tuomi}