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 15KB

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