canonusr.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. /* canonusr.c - user canonicalization support
  2. * Rob Siemborski
  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 <sasl.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. #include <prop.h>
  49. #include <stdio.h>
  50. #include "saslint.h"
  51. typedef struct canonuser_plug_list
  52. {
  53. struct canonuser_plug_list *next;
  54. char name[PATH_MAX];
  55. const sasl_canonuser_plug_t *plug;
  56. } canonuser_plug_list_t;
  57. static canonuser_plug_list_t *canonuser_head = NULL;
  58. /* default behavior:
  59. * eliminate leading & trailing whitespace,
  60. * null-terminate, and get into the outparams
  61. * (handled by INTERNAL plugin) */
  62. /* a zero ulen or alen indicates that it is strlen(value) */
  63. int _sasl_canon_user(sasl_conn_t *conn,
  64. const char *user, unsigned ulen,
  65. unsigned flags,
  66. sasl_out_params_t *oparams)
  67. {
  68. canonuser_plug_list_t *ptr;
  69. sasl_server_conn_t *sconn = NULL;
  70. sasl_client_conn_t *cconn = NULL;
  71. sasl_canon_user_t *cuser_cb;
  72. sasl_getopt_t *getopt;
  73. void *context;
  74. int result;
  75. const char *plugin_name = NULL;
  76. char *user_buf;
  77. unsigned *lenp;
  78. if(!conn) return SASL_BADPARAM;
  79. if(!user || !oparams) return SASL_BADPARAM;
  80. if(flags & SASL_CU_AUTHID) {
  81. user_buf = conn->authid_buf;
  82. lenp = &(oparams->alen);
  83. } else if (flags & SASL_CU_AUTHZID) {
  84. user_buf = conn->user_buf;
  85. lenp = &(oparams->ulen);
  86. } else {
  87. return SASL_BADPARAM;
  88. }
  89. if (conn->type == SASL_CONN_SERVER)
  90. sconn = (sasl_server_conn_t *)conn;
  91. else if (conn->type == SASL_CONN_CLIENT)
  92. cconn = (sasl_client_conn_t *)conn;
  93. else return SASL_FAIL;
  94. if(!ulen) ulen = (unsigned int)strlen(user);
  95. /* check to see if we have a callback to make*/
  96. result = _sasl_getcallback(conn,
  97. SASL_CB_CANON_USER,
  98. (sasl_callback_ft *)&cuser_cb,
  99. &context);
  100. if(result == SASL_OK && cuser_cb) {
  101. result = cuser_cb(conn,
  102. context,
  103. user,
  104. ulen,
  105. flags,
  106. (sconn ?
  107. sconn->user_realm :
  108. NULL),
  109. user_buf,
  110. CANON_BUF_SIZE,
  111. lenp);
  112. if (result != SASL_OK) return result;
  113. /* Point the input copy at the stored buffer */
  114. user = user_buf;
  115. ulen = *lenp;
  116. }
  117. /* which plugin are we supposed to use? */
  118. result = _sasl_getcallback(conn,
  119. SASL_CB_GETOPT,
  120. (sasl_callback_ft *)&getopt,
  121. &context);
  122. if (result == SASL_OK && getopt) {
  123. getopt(context, NULL, "canon_user_plugin", &plugin_name, NULL);
  124. }
  125. if (!plugin_name) {
  126. /* Use Default */
  127. plugin_name = "INTERNAL";
  128. }
  129. for (ptr = canonuser_head; ptr; ptr = ptr->next) {
  130. /* A match is if we match the internal name of the plugin, or if
  131. * we match the filename (old-style) */
  132. if ((ptr->plug->name && !strcmp(plugin_name, ptr->plug->name))
  133. || !strcmp(plugin_name, ptr->name)) break;
  134. }
  135. /* We clearly don't have this one! */
  136. if (!ptr) {
  137. sasl_seterror(conn, 0, "desired canon_user plugin %s not found",
  138. plugin_name);
  139. return SASL_NOMECH;
  140. }
  141. if (sconn) {
  142. /* we're a server */
  143. result = ptr->plug->canon_user_server(ptr->plug->glob_context,
  144. sconn->sparams,
  145. user, ulen,
  146. flags,
  147. user_buf,
  148. CANON_BUF_SIZE, lenp);
  149. } else {
  150. /* we're a client */
  151. result = ptr->plug->canon_user_client(ptr->plug->glob_context,
  152. cconn->cparams,
  153. user, ulen,
  154. flags,
  155. user_buf,
  156. CANON_BUF_SIZE, lenp);
  157. }
  158. if (result != SASL_OK) return result;
  159. if ((flags & SASL_CU_AUTHID) && (flags & SASL_CU_AUTHZID)) {
  160. /* We did both, so we need to copy the result into
  161. * the buffer for the authzid from the buffer for the authid */
  162. memcpy(conn->user_buf, conn->authid_buf, CANON_BUF_SIZE);
  163. oparams->ulen = oparams->alen;
  164. }
  165. /* Set the appropriate oparams (lengths have already been set by lenp) */
  166. if (flags & SASL_CU_AUTHID) {
  167. oparams->authid = conn->authid_buf;
  168. }
  169. if (flags & SASL_CU_AUTHZID) {
  170. oparams->user = conn->user_buf;
  171. }
  172. RETURN(conn, result);
  173. }
  174. /* Lookup all properties for authentication and/or authorization identity. */
  175. static int _sasl_auxprop_lookup_user_props (sasl_conn_t *conn,
  176. unsigned flags,
  177. sasl_out_params_t *oparams)
  178. {
  179. sasl_server_conn_t *sconn = NULL;
  180. int result = SASL_OK;
  181. if (!conn) return SASL_BADPARAM;
  182. if (!oparams) return SASL_BADPARAM;
  183. #ifndef macintosh
  184. if (conn->type == SASL_CONN_SERVER) sconn = (sasl_server_conn_t *)conn;
  185. /* do auxprop lookups (server only) */
  186. if (sconn) {
  187. int authz_result;
  188. unsigned auxprop_lookup_flags = flags & SASL_CU_ASIS_MASK;
  189. if (flags & SASL_CU_OVERRIDE) {
  190. auxprop_lookup_flags |= SASL_AUXPROP_OVERRIDE;
  191. }
  192. if (flags & SASL_CU_AUTHID) {
  193. result = _sasl_auxprop_lookup(sconn->sparams,
  194. auxprop_lookup_flags,
  195. oparams->authid,
  196. oparams->alen);
  197. } else {
  198. result = SASL_CONTINUE;
  199. }
  200. if (flags & SASL_CU_AUTHZID) {
  201. authz_result = _sasl_auxprop_lookup(sconn->sparams,
  202. auxprop_lookup_flags | SASL_AUXPROP_AUTHZID,
  203. oparams->user,
  204. oparams->ulen);
  205. if (result == SASL_CONTINUE) {
  206. /* Only SASL_CU_AUTHZID was requested.
  207. The authz_result value is authoritative. */
  208. result = authz_result;
  209. } else if (result == SASL_OK && authz_result != SASL_NOUSER) {
  210. /* Use the authz_result value, unless "result"
  211. already contains an error */
  212. result = authz_result;
  213. }
  214. }
  215. if ((flags & SASL_CU_EXTERNALLY_VERIFIED) && (result == SASL_NOUSER || result == SASL_NOMECH)) {
  216. /* The called has explicitly told us that the authentication identity
  217. was already verified or will be verified independently.
  218. So a failure to retrieve any associated properties
  219. is not an error. For example the caller is using Kerberos to verify user,
  220. but the LDAPDB/SASLDB auxprop plugin doesn't contain any auxprops for
  221. the user.
  222. Another case is PLAIN/LOGIN not using auxprop to verify user passwords. */
  223. result = SASL_OK;
  224. }
  225. }
  226. #endif
  227. RETURN(conn, result);
  228. }
  229. /* default behavior:
  230. * Eliminate leading & trailing whitespace,
  231. * null-terminate, and get into the outparams
  232. * (handled by INTERNAL plugin).
  233. *
  234. * Server only: Also does auxprop lookups once username
  235. * is canonicalized. */
  236. int _sasl_canon_user_lookup (sasl_conn_t *conn,
  237. const char *user,
  238. unsigned ulen,
  239. unsigned flags,
  240. sasl_out_params_t *oparams)
  241. {
  242. int result;
  243. result = _sasl_canon_user (conn,
  244. user,
  245. ulen,
  246. flags,
  247. oparams);
  248. if (result == SASL_OK) {
  249. result = _sasl_auxprop_lookup_user_props (conn,
  250. flags,
  251. oparams);
  252. }
  253. RETURN(conn, result);
  254. }
  255. void _sasl_canonuser_free()
  256. {
  257. canonuser_plug_list_t *ptr, *ptr_next;
  258. for(ptr = canonuser_head; ptr; ptr = ptr_next) {
  259. ptr_next = ptr->next;
  260. if(ptr->plug->canon_user_free)
  261. ptr->plug->canon_user_free(ptr->plug->glob_context,
  262. sasl_global_utils);
  263. sasl_FREE(ptr);
  264. }
  265. canonuser_head = NULL;
  266. }
  267. int sasl_canonuser_add_plugin(const char *plugname,
  268. sasl_canonuser_init_t *canonuserfunc)
  269. {
  270. int result, out_version;
  271. canonuser_plug_list_t *new_item;
  272. sasl_canonuser_plug_t *plug;
  273. if(!plugname || strlen(plugname) > (PATH_MAX - 1)) {
  274. sasl_seterror(NULL, 0,
  275. "bad plugname passed to sasl_canonuser_add_plugin\n");
  276. return SASL_BADPARAM;
  277. }
  278. result = canonuserfunc(sasl_global_utils, SASL_CANONUSER_PLUG_VERSION,
  279. &out_version, &plug, plugname);
  280. if(result != SASL_OK) {
  281. _sasl_log(NULL, SASL_LOG_ERR, "%s_canonuser_plug_init() failed in sasl_canonuser_add_plugin(): %z\n",
  282. plugname, result);
  283. return result;
  284. }
  285. if(!plug->canon_user_server && !plug->canon_user_client) {
  286. /* We need at least one of these implemented */
  287. _sasl_log(NULL, SASL_LOG_ERR,
  288. "canonuser plugin '%s' without either client or server side", plugname);
  289. return SASL_BADPROT;
  290. }
  291. new_item = sasl_ALLOC(sizeof(canonuser_plug_list_t));
  292. if(!new_item) return SASL_NOMEM;
  293. strncpy(new_item->name, plugname, PATH_MAX - 1);
  294. new_item->name[strlen(plugname)] = '\0';
  295. new_item->plug = plug;
  296. new_item->next = canonuser_head;
  297. canonuser_head = new_item;
  298. return SASL_OK;
  299. }
  300. #ifdef MIN
  301. #undef MIN
  302. #endif
  303. #define MIN(a,b) (((a) < (b))? (a):(b))
  304. static int _canonuser_internal(const sasl_utils_t *utils,
  305. const char *user, unsigned ulen,
  306. unsigned flags __attribute__((unused)),
  307. char *out_user,
  308. unsigned out_umax, unsigned *out_ulen)
  309. {
  310. unsigned i;
  311. char *in_buf, *userin;
  312. const char *begin_u;
  313. unsigned u_apprealm = 0;
  314. sasl_server_conn_t *sconn = NULL;
  315. if(!utils || !user) return SASL_BADPARAM;
  316. in_buf = sasl_ALLOC((ulen + 2) * sizeof(char));
  317. if(!in_buf) return SASL_NOMEM;
  318. userin = in_buf;
  319. memcpy(userin, user, ulen);
  320. userin[ulen] = '\0';
  321. /* Strip User ID */
  322. for(i=0;isspace((int)userin[i]) && i<ulen;i++);
  323. begin_u = &(userin[i]);
  324. if(i>0) ulen -= i;
  325. for(;ulen > 0 && isspace((int)begin_u[ulen-1]); ulen--);
  326. if(begin_u == &(userin[ulen])) {
  327. sasl_FREE(in_buf);
  328. utils->seterror(utils->conn, 0, "All-whitespace username.");
  329. return SASL_FAIL;
  330. }
  331. if(utils->conn && utils->conn->type == SASL_CONN_SERVER)
  332. sconn = (sasl_server_conn_t *)utils->conn;
  333. /* Need to append realm if necessary (see sasl.h) */
  334. if(sconn && sconn->user_realm && !strchr(user, '@')) {
  335. u_apprealm = (unsigned) strlen(sconn->user_realm) + 1;
  336. }
  337. /* Now Copy */
  338. memcpy(out_user, begin_u, MIN(ulen, out_umax));
  339. if(sconn && u_apprealm) {
  340. if(ulen >= out_umax) return SASL_BUFOVER;
  341. out_user[ulen] = '@';
  342. memcpy(&(out_user[ulen+1]), sconn->user_realm,
  343. MIN(u_apprealm-1, out_umax-ulen-1));
  344. }
  345. out_user[MIN(ulen + u_apprealm,out_umax)] = '\0';
  346. if(ulen + u_apprealm > out_umax) return SASL_BUFOVER;
  347. if(out_ulen) *out_ulen = MIN(ulen + u_apprealm,out_umax);
  348. sasl_FREE(in_buf);
  349. return SASL_OK;
  350. }
  351. static int _cu_internal_server(void *glob_context __attribute__((unused)),
  352. sasl_server_params_t *sparams,
  353. const char *user, unsigned ulen,
  354. unsigned flags,
  355. char *out_user,
  356. unsigned out_umax, unsigned *out_ulen)
  357. {
  358. return _canonuser_internal(sparams->utils,
  359. user, ulen,
  360. flags, out_user, out_umax, out_ulen);
  361. }
  362. static int _cu_internal_client(void *glob_context __attribute__((unused)),
  363. sasl_client_params_t *cparams,
  364. const char *user, unsigned ulen,
  365. unsigned flags,
  366. char *out_user,
  367. unsigned out_umax, unsigned *out_ulen)
  368. {
  369. return _canonuser_internal(cparams->utils,
  370. user, ulen,
  371. flags, out_user, out_umax, out_ulen);
  372. }
  373. static sasl_canonuser_plug_t canonuser_internal_plugin = {
  374. 0, /* features */
  375. 0, /* spare */
  376. NULL, /* glob_context */
  377. "INTERNAL", /* name */
  378. NULL, /* canon_user_free */
  379. _cu_internal_server,
  380. _cu_internal_client,
  381. NULL,
  382. NULL,
  383. NULL
  384. };
  385. int internal_canonuser_init(const sasl_utils_t *utils __attribute__((unused)),
  386. int max_version,
  387. int *out_version,
  388. sasl_canonuser_plug_t **plug,
  389. const char *plugname __attribute__((unused)))
  390. {
  391. if(!out_version || !plug) return SASL_BADPARAM;
  392. if(max_version < SASL_CANONUSER_PLUG_VERSION) return SASL_BADVERS;
  393. *out_version = SASL_CANONUSER_PLUG_VERSION;
  394. *plug = &canonuser_internal_plugin;
  395. return SASL_OK;
  396. }