You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

srs2.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704
  1. /* This file is copied from the libsrs2 sources */
  2. /* Modified by Timo Röhling <timo.roehling@gmx.de> */
  3. /* Copyright (c) 2004 Shevek (srs@anarres.org)
  4. * All rights reserved.
  5. *
  6. * This file is a part of libsrs2 from http://www.libsrs2.org/
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, under the terms of either the GNU General Public
  10. * License version 2 or the BSD license, at the discretion of the
  11. * user. Copies of these licenses have been included in the libsrs2
  12. * distribution. See the the file called LICENSE for more
  13. * information.
  14. */
  15. #undef USE_OPENSSL
  16. #include <stdarg.h>
  17. #include <time.h> /* time */
  18. #include <sys/types.h> /* tyepdefs */
  19. #include <sys/time.h> /* timeval / timezone struct */
  20. #include <string.h> /* memcpy, strcpy, memset */
  21. #include <alloca.h>
  22. #ifdef USE_OPENSSL
  23. #include <openssl/hmac.h>
  24. #endif
  25. #include "srs2.h"
  26. #ifndef EVP_MAX_MD_SIZE
  27. #define EVP_MAX_MD_SIZE (16+20) /* The SSLv3 md5+sha1 type */
  28. #endif
  29. #ifndef HAVE_STRCASECMP
  30. # ifdef HAVE__STRICMP
  31. # define strcasecmp _stricmp
  32. # endif
  33. #endif
  34. #ifndef HAVE_STRNCASECMP
  35. # ifdef HAVE__STRNICMP
  36. # define strncasecmp _strnicmp
  37. # endif
  38. #endif
  39. /* Use this */
  40. #define STRINGP(s) ((s != NULL) && (*(s) != '\0'))
  41. static const char *srs_separators = "=-+";
  42. static srs_malloc_t srs_f_malloc = malloc;
  43. static srs_realloc_t srs_f_realloc = realloc;
  44. static srs_free_t srs_f_free = free;
  45. int
  46. srs_set_malloc(srs_malloc_t m, srs_realloc_t r, srs_free_t f)
  47. {
  48. srs_f_malloc = m;
  49. srs_f_realloc = r;
  50. srs_f_free = f;
  51. return SRS_SUCCESS;
  52. }
  53. const char *
  54. srs_strerror(int code)
  55. {
  56. switch (code) {
  57. /* Simple errors */
  58. case SRS_SUCCESS:
  59. return "Success";
  60. case SRS_ENOTSRSADDRESS:
  61. return "Not an SRS address.";
  62. /* Config errors */
  63. case SRS_ENOSECRETS:
  64. return "No secrets in SRS configuration.";
  65. case SRS_ESEPARATORINVALID:
  66. return "Invalid separator suggested.";
  67. /* Input errors */
  68. case SRS_ENOSENDERATSIGN:
  69. return "No at sign in sender address";
  70. case SRS_EBUFTOOSMALL:
  71. return "Buffer too small.";
  72. /* Syntax errors */
  73. case SRS_ENOSRS0HOST:
  74. return "No host in SRS0 address.";
  75. case SRS_ENOSRS0USER:
  76. return "No user in SRS0 address.";
  77. case SRS_ENOSRS0HASH:
  78. return "No hash in SRS0 address.";
  79. case SRS_ENOSRS0STAMP:
  80. return "No timestamp in SRS0 address.";
  81. case SRS_ENOSRS1HOST:
  82. return "No host in SRS1 address.";
  83. case SRS_ENOSRS1USER:
  84. return "No user in SRS1 address.";
  85. case SRS_ENOSRS1HASH:
  86. return "No hash in SRS1 address.";
  87. case SRS_EBADTIMESTAMPCHAR:
  88. return "Bad base32 character in timestamp.";
  89. case SRS_EHASHTOOSHORT:
  90. return "Hash too short in SRS address.";
  91. /* SRS errors */
  92. case SRS_ETIMESTAMPOUTOFDATE:
  93. return "Time stamp out of date.";
  94. case SRS_EHASHINVALID:
  95. return "Hash invalid in SRS address.";
  96. default:
  97. return "Unknown error in SRS library.";
  98. }
  99. }
  100. srs_t *
  101. srs_new()
  102. {
  103. srs_t *srs = (srs_t *)srs_f_malloc(sizeof(srs_t));
  104. srs_init(srs);
  105. return srs;
  106. }
  107. void
  108. srs_init(srs_t *srs)
  109. {
  110. memset(srs, 0, sizeof(srs_t));
  111. srs->secrets = NULL;
  112. srs->numsecrets = 0;
  113. srs->separator = '=';
  114. srs->maxage = 21;
  115. srs->hashlength = 4;
  116. srs->hashmin = srs->hashlength;
  117. srs->alwaysrewrite = FALSE;
  118. }
  119. void
  120. srs_free(srs_t *srs)
  121. {
  122. int i;
  123. for (i = 0; i < srs->numsecrets; i++) {
  124. memset(srs->secrets[i], 0, strlen(srs->secrets[i]));
  125. srs_f_free(srs->secrets[i]);
  126. srs->secrets[i] = 0;
  127. }
  128. srs_f_free(srs);
  129. }
  130. int
  131. srs_add_secret(srs_t *srs, const char *secret)
  132. {
  133. int newlen = (srs->numsecrets + 1) * sizeof(char *);
  134. srs->secrets = (char **)srs_f_realloc(srs->secrets, newlen);
  135. srs->secrets[srs->numsecrets++] = strdup(secret);
  136. return SRS_SUCCESS;
  137. }
  138. const char *
  139. srs_get_secret(srs_t *srs, int idx)
  140. {
  141. if (idx < srs->numsecrets)
  142. return srs->secrets[idx];
  143. return NULL;
  144. }
  145. #define SRS_PARAM_DEFINE(n, t) \
  146. int srs_set_ ## n (srs_t *srs, t value) { \
  147. srs->n = value; \
  148. return SRS_SUCCESS; \
  149. } \
  150. t srs_get_ ## n (srs_t *srs) { \
  151. return srs->n; \
  152. }
  153. int
  154. srs_set_separator(srs_t *srs, char value)
  155. {
  156. if (strchr(srs_separators, value) == NULL)
  157. return SRS_ESEPARATORINVALID;
  158. srs->separator = value;
  159. return SRS_SUCCESS;
  160. }
  161. char
  162. srs_get_separator(srs_t *srs)
  163. {
  164. return srs->separator;
  165. }
  166. SRS_PARAM_DEFINE(maxage, int)
  167. /* XXX Check hashlength >= hashmin */
  168. SRS_PARAM_DEFINE(hashlength, int)
  169. SRS_PARAM_DEFINE(hashmin, int)
  170. SRS_PARAM_DEFINE(alwaysrewrite, srs_bool)
  171. SRS_PARAM_DEFINE(noforward, srs_bool)
  172. SRS_PARAM_DEFINE(noreverse, srs_bool)
  173. /* Don't mess with these unless you know what you're doing well
  174. * enough to rewrite the timestamp functions. These are based on
  175. * a 2 character timestamp. Changing these in the wild is probably
  176. * a bad idea. */
  177. #define SRS_TIME_PRECISION (60 * 60 * 24) /* One day */
  178. #define SRS_TIME_BASEBITS 5 /* 2^5 = 32 = strlen(CHARS) */
  179. /* This had better be a real variable since we do arithmethic
  180. * with it. */
  181. const char *SRS_TIME_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
  182. #define SRS_TIME_SIZE 2
  183. #define SRS_TIME_SLOTS (1<<(SRS_TIME_BASEBITS<<(SRS_TIME_SIZE-1)))
  184. int
  185. srs_timestamp_create(srs_t *srs __attribute__((unused)), char *buf, time_t now)
  186. {
  187. now = now / SRS_TIME_PRECISION;
  188. buf[1] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
  189. now = now >> SRS_TIME_BASEBITS;
  190. buf[0] = SRS_TIME_BASECHARS[now & ((1 << SRS_TIME_BASEBITS) - 1)];
  191. buf[2] = '\0';
  192. return SRS_SUCCESS;
  193. }
  194. int
  195. srs_timestamp_check(srs_t *srs, const char *stamp)
  196. {
  197. const char *sp;
  198. char *bp;
  199. int off;
  200. time_t now;
  201. time_t then;
  202. /* We had better go around this loop exactly twice! */
  203. then = 0;
  204. for (sp = stamp; *sp; sp++) {
  205. bp = strchr(SRS_TIME_BASECHARS, toupper(*sp));
  206. if (bp == NULL)
  207. return SRS_EBADTIMESTAMPCHAR;
  208. off = bp - SRS_TIME_BASECHARS;
  209. then = (then << SRS_TIME_BASEBITS) | off;
  210. }
  211. time(&now);
  212. now = (now / SRS_TIME_PRECISION) % SRS_TIME_SLOTS;
  213. while (now < then)
  214. now = now + SRS_TIME_SLOTS;
  215. if (now <= then + srs->maxage)
  216. return SRS_SUCCESS;
  217. return SRS_ETIMESTAMPOUTOFDATE;
  218. }
  219. const char *SRS_HASH_BASECHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  220. "abcdefghijklmnopqrstuvwxyz"
  221. "0123456789+/";
  222. static void
  223. srs_hash_create_v(srs_t *srs, int idx, char *buf, int nargs, va_list ap)
  224. {
  225. #ifdef USE_OPENSSL
  226. HMAC_CTX ctx;
  227. int srshashlen;
  228. char srshash[EVP_MAX_MD_SIZE + 1];
  229. #else
  230. srs_hmac_ctx_t ctx;
  231. char srshash[SHA_DIGESTSIZE + 1];
  232. #endif
  233. char *secret;
  234. char *data;
  235. int len;
  236. char *lcdata;
  237. unsigned char *hp;
  238. char *bp;
  239. int i;
  240. int j;
  241. secret = srs->secrets[idx];
  242. #ifdef USE_OPENSSL
  243. HMAC_CTX_init(&ctx);
  244. HMAC_Init(&ctx, secret, strlen(secret), EVP_sha1());
  245. #else
  246. srs_hmac_init(&ctx, secret, strlen(secret));
  247. #endif
  248. for (i = 0; i < nargs; i++) {
  249. data = va_arg(ap, char *);
  250. len = strlen(data);
  251. lcdata = alloca(len + 1);
  252. for (j = 0; j < len; j++) {
  253. if (isupper(data[j]))
  254. lcdata[j] = tolower(data[j]);
  255. else
  256. lcdata[j] = data[j];
  257. }
  258. #ifdef USE_OPENSSL
  259. HMAC_Update(&ctx, lcdata, len);
  260. #else
  261. srs_hmac_update(&ctx, lcdata, len);
  262. #endif
  263. }
  264. #ifdef USE_OPENSSL
  265. HMAC_Final(&ctx, srshash, &srshashlen);
  266. HMAC_CTX_cleanup(&ctx);
  267. srshash[EVP_MAX_MD_SIZE] = '\0';
  268. #else
  269. srs_hmac_fini(&ctx, srshash);
  270. srshash[SHA_DIGESTSIZE] = '\0';
  271. #endif
  272. /* A little base64 encoding. Just a little. */
  273. hp = (unsigned char *)srshash;
  274. bp = buf;
  275. for (i = 0; i < srs->hashlength; i++) {
  276. switch (i & 0x03) {
  277. default: /* NOTREACHED */
  278. case 0:
  279. j = (*hp >> 2);
  280. break;
  281. case 1:
  282. j = ((*hp & 0x03) << 4) |
  283. ((*(hp + 1) & 0xF0) >> 4);
  284. hp++;
  285. break;
  286. case 2:
  287. j = ((*hp & 0x0F) << 2) |
  288. ((*(hp + 1) & 0xC0) >> 6);
  289. hp++;
  290. break;
  291. case 3:
  292. j = (*hp++ & 0x3F);
  293. break;
  294. }
  295. *bp++ = SRS_HASH_BASECHARS[j];
  296. }
  297. *bp = '\0';
  298. buf[srs->hashlength] = '\0';
  299. }
  300. int
  301. srs_hash_create(srs_t *srs, char *buf, int nargs, ...)
  302. {
  303. va_list ap;
  304. if (srs->numsecrets == 0)
  305. return SRS_ENOSECRETS;
  306. if (srs->secrets == NULL)
  307. return SRS_ENOSECRETS;
  308. if (srs->secrets[0] == NULL)
  309. return SRS_ENOSECRETS;
  310. va_start(ap, nargs);
  311. srs_hash_create_v(srs, 0, buf, nargs, ap);
  312. va_end(ap);
  313. return SRS_SUCCESS;
  314. }
  315. int
  316. srs_hash_check(srs_t *srs, char *hash, int nargs, ...)
  317. {
  318. va_list ap;
  319. char *srshash;
  320. char *tmp;
  321. int len;
  322. int i;
  323. len = strlen(hash);
  324. if (len < srs->hashmin)
  325. return SRS_EHASHTOOSHORT;
  326. if (len < srs->hashlength) {
  327. tmp = alloca(srs->hashlength + 1);
  328. strncpy(tmp, hash, srs->hashlength);
  329. tmp[srs->hashlength] = '\0';
  330. hash = tmp;
  331. len = srs->hashlength;
  332. }
  333. for (i = 0; i < srs->numsecrets; i++) {
  334. va_start(ap, nargs);
  335. srshash = alloca(srs->hashlength + 1);
  336. srs_hash_create_v(srs, i, srshash, nargs, ap);
  337. va_end(ap);
  338. if (strncasecmp(hash, srshash, len) == 0)
  339. return SRS_SUCCESS;
  340. }
  341. return SRS_EHASHINVALID;
  342. }
  343. int
  344. srs_compile_shortcut(srs_t *srs,
  345. char *buf, int buflen,
  346. char *sendhost, char *senduser,
  347. const char *aliashost) {
  348. char *srshash;
  349. char srsstamp[SRS_TIME_SIZE + 1];
  350. int len;
  351. int ret;
  352. /* This never happens if we get called from guarded() */
  353. if ((strncasecmp(senduser, SRS0TAG, 4) == 0) &&
  354. (strchr(srs_separators, senduser[4]) != NULL)) {
  355. sendhost = senduser + 5;
  356. if (*sendhost == '\0')
  357. return SRS_ENOSRS0HOST;
  358. senduser = strchr(sendhost, SRSSEP);
  359. if ((senduser == NULL) || (*senduser == '\0'))
  360. return SRS_ENOSRS0USER;
  361. }
  362. len = strlen(SRS0TAG) + 1 +
  363. srs->hashlength + 1 +
  364. SRS_TIME_SIZE + 1 +
  365. strlen(sendhost) + 1 + strlen(senduser)
  366. + 1 + strlen(aliashost);
  367. if (len >= buflen)
  368. return SRS_EBUFTOOSMALL;
  369. ret = srs_timestamp_create(srs, srsstamp, time(NULL));
  370. if (ret != SRS_SUCCESS)
  371. return ret;
  372. srshash = alloca(srs->hashlength + 1);
  373. ret = srs_hash_create(srs, srshash,3, srsstamp, sendhost, senduser);
  374. if (ret != SRS_SUCCESS)
  375. return ret;
  376. sprintf(buf, SRS0TAG "%c%s%c%s%c%s%c%s@%s", srs->separator,
  377. srshash, SRSSEP, srsstamp, SRSSEP,
  378. sendhost, SRSSEP, senduser,
  379. aliashost);
  380. return SRS_SUCCESS;
  381. }
  382. int
  383. srs_compile_guarded(srs_t *srs,
  384. char *buf, int buflen,
  385. char *sendhost, char *senduser,
  386. const char *aliashost) {
  387. char *srshost;
  388. char *srsuser;
  389. char *srshash;
  390. int len;
  391. int ret;
  392. if ((strncasecmp(senduser, SRS1TAG, 4) == 0) &&
  393. (strchr(srs_separators, senduser[4]) != NULL)) {
  394. /* Used as a temporary convenience var */
  395. srshash = senduser + 5;
  396. if (*srshash == '\0')
  397. return SRS_ENOSRS1HASH;
  398. /* Used as a temporary convenience var */
  399. srshost = strchr(srshash, SRSSEP);
  400. if (!STRINGP(srshost))
  401. return SRS_ENOSRS1HOST;
  402. *srshost++ = '\0';
  403. srsuser = strchr(srshost, SRSSEP);
  404. if (!STRINGP(srsuser))
  405. return SRS_ENOSRS1USER;
  406. *srsuser++ = '\0';
  407. srshash = alloca(srs->hashlength + 1);
  408. ret = srs_hash_create(srs, srshash, 2, srshost, srsuser);
  409. if (ret != SRS_SUCCESS)
  410. return ret;
  411. len = strlen(SRS1TAG) + 1 +
  412. srs->hashlength + 1 +
  413. strlen(srshost) + 1 + strlen(srsuser)
  414. + 1 + strlen(aliashost);
  415. if (len >= buflen)
  416. return SRS_EBUFTOOSMALL;
  417. sprintf(buf, SRS1TAG "%c%s%c%s%c%s@%s", srs->separator,
  418. srshash, SRSSEP,
  419. srshost, SRSSEP, srsuser,
  420. aliashost);
  421. return SRS_SUCCESS;
  422. }
  423. else if ((strncasecmp(senduser, SRS0TAG, 4) == 0) &&
  424. (strchr(srs_separators, senduser[4]) != NULL)) {
  425. srsuser = senduser + 4;
  426. srshost = sendhost;
  427. srshash = alloca(srs->hashlength + 1);
  428. ret = srs_hash_create(srs, srshash, 2, srshost, srsuser);
  429. if (ret != SRS_SUCCESS)
  430. return ret;
  431. len = strlen(SRS1TAG) + 1 +
  432. srs->hashlength + 1 +
  433. strlen(srshost) + 1 + strlen(srsuser)
  434. + 1 + strlen(aliashost);
  435. if (len >= buflen)
  436. return SRS_EBUFTOOSMALL;
  437. sprintf(buf, SRS1TAG "%c%s%c%s%c%s@%s", srs->separator,
  438. srshash, SRSSEP,
  439. srshost, SRSSEP, srsuser,
  440. aliashost);
  441. }
  442. else {
  443. return srs_compile_shortcut(srs, buf, buflen,
  444. sendhost, senduser, aliashost);
  445. }
  446. return SRS_SUCCESS;
  447. }
  448. int
  449. srs_parse_shortcut(srs_t *srs, char *buf, unsigned buflen, char *senduser)
  450. {
  451. char *srshash;
  452. char *srsstamp;
  453. char *srshost;
  454. char *srsuser;
  455. int ret;
  456. if (strncasecmp(senduser, SRS0TAG, 4) == 0) {
  457. srshash = senduser + 5;
  458. if (!STRINGP(srshash))
  459. return SRS_ENOSRS0HASH;
  460. srsstamp = strchr(srshash, SRSSEP);
  461. if (!STRINGP(srsstamp))
  462. return SRS_ENOSRS0STAMP;
  463. *srsstamp++ = '\0';
  464. srshost = strchr(srsstamp, SRSSEP);
  465. if (!STRINGP(srshost))
  466. return SRS_ENOSRS0HOST;
  467. *srshost++ = '\0';
  468. srsuser = strchr(srshost, SRSSEP);
  469. if (!STRINGP(srsuser))
  470. return SRS_ENOSRS0USER;
  471. *srsuser++ = '\0';
  472. ret = srs_timestamp_check(srs, srsstamp);
  473. if (ret != SRS_SUCCESS)
  474. return ret;
  475. ret = srs_hash_check(srs, srshash, 3, srsstamp,
  476. srshost, srsuser);
  477. if (ret != SRS_SUCCESS)
  478. return ret;
  479. snprintf(buf, buflen, "%s@%s", srsuser, srshost);
  480. return SRS_SUCCESS;
  481. }
  482. return SRS_ENOTSRSADDRESS;
  483. }
  484. int
  485. srs_parse_guarded(srs_t *srs, char *buf, int buflen, char *senduser)
  486. {
  487. char *srshash;
  488. char *srshost;
  489. char *srsuser;
  490. int ret;
  491. if (strncasecmp(senduser, SRS1TAG, 4) == 0) {
  492. srshash = senduser + 5;
  493. if (!STRINGP(srshash))
  494. return SRS_ENOSRS1HASH;
  495. srshost = strchr(srshash, SRSSEP);
  496. if (!STRINGP(srshost))
  497. return SRS_ENOSRS1HOST;
  498. *srshost++ = '\0';
  499. srsuser = strchr(srshost, SRSSEP);
  500. if (!STRINGP(srsuser))
  501. return SRS_ENOSRS1USER;
  502. *srsuser++ = '\0';
  503. ret = srs_hash_check(srs, srshash, 2, srshost, srsuser);
  504. if (ret != SRS_SUCCESS)
  505. return ret;
  506. sprintf(buf, SRS0TAG "%s@%s", srsuser, srshost);
  507. return SRS_SUCCESS;
  508. }
  509. else {
  510. return srs_parse_shortcut(srs, buf, buflen, senduser);
  511. }
  512. }
  513. int
  514. srs_forward(srs_t *srs, char *buf, unsigned buflen,
  515. const char *sender, const char *alias)
  516. {
  517. char *senduser;
  518. char *sendhost;
  519. char *tmp;
  520. unsigned len;
  521. if (srs->noforward)
  522. return SRS_ENOTREWRITTEN;
  523. /* This is allowed to be a plain domain */
  524. while ((tmp = strchr(alias, '@')) != NULL)
  525. alias = tmp + 1;
  526. tmp = strchr(sender, '@');
  527. if (tmp == NULL)
  528. return SRS_ENOSENDERATSIGN;
  529. sendhost = tmp + 1;
  530. len = strlen(sender);
  531. if (! srs->alwaysrewrite) {
  532. if (strcasecmp(sendhost, alias) == 0) {
  533. if (strlen(sender) >= buflen)
  534. return SRS_EBUFTOOSMALL;
  535. strcpy(buf, sender);
  536. return SRS_SUCCESS;
  537. }
  538. }
  539. /* Reconstruct the whole show into our alloca() buffer. */
  540. senduser = alloca(len + 1);
  541. strcpy(senduser, sender);
  542. tmp = (senduser + (tmp - sender));
  543. sendhost = tmp + 1;
  544. *tmp = '\0';
  545. return srs_compile_guarded(srs, buf, buflen,
  546. sendhost, senduser, alias);
  547. }
  548. int
  549. srs_forward_alloc(srs_t *srs, char **sptr,
  550. const char *sender, const char *alias)
  551. {
  552. char *buf;
  553. int slen;
  554. int alen;
  555. int len;
  556. int ret;
  557. if (srs->noforward)
  558. return SRS_ENOTREWRITTEN;
  559. slen = strlen(sender);
  560. alen = strlen(alias);
  561. /* strlen(SRSxTAG) + strlen("====+@") < 64 */
  562. len = slen + alen + srs->hashlength + SRS_TIME_SIZE + 64;
  563. buf = (char *)srs_f_malloc(len);
  564. ret = srs_forward(srs, buf, len, sender, alias);
  565. if (ret == SRS_SUCCESS)
  566. *sptr = buf;
  567. else
  568. srs_f_free(buf);
  569. return ret;
  570. }
  571. int
  572. srs_reverse(srs_t *srs, char *buf, unsigned buflen, const char *sender)
  573. {
  574. char *senduser;
  575. char *tmp;
  576. unsigned len;
  577. if (!SRS_IS_SRS_ADDRESS(sender))
  578. return SRS_ENOTSRSADDRESS;
  579. if (srs->noreverse)
  580. return SRS_ENOTREWRITTEN;
  581. len = strlen(sender);
  582. if (len >= buflen)
  583. return SRS_EBUFTOOSMALL;
  584. senduser = alloca(len + 1);
  585. strcpy(senduser, sender);
  586. /* We don't really care about the host for reversal. */
  587. tmp = strchr(senduser, '@');
  588. if (tmp != NULL)
  589. *tmp = '\0';
  590. return srs_parse_guarded(srs, buf, buflen, senduser);
  591. }
  592. int
  593. srs_reverse_alloc(srs_t *srs, char **sptr, const char *sender)
  594. {
  595. char *buf;
  596. int len;
  597. int ret;
  598. *sptr = NULL;
  599. if (!SRS_IS_SRS_ADDRESS(sender))
  600. return SRS_ENOTSRSADDRESS;
  601. if (srs->noreverse)
  602. return SRS_ENOTREWRITTEN;
  603. len = strlen(sender) + 1;
  604. buf = (char *)srs_f_malloc(len);
  605. ret = srs_reverse(srs, buf, len, sender);
  606. if (ret == SRS_SUCCESS)
  607. *sptr = buf;
  608. else
  609. srs_f_free(buf);
  610. return ret;
  611. }