[Dovecot] [PATCH, RFC 4/13] OTP: extended response parser
Andrey Panin
pazke at donpac.ru
Mon Jun 26 15:58:03 EEST 2006
Parser for OTP extended response as defined by RFC 2243.
diff -urdpNX /usr/share/dontdiff -x Makefile dovecot.vanilla/src/lib-otp/otp-parse.c dovecot/src/lib-otp/otp-parse.c
--- dovecot.vanilla/src/lib-otp/otp-parse.c 1970-01-01 03:00:00.000000000 +0300
+++ dovecot/src/lib-otp/otp-parse.c 2006-06-23 13:44:31.213883208 +0400
@@ -0,0 +1,254 @@
+/*
+ * OTP extended response parser.
+ *
+ * Copyright (c) 2006 Andrey Panin <pazke at donpac.ru>
+ *
+ * This software is released under the MIT license.
+ */
+
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "lib.h"
+#include "buffer.h"
+#include "str.h"
+#include "strfuncs.h"
+#include "hex-binary.h"
+
+#include "otp.h"
+
+
+#define IS_LWS(c) ((c) == ' ' || (c) == '\t')
+
+static inline const char *otp_skip_lws(const char *data)
+{
+ while (*data && IS_LWS(*data))
+ data++;
+ return data;
+}
+
+static inline int otp_check_tail(const char *data)
+{
+ data = otp_skip_lws(data);
+
+ return *data != 0;
+}
+
+int otp_read_hex(const char *data, const char **endptr, unsigned char *hash)
+{
+ string_t *str;
+ buffer_t *buf;
+ int i = 0;
+
+ if (data == NULL)
+ return -1;
+
+ str = t_str_new(18);
+ buf = buffer_create_data(unsafe_data_stack_pool, hash, OTP_HASH_SIZE);
+
+ while (*data) {
+ char c = *data;
+
+ if (isxdigit(c)) {
+ str_append_c(str, c);
+ if (++i == OTP_HASH_SIZE * 2) {
+ data++;
+ break;
+ }
+ } else if (!IS_LWS(c)) {
+ if (endptr)
+ *endptr = data;
+ return -1;
+ }
+ data++;
+ }
+
+ if (endptr)
+ *endptr = data;
+
+ if (i < OTP_HASH_SIZE * 2)
+ return -1;
+
+ return hex_to_binary(str_c(str), buf);
+}
+
+#define add_word() do { \
+ tmp = otp_lookup_word(str_c(word)); \
+ buffer_append(buf, &tmp, sizeof(tmp)); \
+ count++; \
+} while (0)
+
+int otp_read_words(const char *data, const char **endptr, unsigned char *hash)
+{
+ int space = 0, len = 0, count = 0;
+ unsigned int parity = 0, bits[OTP_WORDS_NUMBER], tmp;
+ string_t *word;
+ buffer_t *buf;
+
+ if (data == NULL)
+ return -1;
+
+ word = t_str_new(8);
+
+ data = otp_skip_lws(data);
+
+ buf = buffer_create_data(pool_datastack_create(), bits, sizeof(bits));
+
+ for (; *data && (count < OTP_WORDS_NUMBER); data++) {
+ char c = *data;
+
+ if (space) {
+ if (IS_LWS(c))
+ continue;
+ else if (isalpha(c)) {
+ str_append_c(word, c);
+ space = 0;
+ len = 1;
+ continue;
+ }
+ } else {
+ if (isalpha(c)) {
+ if (len > OTP_MAX_WORD_LEN) {
+ count = 0;
+ break;
+ }
+ str_append_c(word, c);
+ continue;
+ } else if (IS_LWS(c)) {
+ add_word();
+ str_truncate(word, 0);
+ space = 1;
+ continue;
+ }
+ }
+ break;
+ }
+
+ if ((str_len(word) > 0) && (count == OTP_WORDS_NUMBER - 1))
+ add_word();
+
+ if (endptr)
+ *endptr = data;
+
+ if (count < OTP_WORDS_NUMBER)
+ return -1;
+
+ hash[0] = bits[0] >> 3;
+ hash[1] = ((bits[0] & 7) << 5) | (bits[1] >> 6);
+ hash[2] = ((bits[1] & 0x3f) << 2) | (bits[2] >> 9);
+ hash[3] = (bits[2] >> 1) & 0xff;
+ hash[4] = ((bits[2] & 3) << 7) | (bits[3] >> 4);
+ hash[5] = ((bits[3] & 15) << 4) | (bits[4] >> 7);
+ hash[6] = ((bits[4] & 0x7f) << 1) | (bits[5] >> 10);
+ hash[7] = (bits[5] >> 2) & 0xff;
+ parity = bits[5] & 3;
+
+ return otp_parity(hash) != parity;
+}
+
+int otp_read_new_params(const char *data, const char **endptr,
+ struct otp_state *state)
+{
+ const char *p, *s;
+ int i = 0;
+
+ s = p = data;
+
+ while ((*p != 0) && !IS_LWS(*p)) p++;
+ if (*p == 0)
+ return -1;
+
+ state->algo = digest_find(t_strdup_until(s, p++));
+ if (state->algo < 0)
+ return -2;
+
+ s = p;
+ state->seq = strtol(s, (char **) &p, 10);
+ if ((p == s) || !IS_LWS(*p))
+ return -3;
+ p++;
+
+ while (isalnum(*p) && (i < OTP_MAX_SEED_LEN))
+ state->seed[i++] = tolower(*p++);
+ state->seed[i] = 0;
+
+ *endptr = p;
+ return 0;
+}
+
+int otp_parse_response(const char *data, unsigned char *hash, int hex)
+{
+ const char *end;
+ int ret = hex ? otp_read_hex(data, &end, hash) :
+ otp_read_words(data, &end, hash);
+ if (ret < 0)
+ return ret;
+
+ return otp_check_tail(end);
+}
+
+int otp_parse_init_response(const char *data, struct otp_state *new_state,
+ unsigned char *hash, int hex, const char **error)
+{
+ const char *end;
+ int ret = hex ? otp_read_hex(data, &end, hash) :
+ otp_read_words(data, &end, hash);
+ if (ret < 0) {
+ *error = "invalid current OTP";
+ return ret;
+ }
+
+ end = otp_skip_lws(end);
+ if (*end++ != ':') {
+ *error = "missing colon";
+ return -1;
+ }
+
+ ret = otp_read_new_params(end, &end, new_state);
+ if (ret < 0) {
+ *error = "invalid OTP parameters";
+ return -1;
+ }
+
+ end = otp_skip_lws(end);
+ if (*end++ != ':') {
+ *error = "missing colon";
+ return -1;
+ }
+
+ ret = hex ? otp_read_hex(end, &end, new_state->hash) :
+ otp_read_words(end, &end, new_state->hash);
+ if (ret < 0) {
+ *error = "invalid new OTP";
+ return -1;
+ }
+
+ if (otp_check_tail(end) != 0) {
+ *error = "trailing garbage found";
+ return -1;
+ }
+
+ return 0;
+}
+
+int otp_parse_dbentry(const char *text, struct otp_state *state)
+{
+ const char *end;
+ int ret;
+
+ ret = otp_read_new_params(text, &end, state);
+ if (ret != 0)
+ return ret;
+
+ if (*end++ != ' ')
+ return -1;
+
+ return otp_read_hex(end, NULL, state->hash);
+}
+
+const char * otp_print_dbentry(const struct otp_state *state)
+{
+ return t_strdup_printf("%s %d %s %s", digest_name(state->algo),
+ state->seq, state->seed,
+ binary_to_hex(state->hash, 8));
+}
diff -urdpNX /usr/share/dontdiff -x Makefile dovecot.vanilla/src/lib-otp/otp-parse.h dovecot/src/lib-otp/otp-parse.h
--- dovecot.vanilla/src/lib-otp/otp-parse.h 1970-01-01 03:00:00.000000000 +0300
+++ dovecot/src/lib-otp/otp-parse.h 2006-06-23 13:44:31.213883208 +0400
@@ -0,0 +1,16 @@
+#ifndef __OTP_PARSE_H__
+#define __OTP_PARSE_H__
+
+int otp_read_hex(const char *data, const char **endptr, unsigned char *hash);
+int otp_read_words(const char *data, const char **endptr, unsigned char *hash);
+int otp_read_new_params(const char *data, const char **endptr,
+ struct otp_state *state);
+
+int otp_parse_response(const char *data, unsigned char *hash, int hex);
+int otp_parse_init_response(const char *data, struct otp_state *new_state,
+ unsigned char *hash, int hex, const char **error);
+
+int otp_parse_dbentry(const char *text, struct otp_state *state);
+const char * otp_print_dbentry(const struct otp_state *state);
+
+#endif /* __OTP_PARSE_H__ */
More information about the dovecot
mailing list