123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703 |
- /* This file is copied from the libsrs2 sources */
- /* Modified by Timo Röhling <timo.roehling@gmx.de> */
-
- /* Copyright (c) 2004 Shevek (srs@anarres.org)
- * All rights reserved.
- *
- * This file is a part of libsrs2 from http://www.libsrs2.org/
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, under the terms of either the GNU General Public
- * License version 2 or the BSD license, at the discretion of the
- * user. Copies of these licenses have been included in the libsrs2
- * distribution. See the the file called LICENSE for more
- * information.
- */
-
- #undef USE_OPENSSL
-
- #include <stdarg.h>
- #include <string.h> /* memcpy, strcpy, memset */
- #ifdef HAVE_ALLOCA_H
- #include <alloca.h>
- #endif
-
- #ifdef USE_OPENSSL
- #include <openssl/hmac.h>
- #endif
-
- #include "srs2.h"
-
-
- #ifndef EVP_MAX_MD_SIZE
- #define EVP_MAX_MD_SIZE (16+20) /* The SSLv3 md5+sha1 type */
- #endif
-
- #ifndef HAVE_STRCASECMP
- # ifdef HAVE__STRICMP
- # define strcasecmp _stricmp
- # endif
- #endif
-
- #ifndef HAVE_STRNCASECMP
- # ifdef HAVE__STRNICMP
- # define strncasecmp _strnicmp
- # endif
- #endif
-
- /* Use this */
- #define STRINGP(s) ((s != NULL) && (*(s) != '\0'))
-
- static const char *srs_separators = "=-+";
-
- static srs_malloc_t srs_f_malloc = malloc;
- static srs_realloc_t srs_f_realloc = realloc;
- static srs_free_t srs_f_free = free;
-
- int
- srs_set_malloc(srs_malloc_t m, srs_realloc_t r, srs_free_t f)
- {
- srs_f_malloc = m;
- srs_f_realloc = r;
- srs_f_free = f;
- return SRS_SUCCESS;
- }
-
- const char *
- srs_strerror(int code)
- {
- switch (code) {
- /* Simple errors */
- case SRS_SUCCESS:
- return "Success";
- case SRS_ENOTSRSADDRESS:
- return "Not an SRS address.";
-
- /* Config errors */
- case SRS_ENOSECRETS:
- return "No secrets in SRS configuration.";
- case SRS_ESEPARATORINVALID:
- return "Invalid separator suggested.";
-
- /* Input errors */
- case SRS_ENOSENDERATSIGN:
- return "No at sign in sender address";
- case SRS_EBUFTOOSMALL:
- return "Buffer too small.";
-
- /* Syntax errors */
- case SRS_ENOSRS0HOST:
- return "No host in SRS0 address.";
- case SRS_ENOSRS0USER:
- return "No user in SRS0 address.";
- case SRS_ENOSRS0HASH:
- return "No hash in SRS0 address.";
- case SRS_ENOSRS0STAMP:
- return "No timestamp in SRS0 address.";
- case SRS_ENOSRS1HOST:
- return "No host in SRS1 address.";
- case SRS_ENOSRS1USER:
- return "No user in SRS1 address.";
- case SRS_ENOSRS1HASH:
- return "No hash in SRS1 address.";
- case SRS_EBADTIMESTAMPCHAR:
- return "Bad base32 character in timestamp.";
- case SRS_EHASHTOOSHORT:
- return "Hash too short in SRS address.";
-
- /* SRS errors */
- case SRS_ETIMESTAMPOUTOFDATE:
- return "Time stamp out of date.";
- case SRS_EHASHINVALID:
- return "Hash invalid in SRS address.";
-
- default:
- return "Unknown error in SRS library.";
- }
- }
-
- srs_t *
- srs_new()
- {
- srs_t *srs = (srs_t *)srs_f_malloc(sizeof(srs_t));
- srs_init(srs);
- return srs;
- }
-
- void
- srs_init(srs_t *srs)
- {
- memset(srs, 0, sizeof(srs_t));
- srs->secrets = NULL;
- srs->numsecrets = 0;
- srs->separator = '=';
- srs->maxage = 21;
- srs->hashlength = 4;
- srs->hashmin = srs->hashlength;
- srs->alwaysrewrite = FALSE;
- }
-
- void
- srs_free(srs_t *srs)
- {
- int i;
- for (i = 0; i < srs->numsecrets; i++) {
- memset(srs->secrets[i], 0, strlen(srs->secrets[i]));
- srs_f_free(srs->secrets[i]);
- srs->secrets[i] = 0;
- }
- srs_f_free(srs);
- }
-
- int
- srs_add_secret(srs_t *srs, const char *secret)
- {
- int newlen = (srs->numsecrets + 1) * sizeof(char *);
- srs->secrets = (char **)srs_f_realloc(srs->secrets, newlen);
- srs->secrets[srs->numsecrets++] = strdup(secret);
- return SRS_SUCCESS;
- }
-
- const char *
- srs_get_secret(srs_t *srs, int idx)
- {
- if (idx < srs->numsecrets)
- return srs->secrets[idx];
- return NULL;
- }
-
- #define SRS_PARAM_DEFINE(n, t) \
- int srs_set_ ## n (srs_t *srs, t value) { \
- srs->n = value; \
- return SRS_SUCCESS; \
- } \
- t srs_get_ ## n (srs_t *srs) { \
- return srs->n; \
- }
-
- int
- srs_set_separator(srs_t *srs, char value)
- {
- if (strchr(srs_separators, value) == NULL)
- return SRS_ESEPARATORINVALID;
- srs->separator = value;
- return SRS_SUCCESS;
- }
-
- char
- srs_get_separator(srs_t *srs)
- {
- return srs->separator;
- }
-
- SRS_PARAM_DEFINE(maxage, int)
- /* XXX Check hashlength >= hashmin */
- SRS_PARAM_DEFINE(hashlength, int)
- SRS_PARAM_DEFINE(hashmin, int)
- SRS_PARAM_DEFINE(alwaysrewrite, srs_bool)
- SRS_PARAM_DEFINE(noforward, srs_bool)
- SRS_PARAM_DEFINE(noreverse, srs_bool)
-
- /* Don't mess with these unless you know what you're doing well
- * enough to rewrite the timestamp functions. These are based on
- * a 2 character timestamp. Changing these in the wild is probably
- * a bad idea. */
- #define SRS_TIME_PRECISION (60 * 60 * 24) /* One day */
- #define SRS_TIME_BASEBITS 5 /* 2^5 = 32 = strlen(CHARS) */
- /* This had better be a real variable since we do arithmethic
- * with it. */
- const char *SRS_TIME_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
- #define SRS_TIME_SIZE 2
- #define SRS_TIME_SLOTS (1<<(SRS_TIME_BASEBITS<<(SRS_TIME_SIZE-1)))
-
- int
- srs_timestamp_create(srs_t *srs __attribute__((unused)), char *buf, time_t now)
- {
- now = now / SRS_TIME_PRECISION;
- buf[1] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
- now = now >> SRS_TIME_BASEBITS;
- buf[0] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
- buf[2] = '\0';
- return SRS_SUCCESS;
- }
-
- int
- srs_timestamp_check(srs_t *srs, const char *stamp)
- {
- const char *sp;
- char *bp;
- int off;
- time_t now;
- time_t then;
-
- /* We had better go around this loop exactly twice! */
- then = 0;
- for (sp = stamp; *sp; sp++) {
- bp = strchr(SRS_TIME_BASECHARS, toupper(*sp));
- if (bp == NULL)
- return SRS_EBADTIMESTAMPCHAR;
- off = bp - SRS_TIME_BASECHARS;
- then = (then << SRS_TIME_BASEBITS) | off;
- }
-
- time(&now);
- now = (now / SRS_TIME_PRECISION) % SRS_TIME_SLOTS;
- while (now < then)
- now = now + SRS_TIME_SLOTS;
-
- if (now <= then + srs->maxage)
- return SRS_SUCCESS;
- return SRS_ETIMESTAMPOUTOFDATE;
- }
-
- const char *SRS_HASH_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
-
- static void
- srs_hash_create_v(srs_t *srs, int idx, char *buf, int nargs, va_list ap)
- {
- #ifdef USE_OPENSSL
- HMAC_CTX ctx;
- int srshashlen;
- char srshash[EVP_MAX_MD_SIZE + 1];
- #else
- srs_hmac_ctx_t ctx;
- char srshash[SHA_DIGESTSIZE + 1];
- #endif
- char *secret;
- char *data;
- int len;
- char *lcdata;
- unsigned char *hp;
- char *bp;
- int i;
- int j;
-
- secret = srs->secrets[idx];
-
- #ifdef USE_OPENSSL
- HMAC_CTX_init(&ctx);
- HMAC_Init(&ctx, secret, strlen(secret), EVP_sha1());
- #else
- srs_hmac_init(&ctx, secret, strlen(secret));
- #endif
-
- for (i = 0; i < nargs; i++) {
- data = va_arg(ap, char *);
- len = strlen(data);
- lcdata = alloca(len + 1);
- for (j = 0; j < len; j++) {
- if (isupper(data[j]))
- lcdata[j] = tolower(data[j]);
- else
- lcdata[j] = data[j];
- }
- #ifdef USE_OPENSSL
- HMAC_Update(&ctx, lcdata, len);
- #else
- srs_hmac_update(&ctx, lcdata, len);
- #endif
- }
-
- #ifdef USE_OPENSSL
- HMAC_Final(&ctx, srshash, &srshashlen);
- HMAC_CTX_cleanup(&ctx);
- srshash[EVP_MAX_MD_SIZE] = '\0';
- #else
- srs_hmac_fini(&ctx, srshash);
- srshash[SHA_DIGESTSIZE] = '\0';
- #endif
-
-
- /* A little base64 encoding. Just a little. */
- hp = (unsigned char *)srshash;
- bp = buf;
- for (i = 0; i < srs->hashlength; i++) {
- switch (i & 0x03) {
- default: /* NOTREACHED */
- case 0:
- j = (*hp >> 2);
- break;
- case 1:
- j = ((*hp & 0x03) << 4) |
- ((*(hp + 1) & 0xF0) >> 4);
- hp++;
- break;
- case 2:
- j = ((*hp & 0x0F) << 2) |
- ((*(hp + 1) & 0xC0) >> 6);
- hp++;
- break;
- case 3:
- j = (*hp++ & 0x3F);
- break;
- }
- *bp++ = SRS_HASH_BASECHARS[j];
- }
-
- *bp = '\0';
- buf[srs->hashlength] = '\0';
- }
-
- int
- srs_hash_create(srs_t *srs, char *buf, int nargs, ...)
- {
- va_list ap;
-
- if (srs->numsecrets == 0)
- return SRS_ENOSECRETS;
- if (srs->secrets == NULL)
- return SRS_ENOSECRETS;
- if (srs->secrets[0] == NULL)
- return SRS_ENOSECRETS;
-
- va_start(ap, nargs);
- srs_hash_create_v(srs, 0, buf, nargs, ap);
- va_end(ap);
-
- return SRS_SUCCESS;
- }
-
- int
- srs_hash_check(srs_t *srs, char *hash, int nargs, ...)
- {
- va_list ap;
- char *srshash;
- char *tmp;
- int len;
- int i;
-
- len = strlen(hash);
- if (len < srs->hashmin)
- return SRS_EHASHTOOSHORT;
- if (len < srs->hashlength) {
- tmp = alloca(srs->hashlength + 1);
- strncpy(tmp, hash, srs->hashlength);
- tmp[srs->hashlength] = '\0';
- hash = tmp;
- len = srs->hashlength;
- }
-
- for (i = 0; i < srs->numsecrets; i++) {
- va_start(ap, nargs);
- srshash = alloca(srs->hashlength + 1);
- srs_hash_create_v(srs, i, srshash, nargs, ap);
- va_end(ap);
- if (strncasecmp(hash, srshash, len) == 0)
- return SRS_SUCCESS;
- }
-
- return SRS_EHASHINVALID;
- }
-
- int
- srs_compile_shortcut(srs_t *srs,
- char *buf, int buflen,
- char *sendhost, char *senduser,
- const char *aliashost) {
- char *srshash;
- char srsstamp[SRS_TIME_SIZE + 1];
- int len;
- int ret;
-
- /* This never happens if we get called from guarded() */
- if ((strncasecmp(senduser, SRS0TAG, 4) == 0) &&
- (strchr(srs_separators, senduser[4]) != NULL)) {
- sendhost = senduser + 5;
- if (*sendhost == '\0')
- return SRS_ENOSRS0HOST;
- senduser = strchr(sendhost, SRSSEP);
- if ((senduser == NULL) || (*senduser == '\0'))
- return SRS_ENOSRS0USER;
- }
-
- len = strlen(SRS0TAG) + 1 +
- srs->hashlength + 1 +
- SRS_TIME_SIZE + 1 +
- strlen(sendhost) + 1 + strlen(senduser)
- + 1 + strlen(aliashost);
- if (len >= buflen)
- return SRS_EBUFTOOSMALL;
-
- ret = srs_timestamp_create(srs, srsstamp, time(NULL));
- if (ret != SRS_SUCCESS)
- return ret;
- srshash = alloca(srs->hashlength + 1);
- ret = srs_hash_create(srs, srshash,3, srsstamp, sendhost, senduser);
- if (ret != SRS_SUCCESS)
- return ret;
-
- sprintf(buf, SRS0TAG "%c%s%c%s%c%s%c%s@%s", srs->separator,
- srshash, SRSSEP, srsstamp, SRSSEP,
- sendhost, SRSSEP, senduser,
- aliashost);
-
- return SRS_SUCCESS;
- }
-
- int
- srs_compile_guarded(srs_t *srs,
- char *buf, int buflen,
- char *sendhost, char *senduser,
- const char *aliashost) {
- char *srshost;
- char *srsuser;
- char *srshash;
- int len;
- int ret;
-
- if ((strncasecmp(senduser, SRS1TAG, 4) == 0) &&
- (strchr(srs_separators, senduser[4]) != NULL)) {
- /* Used as a temporary convenience var */
- srshash = senduser + 5;
- if (*srshash == '\0')
- return SRS_ENOSRS1HASH;
- /* Used as a temporary convenience var */
- srshost = strchr(srshash, SRSSEP);
- if (!STRINGP(srshost))
- return SRS_ENOSRS1HOST;
- *srshost++ = '\0';
- srsuser = strchr(srshost, SRSSEP);
- if (!STRINGP(srsuser))
- return SRS_ENOSRS1USER;
- *srsuser++ = '\0';
- srshash = alloca(srs->hashlength + 1);
- ret = srs_hash_create(srs, srshash, 2, srshost, srsuser);
- if (ret != SRS_SUCCESS)
- return ret;
- len = strlen(SRS1TAG) + 1 +
- srs->hashlength + 1 +
- strlen(srshost) + 1 + strlen(srsuser)
- + 1 + strlen(aliashost);
- if (len >= buflen)
- return SRS_EBUFTOOSMALL;
- sprintf(buf, SRS1TAG "%c%s%c%s%c%s@%s", srs->separator,
- srshash, SRSSEP,
- srshost, SRSSEP, srsuser,
- aliashost);
- return SRS_SUCCESS;
- }
- else if ((strncasecmp(senduser, SRS0TAG, 4) == 0) &&
- (strchr(srs_separators, senduser[4]) != NULL)) {
- srsuser = senduser + 4;
- srshost = sendhost;
- srshash = alloca(srs->hashlength + 1);
- ret = srs_hash_create(srs, srshash, 2, srshost, srsuser);
- if (ret != SRS_SUCCESS)
- return ret;
- len = strlen(SRS1TAG) + 1 +
- srs->hashlength + 1 +
- strlen(srshost) + 1 + strlen(srsuser)
- + 1 + strlen(aliashost);
- if (len >= buflen)
- return SRS_EBUFTOOSMALL;
- sprintf(buf, SRS1TAG "%c%s%c%s%c%s@%s", srs->separator,
- srshash, SRSSEP,
- srshost, SRSSEP, srsuser,
- aliashost);
- }
- else {
- return srs_compile_shortcut(srs, buf, buflen,
- sendhost, senduser, aliashost);
- }
-
- return SRS_SUCCESS;
- }
-
- int
- srs_parse_shortcut(srs_t *srs, char *buf, unsigned buflen, char *senduser)
- {
- char *srshash;
- char *srsstamp;
- char *srshost;
- char *srsuser;
- int ret;
-
- if (strncasecmp(senduser, SRS0TAG, 4) == 0) {
- srshash = senduser + 5;
- if (!STRINGP(srshash))
- return SRS_ENOSRS0HASH;
- srsstamp = strchr(srshash, SRSSEP);
- if (!STRINGP(srsstamp))
- return SRS_ENOSRS0STAMP;
- *srsstamp++ = '\0';
- srshost = strchr(srsstamp, SRSSEP);
- if (!STRINGP(srshost))
- return SRS_ENOSRS0HOST;
- *srshost++ = '\0';
- srsuser = strchr(srshost, SRSSEP);
- if (!STRINGP(srsuser))
- return SRS_ENOSRS0USER;
- *srsuser++ = '\0';
- ret = srs_timestamp_check(srs, srsstamp);
- if (ret != SRS_SUCCESS)
- return ret;
- ret = srs_hash_check(srs, srshash, 3, srsstamp,
- srshost, srsuser);
- if (ret != SRS_SUCCESS)
- return ret;
- snprintf(buf, buflen, "%s@%s", srsuser, srshost);
- return SRS_SUCCESS;
- }
-
- return SRS_ENOTSRSADDRESS;
- }
-
- int
- srs_parse_guarded(srs_t *srs, char *buf, int buflen, char *senduser)
- {
- char *srshash;
- char *srshost;
- char *srsuser;
- int ret;
-
- if (strncasecmp(senduser, SRS1TAG, 4) == 0) {
- srshash = senduser + 5;
- if (!STRINGP(srshash))
- return SRS_ENOSRS1HASH;
- srshost = strchr(srshash, SRSSEP);
- if (!STRINGP(srshost))
- return SRS_ENOSRS1HOST;
- *srshost++ = '\0';
- srsuser = strchr(srshost, SRSSEP);
- if (!STRINGP(srsuser))
- return SRS_ENOSRS1USER;
- *srsuser++ = '\0';
- ret = srs_hash_check(srs, srshash, 2, srshost, srsuser);
- if (ret != SRS_SUCCESS)
- return ret;
- sprintf(buf, SRS0TAG "%s@%s", srsuser, srshost);
- return SRS_SUCCESS;
- }
- else {
- return srs_parse_shortcut(srs, buf, buflen, senduser);
- }
- }
-
- int
- srs_forward(srs_t *srs, char *buf, unsigned buflen,
- const char *sender, const char *alias)
- {
- char *senduser;
- char *sendhost;
- char *tmp;
- unsigned len;
-
- if (srs->noforward)
- return SRS_ENOTREWRITTEN;
-
- /* This is allowed to be a plain domain */
- while ((tmp = strchr(alias, '@')) != NULL)
- alias = tmp + 1;
-
- tmp = strchr(sender, '@');
- if (tmp == NULL)
- return SRS_ENOSENDERATSIGN;
- sendhost = tmp + 1;
-
- len = strlen(sender);
-
- if (! srs->alwaysrewrite) {
- if (strcasecmp(sendhost, alias) == 0) {
- if (strlen(sender) >= buflen)
- return SRS_EBUFTOOSMALL;
- strcpy(buf, sender);
- return SRS_SUCCESS;
- }
- }
-
- /* Reconstruct the whole show into our alloca() buffer. */
- senduser = alloca(len + 1);
- strcpy(senduser, sender);
- tmp = (senduser + (tmp - sender));
- sendhost = tmp + 1;
- *tmp = '\0';
-
- return srs_compile_guarded(srs, buf, buflen,
- sendhost, senduser, alias);
- }
-
- int
- srs_forward_alloc(srs_t *srs, char **sptr,
- const char *sender, const char *alias)
- {
- char *buf;
- int slen;
- int alen;
- int len;
- int ret;
-
- if (srs->noforward)
- return SRS_ENOTREWRITTEN;
-
- slen = strlen(sender);
- alen = strlen(alias);
-
- /* strlen(SRSxTAG) + strlen("====+@") < 64 */
- len = slen + alen + srs->hashlength + SRS_TIME_SIZE + 64;
- buf = (char *)srs_f_malloc(len);
-
- ret = srs_forward(srs, buf, len, sender, alias);
-
- if (ret == SRS_SUCCESS)
- *sptr = buf;
- else
- srs_f_free(buf);
-
- return ret;
- }
-
- int
- srs_reverse(srs_t *srs, char *buf, unsigned buflen, const char *sender)
- {
- char *senduser;
- char *tmp;
- unsigned len;
-
- if (!SRS_IS_SRS_ADDRESS(sender))
- return SRS_ENOTSRSADDRESS;
-
- if (srs->noreverse)
- return SRS_ENOTREWRITTEN;
-
- len = strlen(sender);
- if (len >= buflen)
- return SRS_EBUFTOOSMALL;
- senduser = alloca(len + 1);
- strcpy(senduser, sender);
-
- /* We don't really care about the host for reversal. */
- tmp = strchr(senduser, '@');
- if (tmp != NULL)
- *tmp = '\0';
- return srs_parse_guarded(srs, buf, buflen, senduser);
- }
-
- int
- srs_reverse_alloc(srs_t *srs, char **sptr, const char *sender)
- {
- char *buf;
- int len;
- int ret;
-
- *sptr = NULL;
-
- if (!SRS_IS_SRS_ADDRESS(sender))
- return SRS_ENOTSRSADDRESS;
-
- if (srs->noreverse)
- return SRS_ENOTREWRITTEN;
-
- len = strlen(sender) + 1;
- buf = (char *)srs_f_malloc(len);
-
- ret = srs_reverse(srs, buf, len, sender);
-
- if (ret == SRS_SUCCESS)
- *sptr = buf;
- else
- srs_f_free(buf);
-
- return ret;
- }
|