otp.c 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895
  1. /* OTP SASL plugin
  2. * Ken Murchison
  3. */
  4. /*
  5. * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions
  9. * are met:
  10. *
  11. * 1. Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. *
  14. * 2. Redistributions in binary form must reproduce the above copyright
  15. * notice, this list of conditions and the following disclaimer in
  16. * the documentation and/or other materials provided with the
  17. * distribution.
  18. *
  19. * 3. The name "Carnegie Mellon University" must not be used to
  20. * endorse or promote products derived from this software without
  21. * prior written permission. For permission or any other legal
  22. * details, please contact
  23. * Carnegie Mellon University
  24. * Center for Technology Transfer and Enterprise Creation
  25. * 4615 Forbes Avenue
  26. * Suite 302
  27. * Pittsburgh, PA 15213
  28. * (412) 268-7393, fax: (412) 268-7395
  29. * innovation@andrew.cmu.edu
  30. *
  31. * 4. Redistributions of any form whatsoever must retain the following
  32. * acknowledgment:
  33. * "This product includes software developed by Computing Services
  34. * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
  35. *
  36. * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  37. * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  38. * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  39. * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  40. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  41. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  42. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  43. */
  44. #include <config.h>
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #ifdef HAVE_UNISTD_H
  48. #include <unistd.h>
  49. #endif
  50. #include <errno.h>
  51. #include <string.h>
  52. #include <ctype.h>
  53. #include <assert.h>
  54. #include <openssl/evp.h>
  55. #include <openssl/md5.h> /* XXX hack for OpenBSD/OpenSSL cruftiness */
  56. #include <sasl.h>
  57. #define MD5_H /* suppress internal MD5 */
  58. #include <saslplug.h>
  59. #include "plugin_common.h"
  60. #ifdef macintosh
  61. #error #include <sasl_otp_plugin_decl.h>
  62. #endif
  63. /***************************** Common Section *****************************/
  64. #define OTP_SEQUENCE_MAX 9999
  65. #define OTP_SEQUENCE_DEFAULT 499
  66. #define OTP_SEQUENCE_REINIT 490
  67. #define OTP_SEED_MIN 1
  68. #define OTP_SEED_MAX 16
  69. #define OTP_HASH_SIZE 8 /* 64 bits */
  70. #define OTP_CHALLENGE_MAX 100
  71. #define OTP_RESPONSE_MAX 100
  72. #define OTP_HEX_TYPE "hex:"
  73. #define OTP_WORD_TYPE "word:"
  74. #define OTP_INIT_HEX_TYPE "init-hex:"
  75. #define OTP_INIT_WORD_TYPE "init-word:"
  76. typedef struct algorithm_option_s {
  77. const char *name; /* name used in challenge/response */
  78. int swab; /* number of bytes to swab (0, 1, 2, 4, 8) */
  79. const char *evp_name; /* name used for lookup in EVP table */
  80. } algorithm_option_t;
  81. static algorithm_option_t algorithm_options[] = {
  82. {"md4", 0, "md4"},
  83. {"md5", 0, "md5"},
  84. {"sha1", 4, "sha1"},
  85. {NULL, 0, NULL}
  86. };
  87. static EVP_MD_CTX *_plug_EVP_MD_CTX_new(const sasl_utils_t *utils)
  88. {
  89. utils->log(NULL, SASL_LOG_DEBUG, "_plug_EVP_MD_CTX_new()");
  90. #if OPENSSL_VERSION_NUMBER >= 0x10100000L
  91. return EVP_MD_CTX_new();
  92. #else
  93. return utils->malloc(sizeof(EVP_MD_CTX));
  94. #endif
  95. }
  96. static void _plug_EVP_MD_CTX_free(EVP_MD_CTX *ctx, const sasl_utils_t *utils)
  97. {
  98. utils->log(NULL, SASL_LOG_DEBUG, "_plug_EVP_MD_CTX_free()");
  99. #if OPENSSL_VERSION_NUMBER >= 0x10100000L
  100. EVP_MD_CTX_free(ctx);
  101. #else
  102. utils->free(ctx);
  103. #endif
  104. }
  105. /* Convert the binary data into ASCII hex */
  106. void bin2hex(unsigned char *bin, int binlen, char *hex)
  107. {
  108. int i;
  109. unsigned char c;
  110. for (i = 0; i < binlen; i++) {
  111. c = (bin[i] >> 4) & 0xf;
  112. hex[i*2] = (c > 9) ? ('a' + c - 10) : ('0' + c);
  113. c = bin[i] & 0xf;
  114. hex[i*2+1] = (c > 9) ? ('a' + c - 10) : ('0' + c);
  115. }
  116. hex[i*2] = '\0';
  117. }
  118. /*
  119. * Hash the data using the given algorithm and fold it into 64 bits,
  120. * swabbing bytes if necessary.
  121. */
  122. static void otp_hash(const EVP_MD *md, char *in, size_t inlen,
  123. unsigned char *out, int swab, EVP_MD_CTX *mdctx)
  124. {
  125. unsigned char hash[EVP_MAX_MD_SIZE];
  126. unsigned int i;
  127. int j;
  128. unsigned hashlen;
  129. EVP_DigestInit(mdctx, md);
  130. EVP_DigestUpdate(mdctx, in, inlen);
  131. EVP_DigestFinal(mdctx, hash, &hashlen);
  132. /* Fold the result into 64 bits */
  133. for (i = OTP_HASH_SIZE; i < hashlen; i++) {
  134. hash[i % OTP_HASH_SIZE] ^= hash[i];
  135. }
  136. /* Swab bytes */
  137. if (swab) {
  138. for (i = 0; i < OTP_HASH_SIZE;) {
  139. for (j = swab-1; j > -swab; i++, j-=2)
  140. out[i] = hash[i+j];
  141. }
  142. }
  143. else
  144. memcpy(out, hash, OTP_HASH_SIZE);
  145. }
  146. static int generate_otp(const sasl_utils_t *utils,
  147. algorithm_option_t *alg, unsigned seq, char *seed,
  148. unsigned char *secret, unsigned secret_len,
  149. unsigned char *otp)
  150. {
  151. const EVP_MD *md;
  152. EVP_MD_CTX *mdctx = NULL;
  153. char *key = NULL;
  154. int r = SASL_OK;
  155. if (!(md = EVP_get_digestbyname(alg->evp_name))) {
  156. utils->seterror(utils->conn, 0,
  157. "OTP algorithm %s is not available", alg->evp_name);
  158. return SASL_FAIL;
  159. }
  160. if ((mdctx = _plug_EVP_MD_CTX_new(utils)) == NULL) {
  161. SETERROR(utils, "cannot allocate MD CTX");
  162. r = SASL_NOMEM;
  163. goto done;
  164. }
  165. if ((key = utils->malloc(strlen(seed) + secret_len + 1)) == NULL) {
  166. SETERROR(utils, "cannot allocate OTP key");
  167. r = SASL_NOMEM;
  168. goto done;
  169. }
  170. /* initial step */
  171. sprintf(key, "%s%.*s", seed, secret_len, secret);
  172. otp_hash(md, key, strlen(key), otp, alg->swab, mdctx);
  173. /* computation step */
  174. while (seq-- > 0)
  175. otp_hash(md, (char *) otp, OTP_HASH_SIZE, otp, alg->swab, mdctx);
  176. done:
  177. if (key) utils->free(key);
  178. if (mdctx) _plug_EVP_MD_CTX_free(mdctx, utils);
  179. return r;
  180. }
  181. static int parse_challenge(const sasl_utils_t *utils,
  182. char *chal, algorithm_option_t **alg,
  183. unsigned *seq, char *seed, int is_init)
  184. {
  185. char *c;
  186. algorithm_option_t *opt;
  187. int n;
  188. c = chal;
  189. /* eat leading whitespace */
  190. while (*c && isspace((int) *c)) c++;
  191. if (!is_init) {
  192. /* check the prefix */
  193. if (!*c || strncmp(c, "otp-", 4)) {
  194. SETERROR(utils, "not an OTP challenge");
  195. return SASL_BADPROT;
  196. }
  197. /* skip the prefix */
  198. c += 4;
  199. }
  200. /* find the algorithm */
  201. opt = algorithm_options;
  202. while (opt->name) {
  203. if (!strncmp(c, opt->name, strlen(opt->name))) {
  204. break;
  205. }
  206. opt++;
  207. }
  208. /* didn't find the algorithm in our list */
  209. if (!opt->name) {
  210. utils->seterror(utils->conn, 0, "OTP algorithm '%s' not supported", c);
  211. return SASL_BADPROT;
  212. }
  213. /* skip algorithm name */
  214. c += strlen(opt->name);
  215. *alg = opt;
  216. /* eat whitespace */
  217. if (!isspace((int) *c)) {
  218. SETERROR(utils, "no whitespace between OTP algorithm and sequence");
  219. return SASL_BADPROT;
  220. }
  221. while (*c && isspace((int) *c)) c++;
  222. /* grab the sequence */
  223. if ((*seq = strtoul(c, &c, 10)) > OTP_SEQUENCE_MAX) {
  224. utils->seterror(utils->conn, 0, "sequence > %u", OTP_SEQUENCE_MAX);
  225. return SASL_BADPROT;
  226. }
  227. /* eat whitespace */
  228. if (!isspace((int) *c)) {
  229. SETERROR(utils, "no whitespace between OTP sequence and seed");
  230. return SASL_BADPROT;
  231. }
  232. while (*c && isspace((int) *c)) c++;
  233. /* grab the seed, converting to lowercase as we go */
  234. n = 0;
  235. while (*c && isalnum((int) *c) && (n < OTP_SEED_MAX))
  236. seed[n++] = tolower((int) *c++);
  237. if (n > OTP_SEED_MAX) {
  238. utils->seterror(utils->conn, 0, "OTP seed length > %u", OTP_SEED_MAX);
  239. return SASL_BADPROT;
  240. }
  241. else if (n < OTP_SEED_MIN) {
  242. utils->seterror(utils->conn, 0, "OTP seed length < %u", OTP_SEED_MIN);
  243. return SASL_BADPROT;
  244. }
  245. seed[n] = '\0';
  246. if (!is_init) {
  247. /* eat whitespace */
  248. if (!isspace((int) *c)) {
  249. SETERROR(utils, "no whitespace between OTP seed and extensions");
  250. return SASL_BADPROT;
  251. }
  252. while (*c && isspace((int) *c)) c++;
  253. /* make sure this is an extended challenge */
  254. if (strncmp(c, "ext", 3) ||
  255. (*(c+=3) &&
  256. !(isspace((int) *c) || (*c == ',') ||
  257. (*c == '\r') || (*c == '\n')))) {
  258. SETERROR(utils, "not an OTP extended challenge");
  259. return SASL_BADPROT;
  260. }
  261. }
  262. return SASL_OK;
  263. }
  264. static void
  265. otp_common_mech_free(void *global_context __attribute__((unused)),
  266. const sasl_utils_t *utils __attribute__((unused)))
  267. {
  268. /* Don't call EVP_cleanup(); here, as this might confuse the calling
  269. application if it also uses OpenSSL */
  270. }
  271. /***************************** Server Section *****************************/
  272. #ifdef HAVE_OPIE
  273. #include <opie.h>
  274. #endif
  275. typedef struct server_context {
  276. int state;
  277. char *authid;
  278. int locked; /* is the user's secret locked? */
  279. algorithm_option_t *alg;
  280. #ifdef HAVE_OPIE
  281. struct opie opie;
  282. #else
  283. char *realm;
  284. unsigned seq;
  285. char seed[OTP_SEED_MAX+1];
  286. unsigned char otp[OTP_HASH_SIZE];
  287. time_t timestamp; /* time we locked the secret */
  288. #endif /* HAVE_OPIE */
  289. char *out_buf;
  290. unsigned out_buf_len;
  291. } server_context_t;
  292. static int otp_server_mech_new(void *glob_context __attribute__((unused)),
  293. sasl_server_params_t *sparams,
  294. const char *challenge __attribute__((unused)),
  295. unsigned challen __attribute__((unused)),
  296. void **conn_context)
  297. {
  298. server_context_t *text;
  299. /* holds state are in */
  300. text = sparams->utils->malloc(sizeof(server_context_t));
  301. if (text == NULL) {
  302. MEMERROR(sparams->utils);
  303. return SASL_NOMEM;
  304. }
  305. memset(text, 0, sizeof(server_context_t));
  306. text->state = 1;
  307. *conn_context = text;
  308. return SASL_OK;
  309. }
  310. #ifdef HAVE_OPIE
  311. #ifndef OPIE_KEYFILE
  312. #define OPIE_KEYFILE "/etc/opiekeys"
  313. #endif
  314. static int opie_server_mech_step(void *conn_context,
  315. sasl_server_params_t *params,
  316. const char *clientin,
  317. unsigned clientinlen,
  318. const char **serverout,
  319. unsigned *serveroutlen,
  320. sasl_out_params_t *oparams)
  321. {
  322. server_context_t *text = (server_context_t *) conn_context;
  323. *serverout = NULL;
  324. *serveroutlen = 0;
  325. if (text == NULL) {
  326. return SASL_BADPROT;
  327. }
  328. switch (text->state) {
  329. case 1: {
  330. const char *authzid;
  331. const char *authid;
  332. size_t authid_len;
  333. unsigned lup = 0;
  334. int result;
  335. /* should have received authzid NUL authid */
  336. /* get authzid */
  337. authzid = clientin;
  338. while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
  339. if (lup >= clientinlen) {
  340. SETERROR(params->utils, "Can only find OTP authzid (no authid)");
  341. return SASL_BADPROT;
  342. }
  343. /* get authid */
  344. ++lup;
  345. authid = clientin + lup;
  346. while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
  347. authid_len = clientin + lup - authid;
  348. if (lup != clientinlen) {
  349. SETERROR(params->utils,
  350. "Got more data than we were expecting in the OTP plugin\n");
  351. return SASL_BADPROT;
  352. }
  353. text->authid = params->utils->malloc(authid_len + 1);
  354. if (text->authid == NULL) {
  355. MEMERROR(params->utils);
  356. return SASL_NOMEM;
  357. }
  358. /* we can't assume that authen is null-terminated */
  359. strncpy(text->authid, authid, authid_len);
  360. text->authid[authid_len] = '\0';
  361. result = params->canon_user(params->utils->conn, text->authid, 0,
  362. SASL_CU_AUTHID, oparams);
  363. if (result != SASL_OK) return result;
  364. result = params->canon_user(params->utils->conn,
  365. strlen(authzid) ? authzid : text->authid,
  366. 0, SASL_CU_AUTHZID, oparams);
  367. if (result != SASL_OK) return result;
  368. result = _plug_buf_alloc(params->utils, &(text->out_buf),
  369. &(text->out_buf_len), OTP_CHALLENGE_MAX+1);
  370. if (result != SASL_OK) return result;
  371. /* create challenge - return sasl_continue on success */
  372. result = opiechallenge(&text->opie, text->authid, text->out_buf);
  373. switch (result) {
  374. case 0:
  375. text->locked = 1;
  376. *serverout = text->out_buf;
  377. *serveroutlen = strlen(text->out_buf);
  378. text->state = 2;
  379. return SASL_CONTINUE;
  380. case 1:
  381. SETERROR(params->utils, "opiechallenge: user not found or locked");
  382. return SASL_NOUSER;
  383. default:
  384. SETERROR(params->utils,
  385. "opiechallenge: system error (file, memory, I/O)");
  386. return SASL_FAIL;
  387. }
  388. }
  389. case 2: {
  390. char response[OPIE_RESPONSE_MAX+1];
  391. int result;
  392. /* should have received extended response,
  393. but we'll take anything that we can verify */
  394. if (clientinlen > OPIE_RESPONSE_MAX) {
  395. SETERROR(params->utils, "response too long");
  396. return SASL_BADPROT;
  397. }
  398. /* we can't assume that the response is null-terminated */
  399. strncpy(response, clientin, clientinlen);
  400. response[clientinlen] = '\0';
  401. /* verify response */
  402. result = opieverify(&text->opie, response);
  403. text->locked = 0;
  404. switch (result) {
  405. case 0:
  406. /* set oparams */
  407. oparams->doneflag = 1;
  408. oparams->mech_ssf = 0;
  409. oparams->maxoutbuf = 0;
  410. oparams->encode_context = NULL;
  411. oparams->encode = NULL;
  412. oparams->decode_context = NULL;
  413. oparams->decode = NULL;
  414. oparams->param_version = 0;
  415. return SASL_OK;
  416. case 1:
  417. SETERROR(params->utils, "opieverify: invalid/incorrect response");
  418. return SASL_BADAUTH;
  419. default:
  420. SETERROR(params->utils,
  421. "opieverify: system error (file, memory, I/O)");
  422. return SASL_FAIL;
  423. }
  424. }
  425. default:
  426. params->utils->log(NULL, SASL_LOG_ERR,
  427. "Invalid OTP server step %d\n", text->state);
  428. return SASL_FAIL;
  429. }
  430. return SASL_FAIL; /* should never get here */
  431. }
  432. static void opie_server_mech_dispose(void *conn_context,
  433. const sasl_utils_t *utils)
  434. {
  435. server_context_t *text = (server_context_t *) conn_context;
  436. if (!text) return;
  437. /* if we created a challenge, but bailed before the verification of the
  438. response, do a verify here to release the lock on the user key */
  439. if (text->locked) opieverify(&text->opie, "");
  440. if (text->authid) _plug_free_string(utils, &(text->authid));
  441. if (text->out_buf) utils->free(text->out_buf);
  442. utils->free(text);
  443. }
  444. static int opie_mech_avail(void *glob_context __attribute__((unused)),
  445. sasl_server_params_t *sparams,
  446. void **conn_context __attribute__((unused)))
  447. {
  448. const char *fname;
  449. unsigned int len;
  450. sparams->utils->getopt(sparams->utils->getopt_context,
  451. "OTP", "opiekeys", &fname, &len);
  452. if (!fname) fname = OPIE_KEYFILE;
  453. if (access(fname, R_OK|W_OK) != 0) {
  454. sparams->utils->log(NULL, SASL_LOG_ERR,
  455. "OTP unavailable because "
  456. "can't read/write key database %s: %m",
  457. fname, errno);
  458. return SASL_NOMECH;
  459. }
  460. return SASL_OK;
  461. }
  462. static sasl_server_plug_t otp_server_plugins[] =
  463. {
  464. {
  465. "OTP",
  466. 0,
  467. SASL_SEC_NOPLAINTEXT
  468. | SASL_SEC_NOANONYMOUS
  469. | SASL_SEC_FORWARD_SECRECY,
  470. SASL_FEAT_WANT_CLIENT_FIRST
  471. | SASL_FEAT_DONTUSE_USERPASSWD
  472. | SASL_FEAT_ALLOWS_PROXY,
  473. NULL,
  474. &otp_server_mech_new,
  475. &opie_server_mech_step,
  476. &opie_server_mech_dispose,
  477. &otp_common_mech_free,
  478. NULL,
  479. NULL,
  480. NULL,
  481. &opie_mech_avail,
  482. NULL
  483. }
  484. };
  485. #else /* HAVE_OPIE */
  486. #include "otp.h"
  487. #define OTP_MDA_DEFAULT "md5"
  488. #define OTP_LOCK_TIMEOUT 5 * 60 /* 5 minutes */
  489. /* Convert the ASCII hex into binary data */
  490. int hex2bin(char *hex, unsigned char *bin, int binlen)
  491. {
  492. int i;
  493. char *c;
  494. unsigned char msn, lsn;
  495. memset(bin, 0, binlen);
  496. for (c = hex, i = 0; i < binlen; c++) {
  497. /* whitespace */
  498. if (isspace((int) *c))
  499. continue;
  500. /* end of string, or non-hex char */
  501. if (!*c || !*(c+1) || !isxdigit((int) *c))
  502. break;
  503. msn = (*c > '9') ? tolower((int) *c) - 'a' + 10 : *c - '0';
  504. c++;
  505. lsn = (*c > '9') ? tolower((int) *c) - 'a' + 10 : *c - '0';
  506. bin[i++] = (unsigned char) (msn << 4) | lsn;
  507. }
  508. return (i < binlen) ? SASL_BADAUTH : SASL_OK;
  509. }
  510. static int make_secret(const sasl_utils_t *utils, const char *alg,
  511. unsigned seq, char *seed, unsigned char *otp,
  512. time_t timeout, sasl_secret_t **secret)
  513. {
  514. size_t sec_len;
  515. char *data;
  516. char buf[2*OTP_HASH_SIZE+1];
  517. /*
  518. * secret is stored as:
  519. *
  520. * <alg> \t <seq> \t <seed> \t <otp> \t <timeout> \0
  521. *
  522. * <timeout> is used as a "lock" when an auth is in progress
  523. * we just set it to zero here (no lock)
  524. */
  525. sec_len = strlen(alg)+1+4+1+strlen(seed)+1+2*OTP_HASH_SIZE+1+20+1;
  526. *secret = utils->malloc(sizeof(sasl_secret_t)+sec_len);
  527. if (!*secret) {
  528. return SASL_NOMEM;
  529. }
  530. (*secret)->len = (unsigned) sec_len;
  531. data = (char *) (*secret)->data;
  532. bin2hex(otp, OTP_HASH_SIZE, buf);
  533. buf[2*OTP_HASH_SIZE] = '\0';
  534. sprintf(data, "%s\t%04d\t%s\t%s\t%020ld",
  535. alg, seq, seed, buf, timeout);
  536. return SASL_OK;
  537. }
  538. static int parse_secret(const sasl_utils_t *utils,
  539. char *secret, size_t seclen,
  540. char *alg, unsigned *seq, char *seed,
  541. unsigned char *otp,
  542. time_t *timeout)
  543. {
  544. if (strlen(secret) < seclen) {
  545. char *c;
  546. /*
  547. * old-style (binary) secret is stored as:
  548. *
  549. * <alg> \0 <seq> \0 <seed> \0 <otp> <timeout>
  550. *
  551. */
  552. if (seclen < (3+1+1+1+OTP_SEED_MIN+1+OTP_HASH_SIZE+sizeof(time_t))) {
  553. SETERROR(utils, "OTP secret too short");
  554. return SASL_FAIL;
  555. }
  556. c = secret;
  557. strcpy(alg, (char*) c);
  558. c += strlen(alg)+1;
  559. *seq = strtoul(c, NULL, 10);
  560. c += 5;
  561. strcpy(seed, (char*) c);
  562. c += strlen(seed)+1;
  563. memcpy(otp, c, OTP_HASH_SIZE);
  564. c += OTP_HASH_SIZE;
  565. memcpy(timeout, c, sizeof(time_t));
  566. return SASL_OK;
  567. }
  568. else {
  569. char buf[2*OTP_HASH_SIZE+1];
  570. /*
  571. * new-style (ASCII) secret is stored as:
  572. *
  573. * <alg> \t <seq> \t <seed> \t <otp> \t <timeout> \0
  574. *
  575. */
  576. if (seclen < (3+1+1+1+OTP_SEED_MIN+1+2*OTP_HASH_SIZE+1+20)) {
  577. SETERROR(utils, "OTP secret too short");
  578. return SASL_FAIL;
  579. }
  580. sscanf(secret, "%s\t%04d\t%s\t%s\t%020ld",
  581. alg, seq, seed, buf, timeout);
  582. hex2bin(buf, otp, OTP_HASH_SIZE);
  583. return SASL_OK;
  584. }
  585. }
  586. /* Compare two string pointers */
  587. static int strptrcasecmp(const void *arg1, const void *arg2)
  588. {
  589. return (strcasecmp(*((char**) arg1), *((char**) arg2)));
  590. }
  591. /* Convert the 6 words into binary data */
  592. static int word2bin(const sasl_utils_t *utils,
  593. char *words, unsigned char *bin, const EVP_MD *md,
  594. EVP_MD_CTX *mdctx)
  595. {
  596. int i, j;
  597. char *c, *word, buf[OTP_RESPONSE_MAX+1];
  598. void *base;
  599. int nmemb;
  600. unsigned long x = 0;
  601. unsigned char bits[OTP_HASH_SIZE+1]; /* 1 for checksum */
  602. unsigned char chksum;
  603. int bit, fbyte, lbyte;
  604. const char **str_ptr;
  605. int alt_dict = 0;
  606. /* this is a destructive operation, so make a work copy */
  607. strcpy(buf, words);
  608. memset(bits, 0, 9);
  609. for (c = buf, bit = 0, i = 0; i < 6; i++, c++, bit+=11) {
  610. while (*c && isspace((int) *c)) c++;
  611. word = c;
  612. while (*c && isalpha((int) *c)) c++;
  613. if (!*c && i < 5) break;
  614. *c = '\0';
  615. if (strlen(word) < 1 || strlen(word) > 4) {
  616. utils->log(NULL, SASL_LOG_DEBUG,
  617. "incorrect word length '%s'", word);
  618. return SASL_BADAUTH;
  619. }
  620. /* standard dictionary */
  621. if (!alt_dict) {
  622. if (strlen(word) < 4) {
  623. base = otp_std_dict;
  624. nmemb = OTP_4LETTER_OFFSET;
  625. }
  626. else {
  627. base = otp_std_dict + OTP_4LETTER_OFFSET;
  628. nmemb = OTP_STD_DICT_SIZE - OTP_4LETTER_OFFSET;
  629. }
  630. str_ptr = (const char**) bsearch((void*) &word, base, nmemb,
  631. sizeof(const char*),
  632. strptrcasecmp);
  633. if (str_ptr) {
  634. x = (unsigned long) (str_ptr - otp_std_dict);
  635. }
  636. else if (i == 0) {
  637. /* couldn't find first word, try alternate dictionary */
  638. alt_dict = 1;
  639. }
  640. else {
  641. utils->log(NULL, SASL_LOG_DEBUG,
  642. "word '%s' not found in dictionary", word);
  643. return SASL_BADAUTH;
  644. }
  645. }
  646. /* alternate dictionary */
  647. if (alt_dict) {
  648. unsigned char hash[EVP_MAX_MD_SIZE];
  649. unsigned hashlen;
  650. EVP_DigestInit(mdctx, md);
  651. EVP_DigestUpdate(mdctx, word, strlen(word));
  652. EVP_DigestFinal(mdctx, hash, &hashlen);
  653. /* use lowest 11 bits */
  654. x = ((hash[hashlen-2] & 0x7) << 8) | hash[hashlen-1];
  655. }
  656. /* left align 11 bits on byte boundary */
  657. x <<= (8 - ((bit+11) % 8));
  658. /* first output byte containing some of our 11 bits */
  659. fbyte = bit / 8;
  660. /* last output byte containing some of our 11 bits */
  661. lbyte = (bit+11) / 8;
  662. /* populate the output bytes with the 11 bits */
  663. for (j = lbyte; j >= fbyte; j--, x >>= 8)
  664. bits[j] |= (unsigned char) (x & 0xff);
  665. }
  666. if (i < 6) {
  667. utils->log(NULL, SASL_LOG_DEBUG, "not enough words (%d)", i);
  668. return SASL_BADAUTH;
  669. }
  670. /* see if the 2-bit checksum is correct */
  671. for (chksum = 0, i = 0; i < 8; i++) {
  672. for (j = 0; j < 4; j++) {
  673. chksum += ((bits[i] >> (2 * j)) & 0x3);
  674. }
  675. }
  676. chksum <<= 6;
  677. if (chksum != bits[8]) {
  678. utils->log(NULL, SASL_LOG_DEBUG, "incorrect parity");
  679. return SASL_BADAUTH;
  680. }
  681. memcpy(bin, bits, OTP_HASH_SIZE);
  682. return SASL_OK;
  683. }
  684. static int verify_response(server_context_t *text, const sasl_utils_t *utils,
  685. char *response)
  686. {
  687. const EVP_MD *md;
  688. EVP_MD_CTX *mdctx = NULL;
  689. char *c;
  690. int do_init = 0;
  691. unsigned char cur_otp[OTP_HASH_SIZE], prev_otp[OTP_HASH_SIZE];
  692. int r;
  693. /* find the MDA */
  694. if (!(md = EVP_get_digestbyname(text->alg->evp_name))) {
  695. utils->seterror(utils->conn, 0,
  696. "OTP algorithm %s is not available",
  697. text->alg->evp_name);
  698. return SASL_FAIL;
  699. }
  700. if ((mdctx = _plug_EVP_MD_CTX_new(utils)) == NULL) {
  701. SETERROR(utils, "cannot allocate MD CTX");
  702. return SASL_NOMEM;
  703. }
  704. /* eat leading whitespace */
  705. c = response;
  706. while (isspace((int) *c)) c++;
  707. if (strchr(c, ':')) {
  708. if (!strncasecmp(c, OTP_HEX_TYPE, strlen(OTP_HEX_TYPE))) {
  709. r = hex2bin(c+strlen(OTP_HEX_TYPE), cur_otp, OTP_HASH_SIZE);
  710. }
  711. else if (!strncasecmp(c, OTP_WORD_TYPE, strlen(OTP_WORD_TYPE))) {
  712. r = word2bin(utils, c+strlen(OTP_WORD_TYPE), cur_otp, md, mdctx);
  713. }
  714. else if (!strncasecmp(c, OTP_INIT_HEX_TYPE,
  715. strlen(OTP_INIT_HEX_TYPE))) {
  716. do_init = 1;
  717. r = hex2bin(c+strlen(OTP_INIT_HEX_TYPE), cur_otp, OTP_HASH_SIZE);
  718. }
  719. else if (!strncasecmp(c, OTP_INIT_WORD_TYPE,
  720. strlen(OTP_INIT_WORD_TYPE))) {
  721. do_init = 1;
  722. r = word2bin(utils, c+strlen(OTP_INIT_WORD_TYPE), cur_otp, md, mdctx);
  723. }
  724. else {
  725. SETERROR(utils, "unknown OTP extended response type");
  726. r = SASL_BADAUTH;
  727. }
  728. }
  729. else {
  730. /* standard response, try word first, and then hex */
  731. r = word2bin(utils, c, cur_otp, md, mdctx);
  732. if (r != SASL_OK)
  733. r = hex2bin(c, cur_otp, OTP_HASH_SIZE);
  734. }
  735. if (r == SASL_OK) {
  736. /* do one more hash (previous otp) and compare to stored otp */
  737. otp_hash(md, (char *) cur_otp, OTP_HASH_SIZE,
  738. prev_otp, text->alg->swab, mdctx);
  739. if (!memcmp(prev_otp, text->otp, OTP_HASH_SIZE)) {
  740. /* update the secret with this seq/otp */
  741. memcpy(text->otp, cur_otp, OTP_HASH_SIZE);
  742. text->seq--;
  743. r = SASL_OK;
  744. }
  745. else
  746. r = SASL_BADAUTH;
  747. }
  748. /* if this is an init- attempt, let's check it out */
  749. if (r == SASL_OK && do_init) {
  750. char *new_chal = NULL, *new_resp = NULL;
  751. algorithm_option_t *alg;
  752. unsigned seq;
  753. char seed[OTP_SEED_MAX+1];
  754. unsigned char new_otp[OTP_HASH_SIZE];
  755. /* find the challenge and response fields */
  756. new_chal = strchr(c+strlen(OTP_INIT_WORD_TYPE), ':');
  757. if (new_chal) {
  758. *new_chal++ = '\0';
  759. new_resp = strchr(new_chal, ':');
  760. if (new_resp)
  761. *new_resp++ = '\0';
  762. }
  763. if (!(new_chal && new_resp)) {
  764. r = SASL_BADAUTH;
  765. goto done;
  766. }
  767. if ((r = parse_challenge(utils, new_chal, &alg, &seq, seed, 1))
  768. != SASL_OK) {
  769. goto done;
  770. }
  771. if (seq < 1 || !strcasecmp(seed, text->seed)) {
  772. r = SASL_BADAUTH;
  773. goto done;
  774. }
  775. /* find the MDA */
  776. if (!(md = EVP_get_digestbyname(alg->evp_name))) {
  777. utils->seterror(utils->conn, 0,
  778. "OTP algorithm %s is not available",
  779. alg->evp_name);
  780. r = SASL_BADAUTH;
  781. goto done;
  782. }
  783. if (!strncasecmp(c, OTP_INIT_HEX_TYPE, strlen(OTP_INIT_HEX_TYPE))) {
  784. r = hex2bin(new_resp, new_otp, OTP_HASH_SIZE);
  785. }
  786. else if (!strncasecmp(c, OTP_INIT_WORD_TYPE,
  787. strlen(OTP_INIT_WORD_TYPE))) {
  788. r = word2bin(utils, new_resp, new_otp, md, mdctx);
  789. }
  790. if (r == SASL_OK) {
  791. /* setup for new secret */
  792. text->alg = alg;
  793. text->seq = seq;
  794. strcpy(text->seed, seed);
  795. memcpy(text->otp, new_otp, OTP_HASH_SIZE);
  796. }
  797. }
  798. done:
  799. if (mdctx) _plug_EVP_MD_CTX_free(mdctx, utils);
  800. return r;
  801. }
  802. static int otp_server_mech_step1(server_context_t *text,
  803. sasl_server_params_t *params,
  804. const char *clientin,
  805. unsigned clientinlen,
  806. const char **serverout,
  807. unsigned *serveroutlen,
  808. sasl_out_params_t *oparams)
  809. {
  810. const char *authzid;
  811. const char *authidp;
  812. size_t authid_len;
  813. unsigned lup = 0;
  814. int result, n;
  815. const char *lookup_request[] = { "*cmusaslsecretOTP",
  816. NULL };
  817. const char *store_request[] = { "cmusaslsecretOTP",
  818. NULL };
  819. struct propval auxprop_values[2];
  820. char mda[10];
  821. time_t timeout;
  822. sasl_secret_t *sec = NULL;
  823. struct propctx *propctx = NULL;
  824. /* should have received authzid NUL authid */
  825. /* get authzid */
  826. authzid = clientin;
  827. while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
  828. if (lup >= clientinlen) {
  829. SETERROR(params->utils, "Can only find OTP authzid (no authid)");
  830. return SASL_BADPROT;
  831. }
  832. /* get authid */
  833. ++lup;
  834. authidp = clientin + lup;
  835. while ((lup < clientinlen) && (clientin[lup] != 0)) ++lup;
  836. authid_len = clientin + lup - authidp;
  837. if (lup != clientinlen) {
  838. SETERROR(params->utils,
  839. "Got more data than we were expecting in the OTP plugin\n");
  840. return SASL_BADPROT;
  841. }
  842. text->authid = params->utils->malloc(authid_len + 1);
  843. if (text->authid == NULL) {
  844. MEMERROR(params->utils);
  845. return SASL_NOMEM;
  846. }
  847. /* we can't assume that authid is null-terminated */
  848. strncpy(text->authid, authidp, authid_len);
  849. text->authid[authid_len] = '\0';
  850. n = 0;
  851. do {
  852. /* Get user secret */
  853. result = params->utils->prop_request(params->propctx,
  854. lookup_request);
  855. if (result != SASL_OK) return result;
  856. /* this will trigger the getting of the aux properties.
  857. Must use the fully qualified authid here */
  858. result = params->canon_user(params->utils->conn, text->authid, 0,
  859. SASL_CU_AUTHID, oparams);
  860. if (result != SASL_OK) return result;
  861. result = params->canon_user(params->utils->conn,
  862. strlen(authzid) ? authzid : text->authid,
  863. 0, SASL_CU_AUTHZID, oparams);
  864. if (result != SASL_OK) return result;
  865. result = params->utils->prop_getnames(params->propctx,
  866. lookup_request,
  867. auxprop_values);
  868. if (result < 0 ||
  869. (!auxprop_values[0].name || !auxprop_values[0].values)) {
  870. /* We didn't find this username */
  871. SETERROR(params->utils, "no OTP secret in database");
  872. result = params->transition ? SASL_TRANS : SASL_NOUSER;
  873. return (result);
  874. }
  875. if (auxprop_values[0].name && auxprop_values[0].values) {
  876. result = parse_secret(params->utils,
  877. (char*) auxprop_values[0].values[0],
  878. auxprop_values[0].valsize,
  879. mda, &text->seq, text->seed, text->otp,
  880. &timeout);
  881. if (result != SASL_OK) return result;
  882. } else {
  883. SETERROR(params->utils, "don't have an OTP secret");
  884. return SASL_FAIL;
  885. }
  886. text->timestamp = time(0);
  887. }
  888. /*
  889. * check lock timeout
  890. *
  891. * we try 10 times in 1 second intervals in order to give the other
  892. * auth attempt time to finish
  893. */
  894. while ((text->timestamp < timeout) && (n++ < 10) && !sleep(1));
  895. if (text->timestamp < timeout) {
  896. SETERROR(params->utils,
  897. "simultaneous OTP authentications not permitted");
  898. return SASL_TRYAGAIN;
  899. }
  900. /* check sequence number */
  901. if (text->seq <= 1) {
  902. SETERROR(params->utils, "OTP has expired (sequence <= 1)");
  903. return SASL_EXPIRED;
  904. }
  905. /* find algorithm */
  906. text->alg = algorithm_options;
  907. while (text->alg->name) {
  908. if (!strcasecmp(text->alg->name, mda))
  909. break;
  910. text->alg++;
  911. }
  912. if (!text->alg->name) {
  913. params->utils->seterror(params->utils->conn, 0,
  914. "unknown OTP algorithm '%s'", mda);
  915. return SASL_FAIL;
  916. }
  917. /* remake the secret with a timeout */
  918. result = make_secret(params->utils, text->alg->name, text->seq,
  919. text->seed, text->otp,
  920. text->timestamp + OTP_LOCK_TIMEOUT, &sec);
  921. if (result != SASL_OK) {
  922. SETERROR(params->utils, "error making OTP secret");
  923. return result;
  924. }
  925. /* do the store */
  926. propctx = params->utils->prop_new(0);
  927. if (!propctx)
  928. result = SASL_FAIL;
  929. if (result == SASL_OK)
  930. result = params->utils->prop_request(propctx, store_request);
  931. if (result == SASL_OK)
  932. result = params->utils->prop_set(propctx, "cmusaslsecretOTP",
  933. (char *) sec->data, sec->len);
  934. if (result == SASL_OK)
  935. result = params->utils->auxprop_store(params->utils->conn,
  936. propctx, text->authid);
  937. if (propctx)
  938. params->utils->prop_dispose(&propctx);
  939. if (sec) params->utils->free(sec);
  940. if (result != SASL_OK) {
  941. SETERROR(params->utils, "Error putting OTP secret");
  942. return result;
  943. }
  944. text->locked = 1;
  945. result = _plug_buf_alloc(params->utils, &(text->out_buf),
  946. &(text->out_buf_len), OTP_CHALLENGE_MAX+1);
  947. if (result != SASL_OK) return result;
  948. /* create challenge */
  949. sprintf(text->out_buf, "otp-%s %u %s ext",
  950. text->alg->name, text->seq-1, text->seed);
  951. *serverout = text->out_buf;
  952. *serveroutlen = (unsigned) strlen(text->out_buf);
  953. text->state = 2;
  954. return SASL_CONTINUE;
  955. }
  956. static int
  957. otp_server_mech_step2(server_context_t *text,
  958. sasl_server_params_t *params,
  959. const char *clientin,
  960. unsigned clientinlen,
  961. const char **serverout __attribute__((unused)),
  962. unsigned *serveroutlen __attribute__((unused)),
  963. sasl_out_params_t *oparams)
  964. {
  965. char response[OTP_RESPONSE_MAX+1];
  966. int result;
  967. sasl_secret_t *sec = NULL;
  968. struct propctx *propctx = NULL;
  969. const char *store_request[] = { "cmusaslsecretOTP",
  970. NULL };
  971. if (clientinlen > OTP_RESPONSE_MAX) {
  972. SETERROR(params->utils, "OTP response too long");
  973. return SASL_BADPROT;
  974. }
  975. /* we can't assume that the response is null-terminated */
  976. strncpy(response, clientin, clientinlen);
  977. response[clientinlen] = '\0';
  978. /* check timeout */
  979. if (time(0) > text->timestamp + OTP_LOCK_TIMEOUT) {
  980. SETERROR(params->utils, "OTP: server timed out");
  981. return SASL_UNAVAIL;
  982. }
  983. /* verify response */
  984. result = verify_response(text, params->utils, response);
  985. if (result != SASL_OK) return result;
  986. /* make the new secret */
  987. result = make_secret(params->utils, text->alg->name, text->seq,
  988. text->seed, text->otp, 0, &sec);
  989. if (result != SASL_OK) {
  990. SETERROR(params->utils, "error making OTP secret");
  991. }
  992. /* do the store */
  993. propctx = params->utils->prop_new(0);
  994. if (!propctx)
  995. result = SASL_FAIL;
  996. if (result == SASL_OK)
  997. result = params->utils->prop_request(propctx, store_request);
  998. if (result == SASL_OK)
  999. result = params->utils->prop_set(propctx, "cmusaslsecretOTP",
  1000. (char *) sec->data, sec->len);
  1001. if (result == SASL_OK)
  1002. result = params->utils->auxprop_store(params->utils->conn,
  1003. propctx, text->authid);
  1004. if (propctx)
  1005. params->utils->prop_dispose(&propctx);
  1006. if (result) {
  1007. SETERROR(params->utils, "Error putting OTP secret");
  1008. }
  1009. text->locked = 0;
  1010. if (sec) _plug_free_secret(params->utils, &sec);
  1011. /* set oparams */
  1012. oparams->doneflag = 1;
  1013. oparams->mech_ssf = 0;
  1014. oparams->maxoutbuf = 0;
  1015. oparams->encode_context = NULL;
  1016. oparams->encode = NULL;
  1017. oparams->decode_context = NULL;
  1018. oparams->decode = NULL;
  1019. oparams->param_version = 0;
  1020. return result;
  1021. }
  1022. static int otp_server_mech_step(void *conn_context,
  1023. sasl_server_params_t *params,
  1024. const char *clientin,
  1025. unsigned clientinlen,
  1026. const char **serverout,
  1027. unsigned *serveroutlen,
  1028. sasl_out_params_t *oparams)
  1029. {
  1030. server_context_t *text = (server_context_t *) conn_context;
  1031. *serverout = NULL;
  1032. *serveroutlen = 0;
  1033. switch (text->state) {
  1034. case 1:
  1035. return otp_server_mech_step1(text, params, clientin, clientinlen,
  1036. serverout, serveroutlen, oparams);
  1037. case 2:
  1038. return otp_server_mech_step2(text, params, clientin, clientinlen,
  1039. serverout, serveroutlen, oparams);
  1040. default:
  1041. params->utils->log(NULL, SASL_LOG_ERR,
  1042. "Invalid OTP server step %d\n", text->state);
  1043. return SASL_FAIL;
  1044. }
  1045. return SASL_FAIL; /* should never get here */
  1046. }
  1047. static void otp_server_mech_dispose(void *conn_context,
  1048. const sasl_utils_t *utils)
  1049. {
  1050. server_context_t *text = (server_context_t *) conn_context;
  1051. sasl_secret_t *sec;
  1052. struct propctx *propctx = NULL;
  1053. const char *store_request[] = { "cmusaslsecretOTP",
  1054. NULL };
  1055. int r;
  1056. if (!text) return;
  1057. /* if we created a challenge, but bailed before the verification of the
  1058. response, release the lock on the user key */
  1059. if (text->locked && (time(0) < text->timestamp + OTP_LOCK_TIMEOUT)) {
  1060. r = make_secret(utils, text->alg->name, text->seq,
  1061. text->seed, text->otp, 0, &sec);
  1062. if (r != SASL_OK) {
  1063. SETERROR(utils, "error making OTP secret");
  1064. if (sec) utils->free(sec);
  1065. sec = NULL;
  1066. }
  1067. /* do the store */
  1068. propctx = utils->prop_new(0);
  1069. if (!propctx)
  1070. r = SASL_FAIL;
  1071. if (!r)
  1072. r = utils->prop_request(propctx, store_request);
  1073. if (!r)
  1074. r = utils->prop_set(propctx, "cmusaslsecretOTP",
  1075. (sec ? (char *) sec->data : NULL),
  1076. (sec ? sec->len : 0));
  1077. if (!r)
  1078. r = utils->auxprop_store(utils->conn, propctx, text->authid);
  1079. if (propctx)
  1080. utils->prop_dispose(&propctx);
  1081. if (r) {
  1082. SETERROR(utils, "Error putting OTP secret");
  1083. }
  1084. if (sec) _plug_free_secret(utils, &sec);
  1085. }
  1086. if (text->authid) _plug_free_string(utils, &(text->authid));
  1087. if (text->realm) _plug_free_string(utils, &(text->realm));
  1088. if (text->out_buf) utils->free(text->out_buf);
  1089. utils->free(text);
  1090. }
  1091. static int otp_setpass(void *glob_context __attribute__((unused)),
  1092. sasl_server_params_t *sparams,
  1093. const char *userstr,
  1094. const char *pass, unsigned passlen,
  1095. const char *oldpass __attribute__((unused)),
  1096. unsigned oldpasslen __attribute__((unused)),
  1097. unsigned flags)
  1098. {
  1099. int r;
  1100. char *user = NULL;
  1101. char *user_only = NULL;
  1102. char *realm = NULL;
  1103. sasl_secret_t *sec;
  1104. struct propctx *propctx = NULL;
  1105. const char *store_request[] = { "cmusaslsecretOTP",
  1106. NULL };
  1107. /* Do we have a backend that can store properties? */
  1108. if (!sparams->utils->auxprop_store ||
  1109. sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
  1110. SETERROR(sparams->utils, "OTP: auxprop backend can't store properties");
  1111. return SASL_NOMECH;
  1112. }
  1113. r = _plug_parseuser(sparams->utils,
  1114. &user_only,
  1115. &realm,
  1116. sparams->user_realm,
  1117. sparams->serverFQDN,
  1118. userstr);
  1119. if (r) {
  1120. SETERROR(sparams->utils, "OTP: Error parsing user");
  1121. return r;
  1122. }
  1123. r = _plug_make_fulluser(sparams->utils, &user, user_only, realm);
  1124. if (r) {
  1125. goto cleanup;
  1126. }
  1127. if ((flags & SASL_SET_DISABLE) || pass == NULL) {
  1128. sec = NULL;
  1129. } else {
  1130. algorithm_option_t *algs;
  1131. const char *mda;
  1132. unsigned int len;
  1133. unsigned short randnum;
  1134. char seed[OTP_SEED_MAX+1];
  1135. unsigned char otp[OTP_HASH_SIZE];
  1136. sparams->utils->getopt(sparams->utils->getopt_context,
  1137. "OTP", "otp_mda", &mda, &len);
  1138. if (!mda) mda = OTP_MDA_DEFAULT;
  1139. algs = algorithm_options;
  1140. while (algs->name) {
  1141. if (!strcasecmp(algs->name, mda) ||
  1142. !strcasecmp(algs->evp_name, mda))
  1143. break;
  1144. algs++;
  1145. }
  1146. if (!algs->name) {
  1147. sparams->utils->seterror(sparams->utils->conn, 0,
  1148. "unknown OTP algorithm '%s'", mda);
  1149. r = SASL_FAIL;
  1150. goto cleanup;
  1151. }
  1152. sparams->utils->rand(sparams->utils->rpool,
  1153. (char*) &randnum, sizeof(randnum));
  1154. sprintf(seed, "%.2s%04u", sparams->serverFQDN, (randnum % 9999) + 1);
  1155. r = generate_otp(sparams->utils, algs, OTP_SEQUENCE_DEFAULT,
  1156. seed, (unsigned char *) pass, passlen, otp);
  1157. if (r != SASL_OK) {
  1158. /* generate_otp() takes care of error message */
  1159. goto cleanup;
  1160. }
  1161. r = make_secret(sparams->utils, algs->name, OTP_SEQUENCE_DEFAULT,
  1162. seed, otp, 0, &sec);
  1163. if (r != SASL_OK) {
  1164. SETERROR(sparams->utils, "error making OTP secret");
  1165. goto cleanup;
  1166. }
  1167. }
  1168. /* do the store */
  1169. propctx = sparams->utils->prop_new(0);
  1170. if (!propctx)
  1171. r = SASL_FAIL;
  1172. if (!r)
  1173. r = sparams->utils->prop_request(propctx, store_request);
  1174. if (!r)
  1175. r = sparams->utils->prop_set(propctx, "cmusaslsecretOTP",
  1176. (sec ? (char *) sec->data : NULL),
  1177. (sec ? sec->len : 0));
  1178. if (!r)
  1179. r = sparams->utils->auxprop_store(sparams->utils->conn, propctx, user);
  1180. if (propctx)
  1181. sparams->utils->prop_dispose(&propctx);
  1182. if (r) {
  1183. SETERROR(sparams->utils, "Error putting OTP secret");
  1184. goto cleanup;
  1185. }
  1186. sparams->utils->log(NULL, SASL_LOG_DEBUG, "Setpass for OTP successful\n");
  1187. cleanup:
  1188. if (user) _plug_free_string(sparams->utils, &user);
  1189. if (user_only) _plug_free_string(sparams->utils, &user_only);
  1190. if (realm) _plug_free_string(sparams->utils, &realm);
  1191. if (sec) _plug_free_secret(sparams->utils, &sec);
  1192. return r;
  1193. }
  1194. static int otp_mech_avail(void *glob_context __attribute__((unused)),
  1195. sasl_server_params_t *sparams,
  1196. void **conn_context __attribute__((unused)))
  1197. {
  1198. /* Do we have a backend that can store properties? */
  1199. if (!sparams->utils->auxprop_store ||
  1200. sparams->utils->auxprop_store(NULL, NULL, NULL) != SASL_OK) {
  1201. sparams->utils->log(NULL,
  1202. SASL_LOG_DEBUG,
  1203. "OTP: auxprop backend can't store properties");
  1204. return SASL_NOMECH;
  1205. }
  1206. return SASL_OK;
  1207. }
  1208. static sasl_server_plug_t otp_server_plugins[] =
  1209. {
  1210. {
  1211. "OTP", /* mech_name */
  1212. 0, /* max_ssf */
  1213. SASL_SEC_NOPLAINTEXT
  1214. | SASL_SEC_NOANONYMOUS
  1215. | SASL_SEC_FORWARD_SECRECY, /* security_flags */
  1216. SASL_FEAT_WANT_CLIENT_FIRST
  1217. | SASL_FEAT_ALLOWS_PROXY, /* features */
  1218. NULL, /* glob_context */
  1219. &otp_server_mech_new, /* mech_new */
  1220. &otp_server_mech_step, /* mech_step */
  1221. &otp_server_mech_dispose, /* mech_dispose */
  1222. &otp_common_mech_free, /* mech_free */
  1223. &otp_setpass, /* setpass */
  1224. NULL, /* user_query */
  1225. NULL, /* idle */
  1226. &otp_mech_avail, /* mech avail */
  1227. NULL /* spare */
  1228. }
  1229. };
  1230. #endif /* HAVE_OPIE */
  1231. int otp_server_plug_init(const sasl_utils_t *utils,
  1232. int maxversion,
  1233. int *out_version,
  1234. sasl_server_plug_t **pluglist,
  1235. int *plugcount)
  1236. {
  1237. if (maxversion < SASL_SERVER_PLUG_VERSION) {
  1238. SETERROR(utils, "OTP version mismatch");
  1239. return SASL_BADVERS;
  1240. }
  1241. *out_version = SASL_SERVER_PLUG_VERSION;
  1242. *pluglist = otp_server_plugins;
  1243. *plugcount = 1;
  1244. /* Add all digests */
  1245. OpenSSL_add_all_digests();
  1246. return SASL_OK;
  1247. }
  1248. /***************************** Client Section *****************************/
  1249. typedef struct client_context {
  1250. int state;
  1251. sasl_secret_t *password;
  1252. unsigned int free_password; /* set if we need to free password */
  1253. const char *otpassword;
  1254. char *out_buf;
  1255. unsigned out_buf_len;
  1256. char challenge[OTP_CHALLENGE_MAX+1];
  1257. } client_context_t;
  1258. static int otp_client_mech_new(void *glob_context __attribute__((unused)),
  1259. sasl_client_params_t *params,
  1260. void **conn_context)
  1261. {
  1262. client_context_t *text;
  1263. /* holds state are in */
  1264. text = params->utils->malloc(sizeof(client_context_t));
  1265. if (text == NULL) {
  1266. MEMERROR( params->utils );
  1267. return SASL_NOMEM;
  1268. }
  1269. memset(text, 0, sizeof(client_context_t));
  1270. text->state = 1;
  1271. *conn_context = text;
  1272. return SASL_OK;
  1273. }
  1274. static int otp_client_mech_step1(client_context_t *text,
  1275. sasl_client_params_t *params,
  1276. const char *serverin __attribute__((unused)),
  1277. unsigned serverinlen __attribute__((unused)),
  1278. sasl_interact_t **prompt_need,
  1279. const char **clientout,
  1280. unsigned *clientoutlen,
  1281. sasl_out_params_t *oparams)
  1282. {
  1283. const char *user = NULL, *authid = NULL;
  1284. int user_result = SASL_OK;
  1285. int auth_result = SASL_OK;
  1286. int pass_result = SASL_OK;
  1287. sasl_chalprompt_t *echo_cb;
  1288. void *echo_context;
  1289. int result;
  1290. /* check if sec layer strong enough */
  1291. if (params->props.min_ssf > params->external_ssf) {
  1292. SETERROR( params->utils, "SSF requested of OTP plugin");
  1293. return SASL_TOOWEAK;
  1294. }
  1295. /* try to get the authid */
  1296. if (oparams->authid == NULL) {
  1297. auth_result = _plug_get_authid(params->utils, &authid, prompt_need);
  1298. if ((auth_result != SASL_OK) && (auth_result != SASL_INTERACT))
  1299. return auth_result;
  1300. }
  1301. /* try to get the userid */
  1302. if (oparams->user == NULL) {
  1303. user_result = _plug_get_userid(params->utils, &user, prompt_need);
  1304. if ((user_result != SASL_OK) && (user_result != SASL_INTERACT))
  1305. return user_result;
  1306. }
  1307. /* try to get the secret pass-phrase if we don't have a chalprompt */
  1308. if ((params->utils->getcallback(params->utils->conn, SASL_CB_ECHOPROMPT,
  1309. (sasl_callback_ft *)&echo_cb, &echo_context) == SASL_FAIL) &&
  1310. (text->password == NULL)) {
  1311. pass_result = _plug_get_password(params->utils, &text->password,
  1312. &text->free_password, prompt_need);
  1313. if ((pass_result != SASL_OK) && (pass_result != SASL_INTERACT))
  1314. return pass_result;
  1315. }
  1316. /* free prompts we got */
  1317. if (prompt_need && *prompt_need) {
  1318. params->utils->free(*prompt_need);
  1319. *prompt_need = NULL;
  1320. }
  1321. /* if there are prompts not filled in */
  1322. if ((user_result == SASL_INTERACT) || (auth_result == SASL_INTERACT) ||
  1323. (pass_result == SASL_INTERACT)) {
  1324. /* make the prompt list */
  1325. result =
  1326. _plug_make_prompts(params->utils, prompt_need,
  1327. user_result == SASL_INTERACT ?
  1328. "Please enter your authorization name" : NULL,
  1329. NULL,
  1330. auth_result == SASL_INTERACT ?
  1331. "Please enter your authentication name" : NULL,
  1332. NULL,
  1333. pass_result == SASL_INTERACT ?
  1334. "Please enter your secret pass-phrase" : NULL,
  1335. NULL,
  1336. NULL, NULL, NULL,
  1337. NULL, NULL, NULL);
  1338. if (result != SASL_OK) return result;
  1339. return SASL_INTERACT;
  1340. }
  1341. if (!user || !*user) {
  1342. result = params->canon_user(params->utils->conn, authid, 0,
  1343. SASL_CU_AUTHID | SASL_CU_AUTHZID, oparams);
  1344. }
  1345. else {
  1346. result = params->canon_user(params->utils->conn, user, 0,
  1347. SASL_CU_AUTHZID, oparams);
  1348. if (result != SASL_OK) return result;
  1349. result = params->canon_user(params->utils->conn, authid, 0,
  1350. SASL_CU_AUTHID, oparams);
  1351. }
  1352. if (result != SASL_OK) return result;
  1353. /* send authorized id NUL authentication id */
  1354. *clientoutlen = oparams->ulen + 1 + oparams->alen;
  1355. /* remember the extra NUL on the end for stupid clients */
  1356. result = _plug_buf_alloc(params->utils, &(text->out_buf),
  1357. &(text->out_buf_len), *clientoutlen + 1);
  1358. if (result != SASL_OK) return result;
  1359. memset(text->out_buf, 0, *clientoutlen + 1);
  1360. memcpy(text->out_buf, oparams->user, oparams->ulen);
  1361. memcpy(text->out_buf+oparams->ulen+1, oparams->authid, oparams->alen);
  1362. *clientout = text->out_buf;
  1363. text->state = 2;
  1364. return SASL_CONTINUE;
  1365. }
  1366. static int otp_client_mech_step2(client_context_t *text,
  1367. sasl_client_params_t *params,
  1368. const char *serverin,
  1369. unsigned serverinlen,
  1370. sasl_interact_t **prompt_need,
  1371. const char **clientout,
  1372. unsigned *clientoutlen,
  1373. sasl_out_params_t *oparams)
  1374. {
  1375. int echo_result = SASL_OK;
  1376. int result;
  1377. if (serverinlen > OTP_CHALLENGE_MAX) {
  1378. SETERROR(params->utils, "OTP challenge too long");
  1379. return SASL_BADPROT;
  1380. }
  1381. /* we can't assume that challenge is null-terminated */
  1382. strncpy(text->challenge, serverin, serverinlen);
  1383. text->challenge[serverinlen] = '\0';
  1384. /* try to get the one-time password if we don't have the secret */
  1385. if ((text->password == NULL) && (text->otpassword == NULL)) {
  1386. echo_result = _plug_challenge_prompt(params->utils,
  1387. SASL_CB_ECHOPROMPT,
  1388. text->challenge,
  1389. "Please enter your one-time password",
  1390. &text->otpassword,
  1391. prompt_need);
  1392. if ((echo_result != SASL_OK) && (echo_result != SASL_INTERACT))
  1393. return echo_result;
  1394. }
  1395. /* free prompts we got */
  1396. if (prompt_need && *prompt_need) {
  1397. params->utils->free(*prompt_need);
  1398. *prompt_need = NULL;
  1399. }
  1400. /* if there are prompts not filled in */
  1401. if (echo_result == SASL_INTERACT) {
  1402. /* make the prompt list */
  1403. result =
  1404. _plug_make_prompts(params->utils,
  1405. prompt_need,
  1406. NULL,
  1407. NULL,
  1408. NULL,
  1409. NULL,
  1410. NULL,
  1411. NULL,
  1412. text->challenge,
  1413. "Please enter your one-time password",
  1414. NULL,
  1415. NULL,
  1416. NULL,
  1417. NULL);
  1418. if (result != SASL_OK) return result;
  1419. return SASL_INTERACT;
  1420. }
  1421. /* the application provided us with a one-time password so use it */
  1422. if (text->otpassword) {
  1423. *clientout = text->otpassword;
  1424. *clientoutlen = (unsigned) strlen(text->otpassword);
  1425. }
  1426. /* generate our own response using the user's secret pass-phrase */
  1427. else {
  1428. algorithm_option_t *alg;
  1429. unsigned seq;
  1430. char seed[OTP_SEED_MAX+1];
  1431. unsigned char otp[OTP_HASH_SIZE];
  1432. int init_done = 0;
  1433. /* parse challenge */
  1434. result = parse_challenge(params->utils,
  1435. text->challenge,
  1436. &alg,
  1437. &seq,
  1438. seed,
  1439. 0);
  1440. if (result != SASL_OK) return result;
  1441. if (!text->password) {
  1442. PARAMERROR(params->utils);
  1443. return SASL_BADPARAM;
  1444. }
  1445. if (seq < 1) {
  1446. SETERROR(params->utils, "OTP has expired (sequence < 1)");
  1447. return SASL_EXPIRED;
  1448. }
  1449. /* generate otp */
  1450. result = generate_otp(params->utils, alg, seq, seed,
  1451. text->password->data, text->password->len, otp);
  1452. if (result != SASL_OK) return result;
  1453. result = _plug_buf_alloc(params->utils, &(text->out_buf),
  1454. &(text->out_buf_len), OTP_RESPONSE_MAX+1);
  1455. if (result != SASL_OK) return result;
  1456. if (seq < OTP_SEQUENCE_REINIT) {
  1457. unsigned short randnum;
  1458. char new_seed[OTP_SEED_MAX+1];
  1459. unsigned char new_otp[OTP_HASH_SIZE];
  1460. /* try to reinitialize */
  1461. /* make sure we have a different seed */
  1462. do {
  1463. params->utils->rand(params->utils->rpool,
  1464. (char*) &randnum, sizeof(randnum));
  1465. sprintf(new_seed, "%.2s%04u", params->serverFQDN,
  1466. (randnum % 9999) + 1);
  1467. } while (!strcasecmp(seed, new_seed));
  1468. result = generate_otp(params->utils, alg, OTP_SEQUENCE_DEFAULT,
  1469. new_seed, text->password->data, text->password->len, new_otp);
  1470. if (result == SASL_OK) {
  1471. /* create an init-hex response */
  1472. strcpy(text->out_buf, OTP_INIT_HEX_TYPE);
  1473. bin2hex(otp, OTP_HASH_SIZE,
  1474. text->out_buf+strlen(text->out_buf));
  1475. sprintf(text->out_buf+strlen(text->out_buf), ":%s %u %s:",
  1476. alg->name, OTP_SEQUENCE_DEFAULT, new_seed);
  1477. bin2hex(new_otp, OTP_HASH_SIZE,
  1478. text->out_buf+strlen(text->out_buf));
  1479. init_done = 1;
  1480. }
  1481. else {
  1482. /* just do a regular response */
  1483. }
  1484. }
  1485. if (!init_done) {
  1486. /* created hex response */
  1487. strcpy(text->out_buf, OTP_HEX_TYPE);
  1488. bin2hex(otp, OTP_HASH_SIZE, text->out_buf+strlen(text->out_buf));
  1489. }
  1490. *clientout = text->out_buf;
  1491. *clientoutlen = (unsigned) strlen(text->out_buf);
  1492. }
  1493. /* set oparams */
  1494. oparams->doneflag = 1;
  1495. oparams->mech_ssf = 0;
  1496. oparams->maxoutbuf = 0;
  1497. oparams->encode_context = NULL;
  1498. oparams->encode = NULL;
  1499. oparams->decode_context = NULL;
  1500. oparams->decode = NULL;
  1501. oparams->param_version = 0;
  1502. return SASL_OK;
  1503. }
  1504. static int otp_client_mech_step(void *conn_context,
  1505. sasl_client_params_t *params,
  1506. const char *serverin,
  1507. unsigned serverinlen,
  1508. sasl_interact_t **prompt_need,
  1509. const char **clientout,
  1510. unsigned *clientoutlen,
  1511. sasl_out_params_t *oparams)
  1512. {
  1513. client_context_t *text = (client_context_t *) conn_context;
  1514. *clientout = NULL;
  1515. *clientoutlen = 0;
  1516. switch (text->state) {
  1517. case 1:
  1518. return otp_client_mech_step1(text, params, serverin, serverinlen,
  1519. prompt_need, clientout, clientoutlen,
  1520. oparams);
  1521. case 2:
  1522. return otp_client_mech_step2(text, params, serverin, serverinlen,
  1523. prompt_need, clientout, clientoutlen,
  1524. oparams);
  1525. default:
  1526. params->utils->log(NULL, SASL_LOG_ERR,
  1527. "Invalid OTP client step %d\n", text->state);
  1528. return SASL_FAIL;
  1529. }
  1530. return SASL_FAIL; /* should never get here */
  1531. }
  1532. static void otp_client_mech_dispose(void *conn_context,
  1533. const sasl_utils_t *utils)
  1534. {
  1535. client_context_t *text = (client_context_t *) conn_context;
  1536. if (!text) return;
  1537. if (text->free_password) _plug_free_secret(utils, &(text->password));
  1538. if (text->out_buf) utils->free(text->out_buf);
  1539. utils->free(text);
  1540. }
  1541. static sasl_client_plug_t otp_client_plugins[] =
  1542. {
  1543. {
  1544. "OTP", /* mech_name */
  1545. 0, /* max_ssf */
  1546. SASL_SEC_NOPLAINTEXT
  1547. | SASL_SEC_NOANONYMOUS
  1548. | SASL_SEC_FORWARD_SECRECY, /* security_flags */
  1549. SASL_FEAT_WANT_CLIENT_FIRST
  1550. | SASL_FEAT_ALLOWS_PROXY, /* features */
  1551. NULL, /* required_prompts */
  1552. NULL, /* glob_context */
  1553. &otp_client_mech_new, /* mech_new */
  1554. &otp_client_mech_step, /* mech_step */
  1555. &otp_client_mech_dispose, /* mech_dispose */
  1556. &otp_common_mech_free, /* mech_free */
  1557. NULL, /* idle */
  1558. NULL, /* spare */
  1559. NULL /* spare */
  1560. }
  1561. };
  1562. int otp_client_plug_init(sasl_utils_t *utils,
  1563. int maxversion,
  1564. int *out_version,
  1565. sasl_client_plug_t **pluglist,
  1566. int *plugcount)
  1567. {
  1568. if (maxversion < SASL_CLIENT_PLUG_VERSION) {
  1569. SETERROR(utils, "OTP version mismatch");
  1570. return SASL_BADVERS;
  1571. }
  1572. *out_version = SASL_CLIENT_PLUG_VERSION;
  1573. *pluglist = otp_client_plugins;
  1574. *plugcount = 1;
  1575. /* Add all digests */
  1576. OpenSSL_add_all_digests();
  1577. return SASL_OK;
  1578. }