checkpw.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110
  1. /* SASL server API implementation
  2. * Rob Siemborski
  3. * Tim Martin
  4. */
  5. /*
  6. * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The name "Carnegie Mellon University" must not be used to
  21. * endorse or promote products derived from this software without
  22. * prior written permission. For permission or any other legal
  23. * details, please contact
  24. * Carnegie Mellon University
  25. * Center for Technology Transfer and Enterprise Creation
  26. * 4615 Forbes Avenue
  27. * Suite 302
  28. * Pittsburgh, PA 15213
  29. * (412) 268-7393, fax: (412) 268-7395
  30. * innovation@andrew.cmu.edu
  31. *
  32. * 4. Redistributions of any form whatsoever must retain the following
  33. * acknowledgment:
  34. * "This product includes software developed by Computing Services
  35. * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
  36. *
  37. * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  38. * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  39. * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  40. * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  41. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  42. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  43. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  44. */
  45. #include <config.h>
  46. /* checkpw stuff */
  47. #include <stdio.h>
  48. #include "sasl.h"
  49. #include "saslutil.h"
  50. #include "saslplug.h"
  51. #include "saslint.h"
  52. #include <assert.h>
  53. #ifdef HAVE_UNISTD_H
  54. #include <unistd.h>
  55. #endif
  56. #include <fcntl.h>
  57. #ifdef USE_DOORS
  58. #include <sys/mman.h>
  59. #error #include <door.h>
  60. #endif
  61. #include <stdlib.h>
  62. #ifndef WIN32
  63. #include <strings.h>
  64. #include <netdb.h>
  65. #include <netinet/in.h>
  66. #include <sys/un.h>
  67. #else
  68. #include <string.h>
  69. #endif
  70. #include <limits.h>
  71. #include <sys/types.h>
  72. #include <ctype.h>
  73. #ifdef HAVE_PWD_H
  74. #include <pwd.h>
  75. #endif /* HAVE_PWD_H */
  76. #ifdef HAVE_SHADOW_H
  77. #include <shadow.h>
  78. #endif /* HAVE_SHADOW_H */
  79. #if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
  80. # include <errno.h>
  81. # include <sys/types.h>
  82. # include <sys/socket.h>
  83. # include <sys/un.h>
  84. # ifdef HAVE_UNISTD_H
  85. # include <unistd.h>
  86. # endif
  87. #endif
  88. /* we store the following secret to check plaintext passwords:
  89. *
  90. * <salt> \0 <secret>
  91. *
  92. * where <secret> = MD5(<salt>, "sasldb", <pass>)
  93. */
  94. static int _sasl_make_plain_secret(const char *salt,
  95. const char *passwd, size_t passlen,
  96. sasl_secret_t **secret)
  97. {
  98. MD5_CTX ctx;
  99. unsigned sec_len = 16 + 1 + 16; /* salt + "\0" + hash */
  100. *secret = (sasl_secret_t *) sasl_ALLOC(sizeof(sasl_secret_t) +
  101. sec_len * sizeof(char));
  102. if (*secret == NULL) {
  103. return SASL_NOMEM;
  104. }
  105. _sasl_MD5Init(&ctx);
  106. _sasl_MD5Update(&ctx, (const unsigned char *) salt, 16);
  107. _sasl_MD5Update(&ctx, (const unsigned char *) "sasldb", 6);
  108. _sasl_MD5Update(&ctx, (const unsigned char *) passwd, (unsigned int) passlen);
  109. memcpy((*secret)->data, salt, 16);
  110. (*secret)->data[16] = '\0';
  111. _sasl_MD5Final((*secret)->data + 17, &ctx);
  112. (*secret)->len = sec_len;
  113. return SASL_OK;
  114. }
  115. /* verify user password using auxprop plugins
  116. */
  117. static int auxprop_verify_password(sasl_conn_t *conn,
  118. const char *userstr,
  119. const char *passwd,
  120. const char *service __attribute__((unused)),
  121. const char *user_realm __attribute__((unused)))
  122. {
  123. int ret = SASL_FAIL;
  124. int result = SASL_OK;
  125. sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
  126. const char *password_request[] = { SASL_AUX_PASSWORD,
  127. "*cmusaslsecretPLAIN",
  128. NULL };
  129. struct propval auxprop_values[3];
  130. if (!conn || !userstr)
  131. return SASL_BADPARAM;
  132. /* We need to clear any previous results and re-canonify to
  133. * ensure correctness */
  134. prop_clear (sconn->sparams->propctx, 0);
  135. /* ensure its requested */
  136. result = prop_request(sconn->sparams->propctx, password_request);
  137. if(result != SASL_OK) return result;
  138. result = _sasl_canon_user_lookup (conn,
  139. userstr,
  140. 0,
  141. SASL_CU_AUTHID | SASL_CU_AUTHZID,
  142. &(conn->oparams));
  143. if(result != SASL_OK) return result;
  144. result = prop_getnames(sconn->sparams->propctx, password_request,
  145. auxprop_values);
  146. if (result < 0) {
  147. return result;
  148. }
  149. /* Verify that the returned <name>s are correct.
  150. But we defer checking for NULL values till after we verify
  151. that a passwd is specified. */
  152. if (!auxprop_values[0].name && !auxprop_values[1].name) {
  153. return SASL_NOUSER;
  154. }
  155. /* It is possible for us to get useful information out of just
  156. * the lookup, so we won't check that we have a password until now */
  157. if(!passwd) {
  158. ret = SASL_BADPARAM;
  159. goto done;
  160. }
  161. if ((!auxprop_values[0].values || !auxprop_values[0].values[0])
  162. && (!auxprop_values[1].values || !auxprop_values[1].values[0])) {
  163. return SASL_NOUSER;
  164. }
  165. /* At the point this has been called, the username has been canonified
  166. * and we've done the auxprop lookup. This should be easy. */
  167. if(auxprop_values[0].name
  168. && auxprop_values[0].values
  169. && auxprop_values[0].values[0]
  170. && !strcmp(auxprop_values[0].values[0], passwd)) {
  171. /* We have a plaintext version and it matched! */
  172. return SASL_OK;
  173. } else if(auxprop_values[1].name
  174. && auxprop_values[1].values
  175. && auxprop_values[1].values[0]) {
  176. const char *db_secret = auxprop_values[1].values[0];
  177. sasl_secret_t *construct;
  178. ret = _sasl_make_plain_secret(db_secret, passwd,
  179. strlen(passwd),
  180. &construct);
  181. if (ret != SASL_OK) {
  182. goto done;
  183. }
  184. if (!memcmp(db_secret, construct->data, construct->len)) {
  185. /* password verified! */
  186. ret = SASL_OK;
  187. } else {
  188. /* passwords do not match */
  189. ret = SASL_BADAUTH;
  190. }
  191. sasl_FREE(construct);
  192. } else {
  193. /* passwords do not match */
  194. ret = SASL_BADAUTH;
  195. }
  196. /* erase the plaintext password */
  197. sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
  198. password_request[0]);
  199. done:
  200. /* We're not going to erase the property here because other people
  201. * may want it */
  202. return ret;
  203. }
  204. #if 0
  205. /* Verify user password using auxprop plugins. Allow verification against a hashed password,
  206. * or non-retrievable password. Don't use cmusaslsecretPLAIN attribute.
  207. *
  208. * This function is similar to auxprop_verify_password().
  209. */
  210. static int auxprop_verify_password_hashed(sasl_conn_t *conn,
  211. const char *userstr,
  212. const char *passwd,
  213. const char *service __attribute__((unused)),
  214. const char *user_realm __attribute__((unused)))
  215. {
  216. int ret = SASL_FAIL;
  217. int result = SASL_OK;
  218. sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
  219. const char *password_request[] = { SASL_AUX_PASSWORD,
  220. NULL };
  221. struct propval auxprop_values[2];
  222. unsigned extra_cu_flags = 0;
  223. if (!conn || !userstr)
  224. return SASL_BADPARAM;
  225. /* We need to clear any previous results and re-canonify to
  226. * ensure correctness */
  227. prop_clear(sconn->sparams->propctx, 0);
  228. /* ensure its requested */
  229. result = prop_request(sconn->sparams->propctx, password_request);
  230. if (result != SASL_OK) return result;
  231. /* We need to pass "password" down to the auxprop_lookup */
  232. /* NB: We don't support binary passwords */
  233. if (passwd != NULL) {
  234. prop_set (sconn->sparams->propctx,
  235. SASL_AUX_PASSWORD,
  236. passwd,
  237. -1);
  238. extra_cu_flags = SASL_CU_VERIFY_AGAINST_HASH;
  239. }
  240. result = _sasl_canon_user_lookup (conn,
  241. userstr,
  242. 0,
  243. SASL_CU_AUTHID | SASL_CU_AUTHZID | extra_cu_flags,
  244. &(conn->oparams));
  245. if (result != SASL_OK) return result;
  246. result = prop_getnames(sconn->sparams->propctx, password_request,
  247. auxprop_values);
  248. if (result < 0) {
  249. return result;
  250. }
  251. /* Verify that the returned <name>s are correct.
  252. But we defer checking for NULL values till after we verify
  253. that a passwd is specified. */
  254. if (!auxprop_values[0].name && !auxprop_values[1].name) {
  255. return SASL_NOUSER;
  256. }
  257. /* It is possible for us to get useful information out of just
  258. * the lookup, so we won't check that we have a password until now */
  259. if (!passwd) {
  260. ret = SASL_BADPARAM;
  261. goto done;
  262. }
  263. if ((!auxprop_values[0].values || !auxprop_values[0].values[0])) {
  264. return SASL_NOUSER;
  265. }
  266. /* At the point this has been called, the username has been canonified
  267. * and we've done the auxprop lookup. This should be easy. */
  268. /* NB: Note that if auxprop_lookup failed to verify the password,
  269. then the userPassword property value would be NULL */
  270. if (auxprop_values[0].name
  271. && auxprop_values[0].values
  272. && auxprop_values[0].values[0]
  273. && !strcmp(auxprop_values[0].values[0], passwd)) {
  274. /* We have a plaintext version and it matched! */
  275. return SASL_OK;
  276. } else {
  277. /* passwords do not match */
  278. ret = SASL_BADAUTH;
  279. }
  280. done:
  281. /* We're not going to erase the property here because other people
  282. * may want it */
  283. return ret;
  284. }
  285. #endif
  286. #ifdef DO_SASL_CHECKAPOP
  287. int _sasl_auxprop_verify_apop(sasl_conn_t *conn,
  288. const char *userstr,
  289. const char *challenge,
  290. const char *response,
  291. const char *user_realm __attribute__((unused)))
  292. {
  293. int ret = SASL_BADAUTH;
  294. char *userid = NULL;
  295. char *realm = NULL;
  296. unsigned char digest[16];
  297. char digeststr[33];
  298. const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
  299. struct propval auxprop_values[2];
  300. sasl_server_conn_t *sconn = (sasl_server_conn_t *)conn;
  301. MD5_CTX ctx;
  302. int i;
  303. if (!conn || !userstr || !challenge || !response)
  304. PARAMERROR(conn)
  305. /* We've done the auxprop lookup already (in our caller) */
  306. /* sadly, APOP has no provision for storing secrets */
  307. ret = prop_getnames(sconn->sparams->propctx, password_request,
  308. auxprop_values);
  309. if(ret < 0) {
  310. sasl_seterror(conn, 0, "could not perform password lookup");
  311. goto done;
  312. }
  313. if(!auxprop_values[0].name ||
  314. !auxprop_values[0].values ||
  315. !auxprop_values[0].values[0]) {
  316. sasl_seterror(conn, 0, "could not find password");
  317. ret = SASL_NOUSER;
  318. goto done;
  319. }
  320. _sasl_MD5Init(&ctx);
  321. _sasl_MD5Update(&ctx, (const unsigned char *) challenge, strlen(challenge));
  322. _sasl_MD5Update(&ctx, (const unsigned char *) auxprop_values[0].values[0],
  323. strlen(auxprop_values[0].values[0]));
  324. _sasl_MD5Final(digest, &ctx);
  325. /* erase the plaintext password */
  326. sconn->sparams->utils->prop_erase(sconn->sparams->propctx,
  327. password_request[0]);
  328. /* convert digest from binary to ASCII hex */
  329. for (i = 0; i < 16; i++)
  330. sprintf(digeststr + (i*2), "%02x", digest[i]);
  331. if (!strncasecmp(digeststr, response, 32)) {
  332. /* password verified! */
  333. ret = SASL_OK;
  334. } else {
  335. /* passwords do not match */
  336. ret = SASL_BADAUTH;
  337. }
  338. done:
  339. if (ret == SASL_BADAUTH) sasl_seterror(conn, SASL_NOLOG,
  340. "login incorrect");
  341. if (userid) sasl_FREE(userid);
  342. if (realm) sasl_FREE(realm);
  343. return ret;
  344. }
  345. #endif /* DO_SASL_CHECKAPOP */
  346. #if defined(HAVE_PWCHECK) || defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
  347. /*
  348. * Wait for file descriptor to be writable. Return with error if timeout.
  349. */
  350. static int write_wait(int fd, unsigned delta)
  351. {
  352. fd_set wfds;
  353. fd_set efds;
  354. struct timeval tv;
  355. /*
  356. * Wait for file descriptor fd to be writable. Retry on
  357. * interruptions. Return with error upon timeout.
  358. */
  359. while (1) {
  360. FD_ZERO(&wfds);
  361. FD_ZERO(&efds);
  362. FD_SET(fd, &wfds);
  363. FD_SET(fd, &efds);
  364. tv.tv_sec = (long) delta;
  365. tv.tv_usec = 0;
  366. switch(select(fd + 1, 0, &wfds, &efds, &tv)) {
  367. case 0:
  368. /* Timeout. */
  369. errno = ETIMEDOUT;
  370. return -1;
  371. case +1:
  372. if (FD_ISSET(fd, &wfds)) {
  373. /* Success, file descriptor is writable. */
  374. return 0;
  375. }
  376. return -1;
  377. case -1:
  378. if (errno == EINTR || errno == EAGAIN)
  379. continue;
  380. return -1;
  381. default:
  382. /* Error catch-all. */
  383. return -1;
  384. }
  385. }
  386. /* Not reached. */
  387. return -1;
  388. }
  389. /*
  390. * Keep calling the writev() system call with 'fd', 'iov', and 'iovcnt'
  391. * until all the data is written out or an error/timeout occurs.
  392. */
  393. static int retry_writev(int fd, struct iovec *iov, int iovcnt, unsigned delta)
  394. {
  395. int n;
  396. int i;
  397. int written = 0;
  398. static int iov_max =
  399. #ifdef MAXIOV
  400. MAXIOV
  401. #else
  402. #ifdef IOV_MAX
  403. IOV_MAX
  404. #else
  405. 8192
  406. #endif
  407. #endif
  408. ;
  409. for (;;) {
  410. while (iovcnt && iov[0].iov_len == 0) {
  411. iov++;
  412. iovcnt--;
  413. }
  414. if (!iovcnt) return written;
  415. if (delta > 0) {
  416. if (write_wait(fd, delta))
  417. return -1;
  418. }
  419. n = writev(fd, iov, iovcnt > iov_max ? iov_max : iovcnt);
  420. if (n == -1) {
  421. if (errno == EINVAL && iov_max > 10) {
  422. iov_max /= 2;
  423. continue;
  424. }
  425. if (errno == EINTR) continue;
  426. return -1;
  427. }
  428. written += n;
  429. for (i = 0; i < iovcnt; i++) {
  430. if ((int) iov[i].iov_len > n) {
  431. iov[i].iov_base = (char *)iov[i].iov_base + n;
  432. iov[i].iov_len -= n;
  433. break;
  434. }
  435. n -= iov[i].iov_len;
  436. iov[i].iov_len = 0;
  437. }
  438. if (i == iovcnt) return written;
  439. }
  440. }
  441. #endif
  442. #ifdef HAVE_PWCHECK
  443. /* pwcheck daemon-authenticated login */
  444. static int pwcheck_verify_password(sasl_conn_t *conn,
  445. const char *userid,
  446. const char *passwd,
  447. const char *service __attribute__((unused)),
  448. const char *user_realm
  449. __attribute__((unused)))
  450. {
  451. int s;
  452. struct sockaddr_un srvaddr;
  453. int r;
  454. struct iovec iov[10];
  455. static char response[1024];
  456. unsigned start, n;
  457. char pwpath[1024];
  458. if (strlen(PWCHECKDIR)+8+1 > sizeof(pwpath)) return SASL_FAIL;
  459. strcpy(pwpath, PWCHECKDIR);
  460. strcat(pwpath, "/pwcheck");
  461. s = socket(AF_UNIX, SOCK_STREAM, 0);
  462. if (s == -1) return errno;
  463. memset((char *)&srvaddr, 0, sizeof(srvaddr));
  464. srvaddr.sun_family = AF_UNIX;
  465. strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path));
  466. r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
  467. if (r == -1) {
  468. sasl_seterror(conn,0,"cannot connect to pwcheck server");
  469. return SASL_FAIL;
  470. }
  471. iov[0].iov_base = (char *)userid;
  472. iov[0].iov_len = strlen(userid)+1;
  473. iov[1].iov_base = (char *)passwd;
  474. iov[1].iov_len = strlen(passwd)+1;
  475. retry_writev(s, iov, 2, 0);
  476. start = 0;
  477. while (start < sizeof(response) - 1) {
  478. n = read(s, response+start, sizeof(response) - 1 - start);
  479. if (n < 1) break;
  480. start += n;
  481. }
  482. close(s);
  483. if (start > 1 && !strncmp(response, "OK", 2)) {
  484. return SASL_OK;
  485. }
  486. response[start] = '\0';
  487. sasl_seterror(conn,0,response);
  488. return SASL_BADAUTH;
  489. }
  490. #endif
  491. #if defined(HAVE_SASLAUTHD) || defined(HAVE_AUTHDAEMON)
  492. static int read_wait(int fd, unsigned delta)
  493. {
  494. fd_set rfds;
  495. fd_set efds;
  496. struct timeval tv;
  497. /*
  498. * Wait for file descriptor fd to be readable. Retry on
  499. * interruptions. Return with error upon timeout.
  500. */
  501. while (1) {
  502. FD_ZERO(&rfds);
  503. FD_ZERO(&efds);
  504. FD_SET(fd, &rfds);
  505. FD_SET(fd, &efds);
  506. tv.tv_sec = (long) delta;
  507. tv.tv_usec = 0;
  508. switch(select(fd + 1, &rfds, 0, &efds, &tv)) {
  509. case 0:
  510. /* Timeout. */
  511. errno = ETIMEDOUT;
  512. return -1;
  513. case +1:
  514. case +2:
  515. if (FD_ISSET(fd, &rfds)) {
  516. /* Success, file descriptor is readable. */
  517. return 0;
  518. }
  519. return -1;
  520. case -1:
  521. if (errno == EINTR || errno == EAGAIN)
  522. continue;
  523. return -1;
  524. default:
  525. /* Error catch-all. */
  526. return -1;
  527. }
  528. }
  529. /* Not reached. */
  530. return -1;
  531. }
  532. /*
  533. * Keep calling the read() system call until all the data is read in,
  534. * timeout, EOF, or an error occurs. This function returns the number
  535. * of useful bytes, or -1 if timeout/error.
  536. */
  537. static int retry_read(int fd, void *buf0, unsigned nbyte, unsigned delta)
  538. {
  539. int nr;
  540. unsigned nleft = nbyte;
  541. char *buf = (char*) buf0;
  542. while (nleft >= 1) {
  543. if (delta > 0) {
  544. if (read_wait(fd, delta))
  545. return -1;
  546. }
  547. nr = read(fd, buf, nleft);
  548. if (nr < 0) {
  549. if (errno == EINTR || errno == EAGAIN)
  550. continue;
  551. return -1;
  552. } else if (nr == 0) {
  553. break;
  554. }
  555. buf += nr;
  556. nleft -= nr;
  557. }
  558. return nbyte - nleft;
  559. }
  560. #endif
  561. #ifdef HAVE_SASLAUTHD
  562. /* saslauthd-authenticated login */
  563. static int saslauthd_verify_password(sasl_conn_t *conn,
  564. const char *userid,
  565. const char *passwd,
  566. const char *service,
  567. const char *user_realm)
  568. {
  569. char response[1024];
  570. char query[8192];
  571. char *query_end = query;
  572. int s;
  573. struct sockaddr_un srvaddr;
  574. sasl_getopt_t *getopt;
  575. void *context;
  576. char pwpath[sizeof(srvaddr.sun_path)];
  577. const char *p = NULL;
  578. char *freeme = NULL;
  579. #ifdef USE_DOORS
  580. door_arg_t arg;
  581. #endif
  582. /* check to see if the user configured a rundir */
  583. if (_sasl_getcallback(conn, SASL_CB_GETOPT,
  584. (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
  585. getopt(context, NULL, "saslauthd_path", &p, NULL);
  586. }
  587. if (p) {
  588. if (strlen(p) >= sizeof(pwpath))
  589. return SASL_FAIL;
  590. strncpy(pwpath, p, sizeof(pwpath) - 1);
  591. pwpath[strlen(p)] = '\0';
  592. } else {
  593. if (strlen(PATH_SASLAUTHD_RUNDIR) + 4 + 1 > sizeof(pwpath))
  594. return SASL_FAIL;
  595. strcpy(pwpath, PATH_SASLAUTHD_RUNDIR "/mux");
  596. }
  597. /* Split out username/realm if necessary */
  598. if(strrchr(userid,'@') != NULL) {
  599. char *rtmp;
  600. if(_sasl_strdup(userid, &freeme, NULL) != SASL_OK)
  601. goto fail;
  602. userid = freeme;
  603. rtmp = strrchr(userid,'@');
  604. *rtmp = '\0';
  605. user_realm = rtmp + 1;
  606. }
  607. /*
  608. * build request of the form:
  609. *
  610. * count authid count password count service count realm
  611. */
  612. {
  613. unsigned short max_len, req_len, u_len, p_len, s_len, r_len;
  614. max_len = (unsigned short) sizeof(query);
  615. /* prevent buffer overflow */
  616. if ((strlen(userid) > USHRT_MAX) ||
  617. (strlen(passwd) > USHRT_MAX) ||
  618. (strlen(service) > USHRT_MAX) ||
  619. (user_realm && (strlen(user_realm) > USHRT_MAX))) {
  620. goto toobig;
  621. }
  622. u_len = (strlen(userid));
  623. p_len = (strlen(passwd));
  624. s_len = (strlen(service));
  625. r_len = ((user_realm ? strlen(user_realm) : 0));
  626. /* prevent buffer overflow */
  627. req_len = 30;
  628. if (max_len - req_len < u_len) goto toobig;
  629. req_len += u_len;
  630. if (max_len - req_len < p_len) goto toobig;
  631. req_len += p_len;
  632. if (max_len - req_len < s_len) goto toobig;
  633. req_len += s_len;
  634. if (max_len - req_len < r_len) goto toobig;
  635. u_len = htons(u_len);
  636. p_len = htons(p_len);
  637. s_len = htons(s_len);
  638. r_len = htons(r_len);
  639. memcpy(query_end, &u_len, sizeof(unsigned short));
  640. query_end += sizeof(unsigned short);
  641. while (*userid) *query_end++ = *userid++;
  642. memcpy(query_end, &p_len, sizeof(unsigned short));
  643. query_end += sizeof(unsigned short);
  644. while (*passwd) *query_end++ = *passwd++;
  645. memcpy(query_end, &s_len, sizeof(unsigned short));
  646. query_end += sizeof(unsigned short);
  647. while (*service) *query_end++ = *service++;
  648. memcpy(query_end, &r_len, sizeof(unsigned short));
  649. query_end += sizeof(unsigned short);
  650. if (user_realm) while (*user_realm) *query_end++ = *user_realm++;
  651. }
  652. #ifdef USE_DOORS
  653. s = open(pwpath, O_RDONLY);
  654. if (s < 0) {
  655. sasl_seterror(conn, 0, "cannot open door to saslauthd server: %m", errno);
  656. goto fail;
  657. }
  658. arg.data_ptr = query;
  659. arg.data_size = query_end - query;
  660. arg.desc_ptr = NULL;
  661. arg.desc_num = 0;
  662. arg.rbuf = response;
  663. arg.rsize = sizeof(response);
  664. if (door_call(s, &arg) < 0) {
  665. /* Parameters are undefined */
  666. close(s);
  667. sasl_seterror(conn, 0, "door call to saslauthd server failed: %m", errno);
  668. goto fail;
  669. }
  670. if (arg.data_ptr != response || arg.data_size >= sizeof(response)) {
  671. /* oh damn, we got back a really long response */
  672. munmap(arg.rbuf, arg.rsize);
  673. close(s);
  674. sasl_seterror(conn, 0, "saslauthd sent an overly long response");
  675. goto fail;
  676. }
  677. response[arg.data_size] = '\0';
  678. close(s);
  679. #else
  680. /* unix sockets */
  681. s = socket(AF_UNIX, SOCK_STREAM, 0);
  682. if (s == -1) {
  683. sasl_seterror(conn, 0, "cannot create socket for saslauthd: %m", errno);
  684. goto fail;
  685. }
  686. memset((char *)&srvaddr, 0, sizeof(srvaddr));
  687. srvaddr.sun_family = AF_UNIX;
  688. strncpy(srvaddr.sun_path, pwpath, sizeof(srvaddr.sun_path) - 1);
  689. srvaddr.sun_path[strlen(pwpath)] = '\0';
  690. {
  691. int r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
  692. if (r == -1) {
  693. close(s);
  694. sasl_seterror(conn, 0, "cannot connect to saslauthd server: %m", errno);
  695. goto fail;
  696. }
  697. }
  698. {
  699. struct iovec iov[8];
  700. iov[0].iov_len = query_end - query;
  701. iov[0].iov_base = query;
  702. if (retry_writev(s, iov, 1, 0) == -1) {
  703. close(s);
  704. sasl_seterror(conn, 0, "write failed");
  705. goto fail;
  706. }
  707. }
  708. {
  709. unsigned short count = 0;
  710. /*
  711. * read response of the form:
  712. *
  713. * count result
  714. */
  715. if (retry_read(s, &count, sizeof(count), 0) < (int) sizeof(count)) {
  716. sasl_seterror(conn, 0, "size read failed");
  717. goto fail;
  718. }
  719. count = ntohs(count);
  720. if (count < 2) { /* MUST have at least "OK" or "NO" */
  721. close(s);
  722. sasl_seterror(conn, 0, "bad response from saslauthd");
  723. goto fail;
  724. }
  725. count = (int)sizeof(response) <= count ? sizeof(response) - 1 : count;
  726. if (retry_read(s, response, count, 0) < count) {
  727. close(s);
  728. sasl_seterror(conn, 0, "read failed");
  729. goto fail;
  730. }
  731. response[count] = '\0';
  732. }
  733. close(s);
  734. #endif /* USE_DOORS */
  735. if(freeme) free(freeme);
  736. if (!strncmp(response, "OK", 2)) {
  737. return SASL_OK;
  738. }
  739. sasl_seterror(conn, SASL_NOLOG, "authentication failed");
  740. return SASL_BADAUTH;
  741. toobig:
  742. /* request just too damn big */
  743. sasl_seterror(conn, 0, "saslauthd request too large");
  744. fail:
  745. if (freeme) free(freeme);
  746. return SASL_FAIL;
  747. }
  748. #endif
  749. #ifdef HAVE_AUTHDAEMON
  750. /*
  751. * Preliminary support for Courier's authdaemond.
  752. */
  753. #define AUTHDAEMON_IO_TIMEOUT 30
  754. static int authdaemon_blocking(int fd, int block)
  755. {
  756. int f, r;
  757. /* Get the fd's blocking bit. */
  758. f = fcntl(fd, F_GETFL, 0);
  759. if (f == -1)
  760. return -1;
  761. /* Adjust the bitmap accordingly. */
  762. #ifndef O_NONBLOCK
  763. #define NB_BITMASK FNDELAY
  764. #else
  765. #define NB_BITMASK O_NONBLOCK
  766. #endif
  767. if (block)
  768. f &= ~NB_BITMASK;
  769. else
  770. f |= NB_BITMASK;
  771. #undef NB_BITMASK
  772. /* Adjust the fd's blocking bit. */
  773. r = fcntl(fd, F_SETFL, f);
  774. if (r)
  775. return -1;
  776. /* Success. */
  777. return 0;
  778. }
  779. static int authdaemon_connect(sasl_conn_t *conn, const char *path)
  780. {
  781. int r, s = -1;
  782. struct sockaddr_un srvaddr;
  783. if (strlen(path) >= sizeof(srvaddr.sun_path)) {
  784. sasl_seterror(conn, 0, "unix socket path too large", errno);
  785. goto fail;
  786. }
  787. s = socket(AF_UNIX, SOCK_STREAM, 0);
  788. if (s == -1) {
  789. sasl_seterror(conn, 0, "cannot create socket for connection to Courier authdaemond: %m", errno);
  790. goto fail;
  791. }
  792. memset((char *)&srvaddr, 0, sizeof(srvaddr));
  793. srvaddr.sun_family = AF_UNIX;
  794. strncpy(srvaddr.sun_path, path, sizeof(srvaddr.sun_path) - 1);
  795. /* Use nonblocking unix socket connect(2). */
  796. if (authdaemon_blocking(s, 0)) {
  797. sasl_seterror(conn, 0, "cannot set nonblocking bit: %m", errno);
  798. goto fail;
  799. }
  800. r = connect(s, (struct sockaddr *) &srvaddr, sizeof(srvaddr));
  801. if (r == -1) {
  802. sasl_seterror(conn, 0, "cannot connect to Courier authdaemond: %m", errno);
  803. goto fail;
  804. }
  805. if (authdaemon_blocking(s, 1)) {
  806. sasl_seterror(conn, 0, "cannot clear nonblocking bit: %m", errno);
  807. goto fail;
  808. }
  809. return s;
  810. fail:
  811. if (s >= 0)
  812. close(s);
  813. return -1;
  814. }
  815. static char *authdaemon_build_query(const char *service,
  816. const char *authtype,
  817. const char *user,
  818. const char *passwd)
  819. {
  820. int sz;
  821. int l = strlen(service)
  822. + 1
  823. + strlen(authtype)
  824. + 1
  825. + strlen(user)
  826. + 1
  827. + strlen(passwd)
  828. + 1;
  829. char *buf, n[5];
  830. if (snprintf(n, sizeof(n), "%d", l) >= (int)sizeof(n))
  831. return NULL;
  832. sz = strlen(n) + l + 20;
  833. if (!(buf = sasl_ALLOC(sz)))
  834. return NULL;
  835. snprintf(buf,
  836. sz,
  837. "AUTH %s\n%s\n%s\n%s\n%s\n\n",
  838. n,
  839. service,
  840. authtype,
  841. user,
  842. passwd);
  843. return buf;
  844. }
  845. static int authdaemon_read(int fd, void *buf0, unsigned sz)
  846. {
  847. int nr;
  848. char *buf = (char*) buf0;
  849. if (sz <= 1)
  850. return -1;
  851. if ((nr = retry_read(fd, buf0, sz - 1, AUTHDAEMON_IO_TIMEOUT)) < 0)
  852. return -1;
  853. /* We need a null-terminated buffer. */
  854. buf[nr] = 0;
  855. /* Check for overflow condition. */
  856. return nr + 1 < (int)sz ? 0 : -1;
  857. }
  858. static int authdaemon_write(int fd, void *buf0, unsigned sz)
  859. {
  860. int nw;
  861. struct iovec io;
  862. io.iov_len = sz;
  863. io.iov_base = buf0;
  864. nw = retry_writev(fd, &io, 1, AUTHDAEMON_IO_TIMEOUT);
  865. return nw == (int)sz ? 0 : -1;
  866. }
  867. static int authdaemon_talk(sasl_conn_t *conn, int sock, char *authreq)
  868. {
  869. char *str;
  870. char buf[8192];
  871. if (authdaemon_write(sock, authreq, strlen(authreq)))
  872. goto _err_out;
  873. if (authdaemon_read(sock, buf, sizeof(buf)))
  874. goto _err_out;
  875. for (str = buf; *str; ) {
  876. char *sub;
  877. for (sub = str; *str; ++str) {
  878. if (*str == '\n') {
  879. *str++ = 0;
  880. break;
  881. }
  882. }
  883. if (strcmp(sub, ".") == 0) {
  884. /* success */
  885. return SASL_OK;
  886. }
  887. if (strcmp(sub, "FAIL") == 0) {
  888. /* passwords do not match */
  889. sasl_seterror(conn, SASL_NOLOG, "authentication failed");
  890. return SASL_BADAUTH;
  891. }
  892. }
  893. _err_out:
  894. /* catchall: authentication error */
  895. sasl_seterror(conn, 0, "could not verify password");
  896. return SASL_FAIL;
  897. }
  898. static int authdaemon_verify_password(sasl_conn_t *conn,
  899. const char *userid,
  900. const char *passwd,
  901. const char *service,
  902. const char *user_realm __attribute__((unused)))
  903. {
  904. const char *p = NULL;
  905. sasl_getopt_t *getopt;
  906. void *context;
  907. int result = SASL_FAIL;
  908. char *query = NULL;
  909. int sock = -1;
  910. /* check to see if the user configured a rundir */
  911. if (_sasl_getcallback(conn, SASL_CB_GETOPT,
  912. (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
  913. getopt(context, NULL, "authdaemond_path", &p, NULL);
  914. }
  915. if (!p) {
  916. /*
  917. * XXX should we peek at Courier's build-time config ?
  918. */
  919. p = PATH_AUTHDAEMON_SOCKET;
  920. }
  921. if ((sock = authdaemon_connect(conn, p)) < 0)
  922. goto out;
  923. if (!(query = authdaemon_build_query(service, "login", userid, passwd)))
  924. goto out;
  925. result = authdaemon_talk(conn, sock, query);
  926. out:
  927. if (sock >= 0)
  928. close(sock), sock = -1;
  929. if (query)
  930. sasl_FREE(query), query = 0;
  931. return result;
  932. }
  933. #endif
  934. #ifdef HAVE_ALWAYSTRUE
  935. static int always_true(sasl_conn_t *conn,
  936. const char *userstr,
  937. const char *passwd __attribute__((unused)),
  938. const char *service __attribute__((unused)),
  939. const char *user_realm __attribute__((unused)))
  940. {
  941. _sasl_log(conn, SASL_LOG_WARN, "AlwaysTrue Password Verifier Verified: %s",
  942. userstr);
  943. return SASL_OK;
  944. }
  945. #endif
  946. struct sasl_verify_password_s _sasl_verify_password[] = {
  947. { "auxprop", &auxprop_verify_password },
  948. #if 0 /* totally undocumented. wtf is this? */
  949. { "auxprop-hashed", &auxprop_verify_password_hashed },
  950. #endif
  951. #ifdef HAVE_PWCHECK
  952. { "pwcheck", &pwcheck_verify_password },
  953. #endif
  954. #ifdef HAVE_SASLAUTHD
  955. { "saslauthd", &saslauthd_verify_password },
  956. #endif
  957. #ifdef HAVE_AUTHDAEMON
  958. { "authdaemond", &authdaemon_verify_password },
  959. #endif
  960. #ifdef HAVE_ALWAYSTRUE
  961. { "alwaystrue", &always_true },
  962. #endif
  963. { NULL, NULL }
  964. };