dovecot-2.0: Added hash formatter.
dovecot at dovecot.org
dovecot at dovecot.org
Sat Oct 2 14:34:04 EEST 2010
details: http://hg.dovecot.org/dovecot-2.0/rev/3bd4d0a65070
changeset: 12263:3bd4d0a65070
user: Timo Sirainen <tss at iki.fi>
date: Thu Sep 16 19:14:22 2010 +0100
description:
Added hash formatter.
diffstat:
src/lib/Makefile.am | 5 +
src/lib/hash-format.c | 228 +++++++++++++++++++++++++++++++++++++++++++++
src/lib/hash-format.h | 19 +++
src/lib/hash-method.c | 68 +++++++++++++
src/lib/hash-method.h | 21 ++++
src/lib/md4.c | 24 ++++
src/lib/md4.h | 4 +
src/lib/md5.c | 24 ++++
src/lib/md5.h | 4 +
src/lib/sha1.c | 24 ++++
src/lib/sha1.h | 4 +
src/lib/sha2.c | 48 +++++++++
src/lib/sha2.h | 5 +
src/lib/test-hash-format.c | 54 ++++++++++
src/lib/test-lib.c | 1 +
src/lib/test-lib.h | 1 +
16 files changed, 534 insertions(+), 0 deletions(-)
diffs (truncated from 686 to 300 lines):
diff -r e4babf5f7eea -r 3bd4d0a65070 src/lib/Makefile.am
--- a/src/lib/Makefile.am Thu Aug 26 20:07:35 2010 +0100
+++ b/src/lib/Makefile.am Thu Sep 16 19:14:22 2010 +0100
@@ -36,6 +36,8 @@
file-lock.c \
file-set-size.c \
hash.c \
+ hash-format.c \
+ hash-method.c \
hash2.c \
hex-binary.c \
hex-dec.c \
@@ -146,6 +148,8 @@
file-set-size.h \
fsync-mode.h \
hash.h \
+ hash-format.h \
+ hash-method.h \
hash2.h \
hex-binary.h \
hex-dec.h \
@@ -230,6 +234,7 @@
test-bsearch-insert-pos.c \
test-buffer.c \
test-crc32.c \
+ test-hash-format.c \
test-hex-binary.c \
test-istream-concat.c \
test-istream-crlf.c \
diff -r e4babf5f7eea -r 3bd4d0a65070 src/lib/hash-format.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/hash-format.c Thu Sep 16 19:14:22 2010 +0100
@@ -0,0 +1,228 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "base64.h"
+#include "hex-binary.h"
+#include "str.h"
+#include "hash-method.h"
+#include "hash-format.h"
+
+enum hash_encoding {
+ HASH_ENCODING_HEX,
+ HASH_ENCODING_HEX_SHORT,
+ HASH_ENCODING_BASE64
+};
+
+struct hash_format_list {
+ struct hash_format_list *next;
+
+ const struct hash_method *method;
+ void *context;
+ unsigned int bits;
+ enum hash_encoding encoding;
+};
+
+struct hash_format {
+ pool_t pool;
+ const char *str;
+
+ struct hash_format_list *list, **pos;
+};
+
+static int
+hash_format_parse(const char *str, unsigned int *idxp,
+ const struct hash_method **method_r,
+ unsigned int *bits_r, const char **error_r)
+{
+ const char *name, *end, *bitsp;
+ unsigned int bits, i = *idxp;
+
+ /* we should have "hash_name}" or "hash_name:bits}" */
+ end = strchr(str+i, '}');
+ if (end == NULL) {
+ *error_r = "Missing '}'";
+ return -1;
+ }
+ *idxp = end - str;
+ name = t_strdup_until(str+i, end);
+
+ bitsp = strchr(name, ':');
+ if (bitsp != NULL)
+ name = t_strdup_until(name, bitsp++);
+
+ *method_r = hash_method_lookup(name);
+ if (*method_r == NULL) {
+ *error_r = t_strconcat("Unknown hash method: ", name, NULL);
+ return -1;
+ }
+
+ bits = (*method_r)->digest_size * 8;
+ if (bitsp != NULL) {
+ if (str_to_uint(bitsp, &bits) < 0 ||
+ bits == 0 || bits > (*method_r)->digest_size*8) {
+ *error_r = t_strconcat("Invalid :bits number: ",
+ bitsp, NULL);
+ return -1;
+ }
+ if ((bits % 8) != 0) {
+ *error_r = t_strconcat(
+ "Currently :bits must be divisible by 8: ",
+ bitsp, NULL);
+ return -1;
+ }
+ }
+ *bits_r = bits;
+ return 0;
+}
+
+static int
+hash_format_string_analyze(struct hash_format *format, const char *str,
+ const char **error_r)
+{
+ struct hash_format_list *list;
+ unsigned int i;
+
+ for (i = 0; str[i] != '\0'; i++) {
+ if (str[i] != '%')
+ continue;
+ i++;
+
+ list = p_new(format->pool, struct hash_format_list, 1);
+ list->encoding = HASH_ENCODING_HEX;
+ *format->pos = list;
+ format->pos = &list->next;
+
+ if (str[i] == 'B') {
+ list->encoding = HASH_ENCODING_BASE64;
+ i++;
+ } else if (str[i] == 'X') {
+ list->encoding = HASH_ENCODING_HEX_SHORT;
+ i++;
+ }
+ if (str[i++] != '{') {
+ *error_r = "No '{' after '%'";
+ return -1;
+ }
+ if (hash_format_parse(str, &i, &list->method,
+ &list->bits, error_r) < 0)
+ return -1;
+ list->context = p_malloc(format->pool,
+ list->method->context_size);
+ list->method->init(list->context);
+ }
+ return 0;
+}
+
+int hash_format_init(const char *format_string, struct hash_format **format_r,
+ const char **error_r)
+{
+ struct hash_format *format;
+ pool_t pool;
+ int ret;
+
+ pool = pool_alloconly_create("hash format", 1024);
+ format = p_new(pool, struct hash_format, 1);
+ format->pool = pool;
+ format->str = p_strdup(pool, format_string);
+ format->pos = &format->list;
+ T_BEGIN {
+ ret = hash_format_string_analyze(format, format_string,
+ error_r);
+ if (ret < 0)
+ *error_r = p_strdup(format->pool, *error_r);
+ } T_END;
+ if (ret < 0) {
+ *error_r = t_strdup(*error_r);
+ return -1;
+ }
+ *format_r = format;
+ return 0;
+}
+
+void hash_format_loop(struct hash_format *format,
+ const void *data, size_t size)
+{
+ struct hash_format_list *list;
+
+ for (list = format->list; list != NULL; list = list->next)
+ list->method->loop(list->context, data, size);
+}
+
+static void
+hash_format_digest(string_t *dest, const struct hash_format_list *list,
+ const unsigned char *digest)
+{
+ unsigned int i, orig_len, size = list->bits / 8;
+
+ i_assert(list->bits % 8 == 0);
+
+ switch (list->encoding) {
+ case HASH_ENCODING_HEX:
+ binary_to_hex_append(dest, digest, size);
+ break;
+ case HASH_ENCODING_HEX_SHORT:
+ orig_len = str_len(dest);
+ binary_to_hex_append(dest, digest, size);
+ /* drop leading zeros, except if it's the only one */
+ for (i = orig_len; i < str_len(dest); i++) {
+ if (str_data(dest)[i] != '0')
+ break;
+ }
+ if (i == str_len(dest)) i--;
+ str_delete(dest, orig_len, i-orig_len);
+ break;
+ case HASH_ENCODING_BASE64:
+ orig_len = str_len(dest);
+ base64_encode(digest, size, dest);
+ /* drop trailing '=' chars */
+ while (str_len(dest) > orig_len &&
+ str_data(dest)[str_len(dest)-1] == '=')
+ str_truncate(dest, str_len(dest)-1);
+ break;
+ }
+}
+
+void hash_format_deinit(struct hash_format **_format, string_t *dest)
+{
+ struct hash_format *format = *_format;
+ struct hash_format_list *list;
+ const char *p;
+ unsigned char *digest;
+ unsigned int i, max_digest_size = 0;
+
+ *_format = NULL;
+
+ for (list = format->list; list != NULL; list = list->next) {
+ if (max_digest_size < list->method->digest_size)
+ max_digest_size = list->method->digest_size;
+ }
+ digest = p_malloc(format->pool, max_digest_size);
+
+ list = format->list;
+ for (i = 0; format->str[i] != '\0'; i++) {
+ if (format->str[i] != '%') {
+ str_append_c(dest, format->str[i]);
+ continue;
+ }
+
+ /* we already verified that the string is ok */
+ i_assert(list != NULL);
+ list->method->result(list->context, digest);
+ hash_format_digest(dest, list, digest);
+ list = list->next;
+
+ p = strchr(format->str+i, '}');
+ i_assert(p != NULL);
+ i = p - format->str;
+ }
+
+ pool_unref(&format->pool);
+}
+
+void hash_format_deinit_free(struct hash_format **_format)
+{
+ struct hash_format *format = *_format;
+
+ *_format = NULL;
+ pool_unref(&format->pool);
+}
diff -r e4babf5f7eea -r 3bd4d0a65070 src/lib/hash-format.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/hash-format.h Thu Sep 16 19:14:22 2010 +0100
@@ -0,0 +1,19 @@
+#ifndef HASH_FORMAT_H
+#define HASH_FORMAT_H
+
+struct hash_format;
+
+/* Initialize formatting hash. Format can contain text with %{sha1} style
+ variables. Each hash hash can be also truncated by specifying the number
+ of bits to truncate to, such as %{sha1:80}. */
+int hash_format_init(const char *format_string, struct hash_format **format_r,
+ const char **error_r);
+/* Add more data to hash. */
+void hash_format_loop(struct hash_format *format,
+ const void *data, size_t size);
+/* Write the hash into given string and free used memory. */
+void hash_format_deinit(struct hash_format **format, string_t *dest);
+/* Free used memory without writing to string. */
+void hash_format_deinit_free(struct hash_format **format);
+
+#endif
diff -r e4babf5f7eea -r 3bd4d0a65070 src/lib/hash-method.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/hash-method.c Thu Sep 16 19:14:22 2010 +0100
@@ -0,0 +1,68 @@
+/* Copyright (c) 2010 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "md4.h"
+#include "md5.h"
+#include "sha1.h"
+#include "sha2.h"
+#include "hash-method.h"
+
+const struct hash_method *hash_method_lookup(const char *name)
+{
+ unsigned int i;
More information about the dovecot-cvs
mailing list