sasldb.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. /* sasldb stuff */
  47. #include <stdio.h>
  48. #include "sasl.h"
  49. #include "saslutil.h"
  50. #include "saslplug.h"
  51. #include "../sasldb/sasldb.h"
  52. #include "plugin_common.h"
  53. static int sasldb_auxprop_lookup(void *glob_context __attribute__((unused)),
  54. sasl_server_params_t *sparams,
  55. unsigned flags,
  56. const char *user,
  57. unsigned ulen)
  58. {
  59. char *userid = NULL;
  60. char *realm = NULL;
  61. const char *user_realm = NULL;
  62. int ret;
  63. const struct propval *to_fetch, *cur;
  64. char value[8192];
  65. size_t value_len;
  66. char *user_buf;
  67. int verify_against_hashed_password;
  68. int saw_user_password = 0;
  69. if (!sparams || !user) return SASL_BADPARAM;
  70. user_buf = sparams->utils->malloc(ulen + 1);
  71. if(!user_buf) {
  72. ret = SASL_NOMEM;
  73. goto done;
  74. }
  75. memcpy(user_buf, user, ulen);
  76. user_buf[ulen] = '\0';
  77. if(sparams->user_realm) {
  78. user_realm = sparams->user_realm;
  79. } else {
  80. user_realm = sparams->serverFQDN;
  81. }
  82. ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
  83. sparams->serverFQDN, user_buf);
  84. if(ret != SASL_OK) goto done;
  85. to_fetch = sparams->utils->prop_get(sparams->propctx);
  86. if (!to_fetch) {
  87. ret = SASL_NOMEM;
  88. goto done;
  89. }
  90. verify_against_hashed_password = flags & SASL_AUXPROP_VERIFY_AGAINST_HASH;
  91. /* Use a fake value to signal that we have no property to lookup */
  92. ret = SASL_CONTINUE;
  93. for(cur = to_fetch; cur->name; cur++) {
  94. int cur_ret;
  95. const char *realname = cur->name;
  96. /* Only look up properties that apply to this lookup! */
  97. if(cur->name[0] == '*' && (flags & SASL_AUXPROP_AUTHZID)) continue;
  98. if(!(flags & SASL_AUXPROP_AUTHZID)) {
  99. if(cur->name[0] != '*') continue;
  100. else realname = cur->name + 1;
  101. }
  102. /* If it's there already, we want to see if it needs to be
  103. * overridden. userPassword is a special case, because it's value
  104. is always present if SASL_AUXPROP_VERIFY_AGAINST_HASH is specified.
  105. When SASL_AUXPROP_VERIFY_AGAINST_HASH is set, we just clear userPassword. */
  106. if (cur->values && !(flags & SASL_AUXPROP_OVERRIDE) &&
  107. (verify_against_hashed_password == 0 ||
  108. strcasecmp(realname, SASL_AUX_PASSWORD_PROP) != 0)) {
  109. continue;
  110. } else if (cur->values) {
  111. sparams->utils->prop_erase(sparams->propctx, cur->name);
  112. }
  113. if (strcasecmp(realname, SASL_AUX_PASSWORD_PROP) == 0) {
  114. saw_user_password = 1;
  115. }
  116. cur_ret = _sasldb_getdata(sparams->utils,
  117. sparams->utils->conn, userid, realm,
  118. realname, value, sizeof(value), &value_len);
  119. /* Assumption: cur_ret is never SASL_CONTINUE */
  120. /* If this is the first property we've tried to fetch ==>
  121. always set the global error code.
  122. If we had SASL_NOUSER ==> any other error code overrides it
  123. (including SASL_NOUSER). */
  124. if (ret == SASL_CONTINUE || ret == SASL_NOUSER) {
  125. ret = cur_ret;
  126. } else if (ret == SASL_OK) {
  127. /* Any error code other than SASL_NOUSER overrides SASL_OK.
  128. (And SASL_OK overrides SASL_OK as well) */
  129. if (cur_ret != SASL_NOUSER) {
  130. ret = cur_ret;
  131. }
  132. }
  133. /* Any other global error code is left as is */
  134. if (cur_ret != SASL_OK) {
  135. if (cur_ret != SASL_NOUSER) {
  136. /* No point in continuing if we hit any serious error */
  137. break;
  138. }
  139. /* We didn't find it, leave it as not found */
  140. continue;
  141. }
  142. sparams->utils->prop_set(sparams->propctx, cur->name,
  143. value, (unsigned) value_len);
  144. }
  145. /* [Keep in sync with LDAPDB, SQL]
  146. If ret is SASL_CONTINUE, it means that no properties were requested
  147. (or maybe some were requested, but they already have values and
  148. SASL_AUXPROP_OVERRIDE flag is not set).
  149. Always return SASL_OK in this case. */
  150. if (ret == SASL_CONTINUE) {
  151. ret = SASL_OK;
  152. }
  153. if (flags & SASL_AUXPROP_AUTHZID) {
  154. /* This is a lie, but the caller can't handle
  155. when we return SASL_NOUSER for authorization identity lookup. */
  156. if (ret == SASL_NOUSER) {
  157. ret = SASL_OK;
  158. }
  159. } else {
  160. if (ret == SASL_NOUSER && saw_user_password == 0) {
  161. /* Verify user existence by checking presence of
  162. the userPassword attribute */
  163. ret = _sasldb_getdata(sparams->utils,
  164. sparams->utils->conn,
  165. userid,
  166. realm,
  167. SASL_AUX_PASSWORD_PROP,
  168. value,
  169. sizeof(value),
  170. &value_len);
  171. }
  172. }
  173. done:
  174. if (userid) sparams->utils->free(userid);
  175. if (realm) sparams->utils->free(realm);
  176. if (user_buf) sparams->utils->free(user_buf);
  177. return ret;
  178. }
  179. static int sasldb_auxprop_store(void *glob_context __attribute__((unused)),
  180. sasl_server_params_t *sparams,
  181. struct propctx *ctx,
  182. const char *user,
  183. unsigned ulen)
  184. {
  185. char *userid = NULL;
  186. char *realm = NULL;
  187. const char *user_realm = NULL;
  188. int ret = SASL_FAIL;
  189. const struct propval *to_store, *cur;
  190. char *user_buf;
  191. /* just checking if we are enabled */
  192. if(!ctx) return SASL_OK;
  193. if(!sparams || !user) return SASL_BADPARAM;
  194. user_buf = sparams->utils->malloc(ulen + 1);
  195. if(!user_buf) {
  196. ret = SASL_NOMEM;
  197. goto done;
  198. }
  199. memcpy(user_buf, user, ulen);
  200. user_buf[ulen] = '\0';
  201. if(sparams->user_realm) {
  202. user_realm = sparams->user_realm;
  203. } else {
  204. user_realm = sparams->serverFQDN;
  205. }
  206. ret = _plug_parseuser(sparams->utils, &userid, &realm, user_realm,
  207. sparams->serverFQDN, user_buf);
  208. if(ret != SASL_OK) goto done;
  209. to_store = sparams->utils->prop_get(ctx);
  210. if(!to_store) {
  211. ret = SASL_BADPARAM;
  212. goto done;
  213. }
  214. ret = SASL_OK;
  215. for (cur = to_store; cur->name; cur++) {
  216. const char *value = (cur->values && cur->values[0]) ? cur->values[0] : NULL;
  217. if (cur->name[0] == '*') {
  218. continue;
  219. }
  220. /* WARN: We only support one value right now. */
  221. ret = _sasldb_putdata(sparams->utils,
  222. sparams->utils->conn,
  223. userid,
  224. realm,
  225. cur->name,
  226. value,
  227. value ? strlen(value) : 0);
  228. if (value == NULL && ret == SASL_NOUSER) {
  229. /* Deleting something which is not there is not an error */
  230. ret = SASL_OK;
  231. }
  232. if (ret != SASL_OK) {
  233. /* We've already failed, no point in continuing */
  234. break;
  235. }
  236. }
  237. done:
  238. if (userid) sparams->utils->free(userid);
  239. if (realm) sparams->utils->free(realm);
  240. if (user_buf) sparams->utils->free(user_buf);
  241. return ret;
  242. }
  243. static sasl_auxprop_plug_t sasldb_auxprop_plugin = {
  244. 0, /* Features */
  245. 0, /* spare */
  246. NULL, /* glob_context */
  247. sasldb_auxprop_free, /* auxprop_free */
  248. sasldb_auxprop_lookup, /* auxprop_lookup */
  249. "sasldb", /* name */
  250. sasldb_auxprop_store /* auxprop_store */
  251. };
  252. int sasldb_auxprop_plug_init(const sasl_utils_t *utils,
  253. int max_version,
  254. int *out_version,
  255. sasl_auxprop_plug_t **plug,
  256. const char *plugname __attribute__((unused)))
  257. {
  258. if(!out_version || !plug) return SASL_BADPARAM;
  259. /* Do we have database support? */
  260. /* Note that we can use a NULL sasl_conn_t because our
  261. * sasl_utils_t is "blessed" with the global callbacks */
  262. if(_sasl_check_db(utils, NULL) != SASL_OK)
  263. return SASL_NOMECH;
  264. /* Check if libsasl API is older than ours. If it is, fail */
  265. if(max_version < SASL_AUXPROP_PLUG_VERSION) return SASL_BADVERS;
  266. *out_version = SASL_AUXPROP_PLUG_VERSION;
  267. *plug = &sasldb_auxprop_plugin;
  268. return SASL_OK;
  269. }