server.c 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406
  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. /* local functions/structs don't start with sasl
  46. */
  47. #include <config.h>
  48. #include <errno.h>
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <limits.h>
  52. #ifndef macintosh
  53. #include <sys/types.h>
  54. #include <sys/stat.h>
  55. #endif
  56. #include <fcntl.h>
  57. #include <string.h>
  58. #include <ctype.h>
  59. #include "sasl.h"
  60. #include "saslint.h"
  61. #include "saslplug.h"
  62. #include "saslutil.h"
  63. #define DEFAULT_CHECKPASS_MECH "auxprop"
  64. /* Contains functions:
  65. *
  66. * sasl_server_init
  67. * sasl_server_new
  68. * sasl_listmech
  69. * sasl_server_start
  70. * sasl_server_step
  71. * sasl_checkpass
  72. * sasl_checkapop
  73. * sasl_user_exists
  74. * sasl_setpass
  75. */
  76. /* if we've initialized the server sucessfully */
  77. static int _sasl_server_active = 0;
  78. /* For access by other modules */
  79. int _is_sasl_server_active(void) { return _sasl_server_active; }
  80. static int _sasl_checkpass(sasl_conn_t *conn,
  81. const char *user, unsigned userlen,
  82. const char *pass, unsigned passlen);
  83. static mech_list_t *mechlist = NULL; /* global var which holds the list */
  84. static sasl_global_callbacks_t global_callbacks;
  85. /* set the password for a user
  86. * conn -- SASL connection
  87. * user -- user name
  88. * pass -- plaintext password, may be NULL to remove user
  89. * passlen -- length of password, 0 = strlen(pass)
  90. * oldpass -- NULL will sometimes work
  91. * oldpasslen -- length of password, 0 = strlen(oldpass)
  92. * flags -- see flags below
  93. *
  94. * returns:
  95. * SASL_NOCHANGE -- proper entry already exists
  96. * SASL_NOMECH -- no authdb supports password setting as configured
  97. * SASL_NOVERIFY -- user exists, but no settable password present
  98. * SASL_DISABLED -- account disabled
  99. * SASL_PWLOCK -- password locked
  100. * SASL_WEAKPASS -- password too weak for security policy
  101. * SASL_NOUSERPASS -- user-supplied passwords not permitted
  102. * SASL_FAIL -- OS error
  103. * SASL_BADPARAM -- password too long
  104. * SASL_OK -- successful
  105. */
  106. int sasl_setpass(sasl_conn_t *conn,
  107. const char *user,
  108. const char *pass,
  109. unsigned passlen,
  110. const char *oldpass,
  111. unsigned oldpasslen,
  112. unsigned flags)
  113. {
  114. int result = SASL_OK, tmpresult;
  115. sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
  116. const char *password_request[] = { SASL_AUX_PASSWORD_PROP, NULL };
  117. const char *user_delete_request[] = { SASL_AUX_PASSWORD_PROP, SASL_AUX_ALL, NULL };
  118. sasl_server_userdb_setpass_t *setpass_cb = NULL;
  119. void *context = NULL;
  120. int tried_setpass = 0;
  121. int failed = 0;
  122. mechanism_t *sm;
  123. server_sasl_mechanism_t *m;
  124. char *current_mech;
  125. if (!_sasl_server_active || !mechlist) return SASL_NOTINIT;
  126. /* check params */
  127. if (!conn) return SASL_BADPARAM;
  128. if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
  129. if ((!(flags & SASL_SET_DISABLE) && passlen == 0)
  130. || ((flags & SASL_SET_CREATE) && (flags & SASL_SET_DISABLE)))
  131. PARAMERROR(conn);
  132. /* Check that we have an active SASL mechanism */
  133. if (sasl_getprop (conn,
  134. SASL_MECHNAME,
  135. (const void **) &current_mech) != SASL_OK) {
  136. current_mech = NULL;
  137. }
  138. if ( (flags & SASL_SET_CURMECH_ONLY) &&
  139. (current_mech == NULL) ) {
  140. sasl_seterror( conn, SASL_NOLOG,
  141. "No current SASL mechanism available");
  142. RETURN(conn, SASL_BADPARAM);
  143. }
  144. /* Do we want to store SASL_AUX_PASSWORD_PROP (plain text)? and
  145. * Do we have an auxprop backend that can store properties?
  146. */
  147. if ((flags & SASL_SET_DISABLE || !(flags & SASL_SET_NOPLAIN)) &&
  148. sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
  149. tried_setpass++;
  150. if (flags & SASL_SET_DISABLE) {
  151. pass = NULL;
  152. passlen = 0;
  153. result = prop_request(s_conn->sparams->propctx, user_delete_request);
  154. } else {
  155. result = prop_request(s_conn->sparams->propctx, password_request);
  156. }
  157. if (result == SASL_OK) {
  158. /* NOTE: When deleting users, this will work in a backward compatible way */
  159. result = prop_set(s_conn->sparams->propctx, SASL_AUX_PASSWORD_PROP,
  160. pass, passlen);
  161. }
  162. if (result == SASL_OK && flags & SASL_SET_DISABLE) {
  163. result = prop_set(s_conn->sparams->propctx, SASL_AUX_ALL,
  164. NULL, 0);
  165. }
  166. if (result == SASL_OK) {
  167. result = sasl_auxprop_store(conn, s_conn->sparams->propctx, user);
  168. }
  169. if (result != SASL_OK) {
  170. _sasl_log(conn, SASL_LOG_ERR,
  171. "setpass failed for %s: %z",
  172. user, result);
  173. failed++;
  174. } else {
  175. _sasl_log(conn, SASL_LOG_NOTE,
  176. "setpass succeeded for %s", user);
  177. }
  178. }
  179. /* We want to preserve the current value of result, so we use tmpresult below */
  180. /* call userdb callback function */
  181. tmpresult = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_SETPASS,
  182. (sasl_callback_ft *)&setpass_cb, &context);
  183. if (tmpresult == SASL_OK && setpass_cb) {
  184. tried_setpass++;
  185. tmpresult = setpass_cb(conn, context, user, pass, passlen,
  186. s_conn->sparams->propctx, flags);
  187. if(tmpresult != SASL_OK) {
  188. if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
  189. if (result == SASL_OK) {
  190. result = tmpresult;
  191. }
  192. } else {
  193. result = tmpresult;
  194. }
  195. _sasl_log(conn, SASL_LOG_ERR,
  196. "setpass callback failed for %s: %z",
  197. user, tmpresult);
  198. failed++;
  199. } else {
  200. _sasl_log(conn, SASL_LOG_NOTE,
  201. "setpass callback succeeded for %s", user);
  202. }
  203. }
  204. /* now we let the mechanisms set their secrets */
  205. for (sm = s_conn->mech_list; sm; sm = sm->next) {
  206. m = &sm->m;
  207. if (!m->plug->setpass) {
  208. /* can't set pass for this mech */
  209. continue;
  210. }
  211. /* Invoke only one setpass for the currently selected mechanism,
  212. if SASL_SET_CURMECH_ONLY is specified */
  213. if ((flags & SASL_SET_CURMECH_ONLY) &&
  214. (strcmp(current_mech, m->plug->mech_name) != 0)) {
  215. continue;
  216. }
  217. tried_setpass++;
  218. tmpresult = m->plug->setpass(m->plug->glob_context,
  219. ((sasl_server_conn_t *)conn)->sparams,
  220. user,
  221. pass,
  222. passlen,
  223. oldpass, oldpasslen,
  224. flags);
  225. if (tmpresult == SASL_OK) {
  226. _sasl_log(conn, SASL_LOG_NOTE,
  227. "%s: set secret for %s", m->plug->mech_name, user);
  228. m->condition = SASL_OK; /* if we previously thought the
  229. mechanism didn't have any user secrets
  230. we now think it does */
  231. } else if (tmpresult == SASL_NOCHANGE) {
  232. _sasl_log(conn, SASL_LOG_NOTE,
  233. "%s: secret not changed for %s", m->plug->mech_name, user);
  234. } else if (tmpresult == SASL_CONSTRAINT_VIOLAT) {
  235. _sasl_log(conn, SASL_LOG_ERR,
  236. "%s: failed to set secret for %s: constrain violation",
  237. m->plug->mech_name, user);
  238. if (result == SASL_OK) {
  239. result = tmpresult;
  240. }
  241. failed++;
  242. } else {
  243. result = tmpresult;
  244. _sasl_log(conn, SASL_LOG_ERR,
  245. "%s: failed to set secret for %s: %z (%m)",
  246. m->plug->mech_name, user, tmpresult,
  247. #ifndef WIN32
  248. errno
  249. #else
  250. GetLastError()
  251. #endif
  252. );
  253. failed++;
  254. }
  255. }
  256. if (!tried_setpass) {
  257. _sasl_log(conn, SASL_LOG_WARN,
  258. "secret not changed for %s: "
  259. "no writable auxprop plugin or setpass callback found",
  260. user);
  261. } else if (result == SASL_CONSTRAINT_VIOLAT) {
  262. /* If not all setpass failed with SASL_CONSTRAINT_VIOLAT -
  263. ignore SASL_CONSTRAINT_VIOLAT */
  264. if (failed < tried_setpass) {
  265. result = SASL_OK;
  266. }
  267. }
  268. RETURN(conn, result);
  269. }
  270. /* local mechanism which disposes of server */
  271. static void server_dispose(sasl_conn_t *pconn)
  272. {
  273. sasl_server_conn_t *s_conn= (sasl_server_conn_t *) pconn;
  274. context_list_t *cur, *cur_next;
  275. /* Just sanity check that sasl_server_done wasn't called yet */
  276. if (_sasl_server_active != 0) {
  277. if (s_conn->mech) {
  278. void (*mech_dispose)(void *conn_context, const sasl_utils_t *utils);
  279. mech_dispose = s_conn->mech->m.plug->mech_dispose;
  280. if (mech_dispose) {
  281. mech_dispose(pconn->context, s_conn->sparams->utils);
  282. }
  283. }
  284. pconn->context = NULL;
  285. for(cur = s_conn->mech_contexts; cur; cur=cur_next) {
  286. cur_next = cur->next;
  287. if (cur->context) {
  288. cur->mech->m.plug->mech_dispose(cur->context, s_conn->sparams->utils);
  289. }
  290. sasl_FREE(cur);
  291. }
  292. s_conn->mech_contexts = NULL;
  293. }
  294. _sasl_free_utils(&s_conn->sparams->utils);
  295. if (s_conn->sparams->propctx) {
  296. prop_dispose(&s_conn->sparams->propctx);
  297. }
  298. if (s_conn->appname) {
  299. sasl_FREE(s_conn->appname);
  300. }
  301. if (s_conn->user_realm) {
  302. sasl_FREE(s_conn->user_realm);
  303. }
  304. if (s_conn->sparams) {
  305. sasl_FREE(s_conn->sparams);
  306. }
  307. if (s_conn->mech_list != mechlist->mech_list) {
  308. /* free connection-specific mech_list */
  309. mechanism_t *m, *prevm;
  310. m = s_conn->mech_list; /* m point to beginning of the list */
  311. while (m) {
  312. prevm = m;
  313. m = m->next;
  314. sasl_FREE(prevm);
  315. }
  316. }
  317. _sasl_conn_dispose(pconn);
  318. }
  319. static int init_mechlist(void)
  320. {
  321. sasl_utils_t *newutils = NULL;
  322. /* set util functions - need to do rest */
  323. newutils = _sasl_alloc_utils(NULL, &global_callbacks);
  324. if (newutils == NULL)
  325. return SASL_NOMEM;
  326. newutils->checkpass = &_sasl_checkpass;
  327. mechlist->utils = newutils;
  328. mechlist->mech_list = NULL;
  329. mechlist->mech_length = 0;
  330. return SASL_OK;
  331. }
  332. static int mech_compare(const sasl_server_plug_t *a,
  333. const sasl_server_plug_t *b)
  334. {
  335. unsigned sec_diff;
  336. unsigned features_diff;
  337. /* XXX the following is fairly arbitrary, but its independent
  338. of the order in which the plugins are loaded
  339. */
  340. sec_diff = a->security_flags ^ b->security_flags;
  341. if (sec_diff & a->security_flags & SASL_SEC_NOANONYMOUS) return 1;
  342. if (sec_diff & b->security_flags & SASL_SEC_NOANONYMOUS) return -1;
  343. if (sec_diff & a->security_flags & SASL_SEC_NOPLAINTEXT) return 1;
  344. if (sec_diff & b->security_flags & SASL_SEC_NOPLAINTEXT) return -1;
  345. if (sec_diff & a->security_flags & SASL_SEC_MUTUAL_AUTH) return 1;
  346. if (sec_diff & b->security_flags & SASL_SEC_MUTUAL_AUTH) return -1;
  347. if (sec_diff & a->security_flags & SASL_SEC_NOACTIVE) return 1;
  348. if (sec_diff & b->security_flags & SASL_SEC_NOACTIVE) return -1;
  349. if (sec_diff & a->security_flags & SASL_SEC_NODICTIONARY) return 1;
  350. if (sec_diff & b->security_flags & SASL_SEC_NODICTIONARY) return -1;
  351. if (sec_diff & a->security_flags & SASL_SEC_FORWARD_SECRECY) return 1;
  352. if (sec_diff & b->security_flags & SASL_SEC_FORWARD_SECRECY) return -1;
  353. features_diff = a->features ^ b->features;
  354. if (features_diff & a->features & SASL_FEAT_CHANNEL_BINDING) return 1;
  355. if (features_diff & b->features & SASL_FEAT_CHANNEL_BINDING) return -1;
  356. if (a->max_ssf > b->max_ssf) return 1;
  357. if (a->max_ssf < b->max_ssf) return -1;
  358. if (SASL_GET_HASH_STRENGTH(a->security_flags) > SASL_GET_HASH_STRENGTH(b->security_flags)) return 1;
  359. if (SASL_GET_HASH_STRENGTH(a->security_flags) < SASL_GET_HASH_STRENGTH(b->security_flags)) return -1;
  360. return 0;
  361. }
  362. /*
  363. * parameters:
  364. * p - entry point
  365. */
  366. int sasl_server_add_plugin(const char *plugname,
  367. sasl_server_plug_init_t *p)
  368. {
  369. int plugcount;
  370. sasl_server_plug_t *pluglist = NULL;
  371. sasl_server_plug_init_t *entry_point = NULL;
  372. int result;
  373. int version;
  374. int lupe;
  375. if(!plugname || !p) return SASL_BADPARAM;
  376. entry_point = (sasl_server_plug_init_t *)p;
  377. /* call into the shared library asking for information about it */
  378. /* version is filled in with the version of the plugin */
  379. result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION, &version,
  380. &pluglist, &plugcount);
  381. if ((result != SASL_OK) && (result != SASL_NOUSER)
  382. && (result != SASL_CONTINUE)) {
  383. _sasl_log(NULL, SASL_LOG_DEBUG,
  384. "%s_client_plug_init() failed in sasl_server_add_plugin(): %z\n",
  385. plugname, result);
  386. return result;
  387. }
  388. /* Make sure plugin is using the same SASL version as us */
  389. if (version != SASL_SERVER_PLUG_VERSION)
  390. {
  391. _sasl_log(NULL,
  392. SASL_LOG_ERR,
  393. "version mismatch on sasl_server_add_plugin for '%s': %d expected, but %d reported",
  394. plugname,
  395. SASL_SERVER_PLUG_VERSION,
  396. version);
  397. return SASL_BADVERS;
  398. }
  399. for (lupe=0;lupe < plugcount ;lupe++, pluglist++)
  400. {
  401. mechanism_t *mech, *mp;
  402. mech = sasl_ALLOC(sizeof(mechanism_t));
  403. if (! mech) return SASL_NOMEM;
  404. memset (mech, 0, sizeof(mechanism_t));
  405. mech->m.plug = pluglist;
  406. if(_sasl_strdup(plugname, &mech->m.plugname, NULL) != SASL_OK) {
  407. sasl_FREE(mech);
  408. return SASL_NOMEM;
  409. }
  410. mech->m.version = version;
  411. /* whether this mech actually has any users in it's db */
  412. mech->m.condition = result; /* SASL_OK, SASL_CONTINUE or SASL_NOUSER */
  413. /* mech->m.f = NULL; */
  414. /* sort mech_list by relative "strength" */
  415. mp = mechlist->mech_list;
  416. if (!mp || mech_compare(pluglist, mp->m.plug) >= 0) {
  417. /* add mech to head of list */
  418. mech->next = mechlist->mech_list;
  419. mechlist->mech_list = mech;
  420. } else {
  421. /* find where to insert mech into list */
  422. while (mp->next &&
  423. mech_compare(pluglist, mp->next->m.plug) <= 0) mp = mp->next;
  424. mech->next = mp->next;
  425. mp->next = mech;
  426. }
  427. mechlist->mech_length++;
  428. }
  429. return SASL_OK;
  430. }
  431. int sasl_server_done(void)
  432. {
  433. int result = SASL_CONTINUE;
  434. if (_sasl_server_cleanup_hook == NULL && _sasl_client_cleanup_hook == NULL) {
  435. return SASL_NOTINIT;
  436. }
  437. if (_sasl_server_cleanup_hook) {
  438. result = _sasl_server_cleanup_hook();
  439. if (result == SASL_OK) {
  440. _sasl_server_idle_hook = NULL;
  441. _sasl_server_cleanup_hook = NULL;
  442. } else {
  443. return result;
  444. }
  445. }
  446. if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
  447. return result;
  448. }
  449. sasl_common_done();
  450. return SASL_OK;
  451. }
  452. static int server_done(void) {
  453. mechanism_t *m;
  454. mechanism_t *prevm;
  455. if(_sasl_server_active == 0)
  456. return SASL_NOTINIT;
  457. else
  458. _sasl_server_active--;
  459. if(_sasl_server_active) {
  460. /* Don't de-init yet! Our refcount is nonzero. */
  461. return SASL_CONTINUE;
  462. }
  463. if (mechlist != NULL)
  464. {
  465. m=mechlist->mech_list; /* m point to beginning of the list */
  466. while (m!=NULL)
  467. {
  468. prevm=m;
  469. m=m->next;
  470. if (prevm->m.plug->mech_free) {
  471. prevm->m.plug->mech_free(prevm->m.plug->glob_context,
  472. mechlist->utils);
  473. }
  474. sasl_FREE(prevm->m.plugname);
  475. sasl_FREE(prevm);
  476. }
  477. _sasl_free_utils(&mechlist->utils);
  478. sasl_FREE(mechlist);
  479. mechlist = NULL;
  480. }
  481. /* Free the auxprop plugins */
  482. _sasl_auxprop_free();
  483. global_callbacks.callbacks = NULL;
  484. global_callbacks.appname = NULL;
  485. sasl_config_done();
  486. return SASL_OK;
  487. }
  488. static int server_idle(sasl_conn_t *conn)
  489. {
  490. sasl_server_conn_t *s_conn = NULL;
  491. mechanism_t *m;
  492. if (! mechlist) {
  493. return 0;
  494. }
  495. if (!conn)
  496. return 1;
  497. s_conn = (sasl_server_conn_t *) conn;
  498. for (m = s_conn->mech_list;
  499. m != NULL;
  500. m = m->next) {
  501. if (m->m.plug->idle
  502. && m->m.plug->idle(m->m.plug->glob_context,
  503. conn,
  504. s_conn->sparams)) {
  505. return 1;
  506. }
  507. }
  508. return 0;
  509. }
  510. static int load_config(const sasl_callback_t *verifyfile_cb)
  511. {
  512. int result;
  513. const char *path_to_config = NULL;
  514. size_t path_len;
  515. char *config_filename = NULL;
  516. size_t len;
  517. const sasl_callback_t *getconfpath_cb = NULL;
  518. const char * next;
  519. /* If appname was not provided, behave as if there is no config file
  520. (see also sasl_config_init() */
  521. if (global_callbacks.appname == NULL) {
  522. return SASL_CONTINUE;
  523. }
  524. /* get the path to the config file */
  525. getconfpath_cb = _sasl_find_getconfpath_callback( global_callbacks.callbacks );
  526. if (getconfpath_cb == NULL) return SASL_BADPARAM;
  527. /* getconfpath_cb->proc MUST be a sasl_getconfpath_t; if only C had a type
  528. system */
  529. result = ((sasl_getconfpath_t *)(getconfpath_cb->proc))(getconfpath_cb->context,
  530. (char **) &path_to_config);
  531. if (result != SASL_OK) goto done;
  532. if (path_to_config == NULL) path_to_config = "";
  533. next = path_to_config;
  534. while (next != NULL) {
  535. next = strchr(path_to_config, PATHS_DELIMITER);
  536. /* length = length of path + '/' + length of appname + ".conf" + 1
  537. for '\0' */
  538. if (next != NULL) {
  539. path_len = next - path_to_config;
  540. next++; /* Skip to the next path */
  541. } else {
  542. path_len = strlen(path_to_config);
  543. }
  544. len = path_len + 2 + strlen(global_callbacks.appname) + 5 + 1;
  545. if (len > PATH_MAX ) {
  546. result = SASL_FAIL;
  547. goto done;
  548. }
  549. /* construct the filename for the config file */
  550. config_filename = sasl_ALLOC((unsigned)len);
  551. if (! config_filename) {
  552. result = SASL_NOMEM;
  553. goto done;
  554. }
  555. snprintf(config_filename, len, "%.*s%c%s.conf", (int)path_len, path_to_config,
  556. HIER_DELIMITER, global_callbacks.appname);
  557. /* Ask the application if it's safe to use this file */
  558. result = ((sasl_verifyfile_t *)(verifyfile_cb->proc))(verifyfile_cb->context,
  559. config_filename, SASL_VRFY_CONF);
  560. /* returns SASL_CONTINUE if the config file doesn't exist */
  561. if (result == SASL_OK) {
  562. result = sasl_config_init(config_filename);
  563. if (result != SASL_CONTINUE) {
  564. /* We are done */
  565. break;
  566. }
  567. }
  568. if (config_filename) {
  569. sasl_FREE(config_filename);
  570. config_filename = NULL;
  571. }
  572. path_to_config = next;
  573. }
  574. done:
  575. if (config_filename) sasl_FREE(config_filename);
  576. return result;
  577. }
  578. /*
  579. * Verify that all the callbacks are valid
  580. */
  581. static int verify_server_callbacks(const sasl_callback_t *callbacks)
  582. {
  583. if (callbacks == NULL) return SASL_OK;
  584. while (callbacks->id != SASL_CB_LIST_END) {
  585. if (callbacks->proc==NULL) return SASL_FAIL;
  586. callbacks++;
  587. }
  588. return SASL_OK;
  589. }
  590. static char *grab_field(char *line, char **eofield)
  591. {
  592. int d = 0;
  593. char *field;
  594. while (isspace((int) *line)) line++;
  595. /* find end of field */
  596. while (line[d] && !isspace(((int) line[d]))) d++;
  597. field = sasl_ALLOC(d + 1);
  598. if (!field) { return NULL; }
  599. memcpy(field, line, d);
  600. field[d] = '\0';
  601. *eofield = line + d;
  602. return field;
  603. }
  604. struct secflag_map_s {
  605. char *name;
  606. int value;
  607. };
  608. struct secflag_map_s secflag_map[] = {
  609. { "noplaintext", SASL_SEC_NOPLAINTEXT },
  610. { "noactive", SASL_SEC_NOACTIVE },
  611. { "nodictionary", SASL_SEC_NODICTIONARY },
  612. { "forward_secrecy", SASL_SEC_FORWARD_SECRECY },
  613. { "noanonymous", SASL_SEC_NOANONYMOUS },
  614. { "pass_credentials", SASL_SEC_PASS_CREDENTIALS },
  615. { "mutual_auth", SASL_SEC_MUTUAL_AUTH },
  616. { NULL, 0x0 }
  617. };
  618. static int parse_mechlist_file(const char *mechlistfile)
  619. {
  620. FILE *f;
  621. char buf[1024];
  622. char *t, *ptr;
  623. int r = 0;
  624. f = fopen(mechlistfile, "r");
  625. if (!f) return SASL_FAIL;
  626. r = SASL_OK;
  627. while (fgets(buf, sizeof(buf), f) != NULL) {
  628. mechanism_t *n = sasl_ALLOC(sizeof(mechanism_t));
  629. sasl_server_plug_t *nplug;
  630. if (n == NULL) { r = SASL_NOMEM; break; }
  631. n->m.version = SASL_SERVER_PLUG_VERSION;
  632. n->m.condition = SASL_CONTINUE;
  633. nplug = sasl_ALLOC(sizeof(sasl_server_plug_t));
  634. if (nplug == NULL) { r = SASL_NOMEM; break; }
  635. memset(nplug, 0, sizeof(sasl_server_plug_t));
  636. /* each line is:
  637. plugin-file WS mech_name WS max_ssf *(WS security_flag) RET
  638. */
  639. /* grab file */
  640. n->m.f = grab_field(buf, &ptr);
  641. /* grab mech_name */
  642. nplug->mech_name = grab_field(ptr, &ptr);
  643. /* grab max_ssf */
  644. nplug->max_ssf = strtol(ptr, &ptr, 10);
  645. /* grab security flags */
  646. while (*ptr != '\n') {
  647. struct secflag_map_s *map;
  648. /* read security flag */
  649. t = grab_field(ptr, &ptr);
  650. map = secflag_map;
  651. while (map->name) {
  652. if (!strcasecmp(t, map->name)) {
  653. nplug->security_flags |= map->value;
  654. break;
  655. }
  656. map++;
  657. }
  658. if (!map->name) {
  659. _sasl_log(NULL, SASL_LOG_ERR,
  660. "%s: couldn't identify flag '%s'",
  661. nplug->mech_name, t);
  662. }
  663. free(t);
  664. }
  665. /* insert mechanism into mechlist */
  666. n->m.plug = nplug;
  667. n->next = mechlist->mech_list;
  668. mechlist->mech_list = n;
  669. mechlist->mech_length++;
  670. }
  671. fclose(f);
  672. return r;
  673. }
  674. /* initialize server drivers, done once per process
  675. * callbacks -- callbacks for all server connections; must include
  676. * getopt callback
  677. * appname -- name of calling application
  678. * (for lower level logging and reading of the configuration file)
  679. * results:
  680. * state -- server state
  681. * returns:
  682. * SASL_OK -- success
  683. * SASL_BADPARAM -- error in config file
  684. * SASL_NOMEM -- memory failure
  685. * SASL_BADVERS -- Mechanism version mismatch
  686. */
  687. int sasl_server_init(const sasl_callback_t *callbacks,
  688. const char *appname)
  689. {
  690. int ret;
  691. const sasl_callback_t *vf;
  692. const char *pluginfile = NULL;
  693. #ifdef PIC
  694. sasl_getopt_t *getopt;
  695. void *context;
  696. #endif
  697. const add_plugin_list_t ep_list[] = {
  698. { "sasl_server_plug_init", (add_plugin_t *)sasl_server_add_plugin },
  699. { "sasl_auxprop_plug_init", (add_plugin_t *)sasl_auxprop_add_plugin },
  700. { "sasl_canonuser_init", (add_plugin_t *)sasl_canonuser_add_plugin },
  701. { NULL, NULL }
  702. };
  703. /* lock allocation type */
  704. _sasl_allocation_locked++;
  705. /* we require the appname (if present) to be short enough to be a path */
  706. if (appname != NULL && strlen(appname) >= PATH_MAX)
  707. return SASL_BADPARAM;
  708. if (_sasl_server_active) {
  709. /* We're already active, just increase our refcount */
  710. /* xxx do something with the callback structure? */
  711. _sasl_server_active++;
  712. return SASL_OK;
  713. }
  714. ret = _sasl_common_init(&global_callbacks);
  715. if (ret != SASL_OK)
  716. return ret;
  717. /* verify that the callbacks look ok */
  718. ret = verify_server_callbacks(callbacks);
  719. if (ret != SASL_OK)
  720. return ret;
  721. global_callbacks.callbacks = callbacks;
  722. /* A shared library calling sasl_server_init will pass NULL as appname.
  723. This should retain the original appname. */
  724. if (appname != NULL) {
  725. global_callbacks.appname = appname;
  726. }
  727. /* If we fail now, we have to call server_done */
  728. _sasl_server_active = 1;
  729. /* allocate mechlist and set it to empty */
  730. mechlist = sasl_ALLOC(sizeof(mech_list_t));
  731. if (mechlist == NULL) {
  732. server_done();
  733. return SASL_NOMEM;
  734. }
  735. ret = init_mechlist();
  736. if (ret != SASL_OK) {
  737. server_done();
  738. return ret;
  739. }
  740. vf = _sasl_find_verifyfile_callback(callbacks);
  741. /* load config file if applicable */
  742. ret = load_config(vf);
  743. if ((ret != SASL_OK) && (ret != SASL_CONTINUE)) {
  744. server_done();
  745. return ret;
  746. }
  747. /* load internal plugins */
  748. sasl_server_add_plugin("EXTERNAL", &external_server_plug_init);
  749. #ifdef PIC
  750. /* delayed loading of plugins? (DSO only, as it doesn't
  751. * make much [any] sense to delay in the static library case) */
  752. if (_sasl_getcallback(NULL, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
  753. == SASL_OK) {
  754. /* No sasl_conn_t was given to getcallback, so we provide the
  755. * global callbacks structure */
  756. ret = getopt(&global_callbacks, NULL, "plugin_list", &pluginfile, NULL);
  757. }
  758. #endif
  759. if (pluginfile != NULL) {
  760. /* this file should contain a list of plugins available.
  761. we'll load on demand. */
  762. /* Ask the application if it's safe to use this file */
  763. ret = ((sasl_verifyfile_t *)(vf->proc))(vf->context,
  764. pluginfile,
  765. SASL_VRFY_CONF);
  766. if (ret != SASL_OK) {
  767. _sasl_log(NULL, SASL_LOG_ERR,
  768. "unable to load plugin list %s: %z", pluginfile, ret);
  769. }
  770. if (ret == SASL_OK) {
  771. ret = parse_mechlist_file(pluginfile);
  772. }
  773. } else {
  774. /* load all plugins now */
  775. ret = _sasl_load_plugins(ep_list,
  776. _sasl_find_getpath_callback(callbacks),
  777. _sasl_find_verifyfile_callback(callbacks));
  778. }
  779. if (ret == SASL_OK) {
  780. _sasl_server_cleanup_hook = &server_done;
  781. _sasl_server_idle_hook = &server_idle;
  782. ret = _sasl_build_mechlist();
  783. } else {
  784. server_done();
  785. }
  786. return ret;
  787. }
  788. /*
  789. * Once we have the users plaintext password we
  790. * may want to transition them. That is put entries
  791. * for them in the passwd database for other
  792. * stronger mechanism
  793. *
  794. * for example PLAIN -> CRAM-MD5
  795. */
  796. static int
  797. _sasl_transition(sasl_conn_t * conn,
  798. const char * pass,
  799. unsigned passlen)
  800. {
  801. const char *dotrans = "n";
  802. sasl_getopt_t *getopt;
  803. int result = SASL_OK;
  804. void *context;
  805. unsigned flags = 0;
  806. if (! conn)
  807. return SASL_BADPARAM;
  808. if (! conn->oparams.authid)
  809. PARAMERROR(conn);
  810. /* check if this is enabled: default to false */
  811. if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK)
  812. {
  813. getopt(context, NULL, "auto_transition", &dotrans, NULL);
  814. if (dotrans == NULL) dotrans = "n";
  815. }
  816. if (!strcmp(dotrans, "noplain")) flags |= SASL_SET_NOPLAIN;
  817. if (flags || *dotrans == '1' || *dotrans == 'y' ||
  818. (*dotrans == 'o' && dotrans[1] == 'n') || *dotrans == 't') {
  819. /* ok, it's on! */
  820. _sasl_log(conn, SASL_LOG_NOTE,
  821. "transitioning user %s to auxprop database",
  822. conn->oparams.authid);
  823. result = sasl_setpass(conn,
  824. conn->oparams.authid,
  825. pass,
  826. passlen,
  827. NULL, 0, SASL_SET_CREATE | flags);
  828. }
  829. RETURN(conn,result);
  830. }
  831. /* create context for a single SASL connection
  832. * service -- registered name of the service using SASL (e.g. "imap")
  833. * serverFQDN -- Fully qualified domain name of server. NULL means use
  834. * gethostname() or equivalent.
  835. * Useful for multi-homed servers.
  836. * user_realm -- permits multiple user realms on server, NULL = default
  837. * iplocalport -- server IPv4/IPv6 domain literal string with port
  838. * (if NULL, then mechanisms requiring IPaddr are disabled)
  839. * ipremoteport -- client IPv4/IPv6 domain literal string with port
  840. * (if NULL, then mechanisms requiring IPaddr are disabled)
  841. * callbacks -- callbacks (e.g., authorization, lang, new getopt context)
  842. * flags -- usage flags (see above)
  843. * returns:
  844. * pconn -- new connection context
  845. *
  846. * returns:
  847. * SASL_OK -- success
  848. * SASL_NOMEM -- not enough memory
  849. */
  850. int sasl_server_new(const char *service,
  851. const char *serverFQDN,
  852. const char *user_realm,
  853. const char *iplocalport,
  854. const char *ipremoteport,
  855. const sasl_callback_t *callbacks,
  856. unsigned flags,
  857. sasl_conn_t **pconn)
  858. {
  859. int result;
  860. sasl_server_conn_t *serverconn;
  861. sasl_utils_t *utils;
  862. sasl_getopt_t *getopt;
  863. void *context;
  864. const char *log_level, *auto_trans;
  865. const char *mlist = NULL;
  866. int plus = 0;
  867. if (_sasl_server_active==0) return SASL_NOTINIT;
  868. if (! pconn) return SASL_FAIL;
  869. if (! service) return SASL_FAIL;
  870. *pconn=sasl_ALLOC(sizeof(sasl_server_conn_t));
  871. if (*pconn==NULL) return SASL_NOMEM;
  872. memset(*pconn, 0, sizeof(sasl_server_conn_t));
  873. serverconn = (sasl_server_conn_t *)*pconn;
  874. /* make sparams */
  875. serverconn->sparams=sasl_ALLOC(sizeof(sasl_server_params_t));
  876. if (serverconn->sparams==NULL)
  877. MEMERROR(*pconn);
  878. memset(serverconn->sparams, 0, sizeof(sasl_server_params_t));
  879. (*pconn)->destroy_conn = &server_dispose;
  880. result = _sasl_conn_init(*pconn, service, flags, SASL_CONN_SERVER,
  881. &server_idle, serverFQDN,
  882. iplocalport, ipremoteport,
  883. callbacks, &global_callbacks);
  884. if (result != SASL_OK)
  885. goto done_error;
  886. /* set util functions - need to do rest */
  887. utils=_sasl_alloc_utils(*pconn, &global_callbacks);
  888. if (!utils) {
  889. result = SASL_NOMEM;
  890. goto done_error;
  891. }
  892. utils->checkpass = &_sasl_checkpass;
  893. /* Setup the propctx -> We'll assume the default size */
  894. serverconn->sparams->propctx=prop_new(0);
  895. if(!serverconn->sparams->propctx) {
  896. result = SASL_NOMEM;
  897. goto done_error;
  898. }
  899. serverconn->sparams->service = (*pconn)->service;
  900. serverconn->sparams->servicelen = (unsigned) strlen((*pconn)->service);
  901. if (global_callbacks.appname && global_callbacks.appname[0] != '\0') {
  902. result = _sasl_strdup (global_callbacks.appname,
  903. &serverconn->appname,
  904. NULL);
  905. if (result != SASL_OK) {
  906. result = SASL_NOMEM;
  907. goto done_error;
  908. }
  909. serverconn->sparams->appname = serverconn->appname;
  910. serverconn->sparams->applen = (unsigned) strlen(serverconn->sparams->appname);
  911. } else {
  912. serverconn->appname = NULL;
  913. serverconn->sparams->appname = NULL;
  914. serverconn->sparams->applen = 0;
  915. }
  916. serverconn->sparams->serverFQDN = (*pconn)->serverFQDN;
  917. serverconn->sparams->slen = (unsigned) strlen((*pconn)->serverFQDN);
  918. if (user_realm) {
  919. result = _sasl_strdup(user_realm, &serverconn->user_realm, NULL);
  920. serverconn->sparams->urlen = (unsigned) strlen(user_realm);
  921. serverconn->sparams->user_realm = serverconn->user_realm;
  922. } else {
  923. serverconn->user_realm = NULL;
  924. /* the sparams is already zeroed */
  925. }
  926. serverconn->sparams->callbacks = callbacks;
  927. log_level = auto_trans = NULL;
  928. if(_sasl_getcallback(*pconn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context) == SASL_OK) {
  929. getopt(context, NULL, "log_level", &log_level, NULL);
  930. getopt(context, NULL, "auto_transition", &auto_trans, NULL);
  931. getopt(context, NULL, "mech_list", &mlist, NULL);
  932. }
  933. serverconn->sparams->log_level = log_level ? atoi(log_level) : SASL_LOG_ERR;
  934. serverconn->sparams->utils = utils;
  935. if (auto_trans &&
  936. (*auto_trans == '1' || *auto_trans == 'y' || *auto_trans == 't' ||
  937. (*auto_trans == 'o' && auto_trans[1] == 'n') ||
  938. !strcmp(auto_trans, "noplain")) &&
  939. sasl_auxprop_store(NULL, NULL, NULL) == SASL_OK) {
  940. serverconn->sparams->transition = &_sasl_transition;
  941. }
  942. /* if we have a mech_list, create ordered list of avail mechs for this conn */
  943. if (mlist) {
  944. const char *cp;
  945. mechanism_t *mptr, *tail = NULL;
  946. while (*mlist) {
  947. /* find end of current mech name */
  948. for (cp = mlist; *cp && !isspace((int) *cp); cp++);
  949. /* search for mech name in loaded plugins */
  950. for (mptr = mechlist->mech_list; mptr; mptr = mptr->next) {
  951. const sasl_server_plug_t *plug = mptr->m.plug;
  952. if (_sasl_is_equal_mech(mlist, plug->mech_name, (size_t) (cp - mlist), &plus)) {
  953. /* found a match */
  954. break;
  955. }
  956. }
  957. if (mptr) {
  958. mechanism_t *new = sasl_ALLOC(sizeof(mechanism_t));
  959. if (!new) return SASL_NOMEM;
  960. memcpy(&new->m, &mptr->m, sizeof(server_sasl_mechanism_t));
  961. new->next = NULL;
  962. if (!serverconn->mech_list) {
  963. serverconn->mech_list = new;
  964. tail = serverconn->mech_list;
  965. }
  966. else {
  967. if (tail)
  968. tail->next = new;
  969. tail = new;
  970. }
  971. serverconn->mech_length++;
  972. }
  973. /* find next mech name */
  974. mlist = cp;
  975. while (*mlist && isspace((int) *mlist)) mlist++;
  976. }
  977. }
  978. else {
  979. serverconn->mech_list = mechlist->mech_list;
  980. serverconn->mech_length = mechlist->mech_length;
  981. }
  982. serverconn->sparams->canon_user = &_sasl_canon_user_lookup;
  983. serverconn->sparams->props = serverconn->base.props;
  984. serverconn->sparams->flags = flags;
  985. if(result == SASL_OK) return SASL_OK;
  986. done_error:
  987. _sasl_conn_dispose(*pconn);
  988. sasl_FREE(*pconn);
  989. *pconn = NULL;
  990. return result;
  991. }
  992. /*
  993. * The rule is:
  994. * IF mech strength + external strength < min ssf THEN FAIL.
  995. * We also have to look at the security properties and make sure
  996. * that this mechanism has everything we want.
  997. */
  998. static int mech_permitted(sasl_conn_t *conn,
  999. mechanism_t *mech)
  1000. {
  1001. sasl_server_conn_t *s_conn = (sasl_server_conn_t *)conn;
  1002. const sasl_server_plug_t *plug;
  1003. int ret;
  1004. int myflags;
  1005. context_list_t *cur;
  1006. context_list_t *mech_context_list_entry = NULL;
  1007. void *context = NULL;
  1008. sasl_ssf_t minssf = 0;
  1009. if(!conn) return SASL_NOMECH;
  1010. if(! mech || ! mech->m.plug) {
  1011. PARAMERROR(conn);
  1012. return SASL_NOMECH;
  1013. }
  1014. plug = mech->m.plug;
  1015. /* setup parameters for the call to mech_avail */
  1016. s_conn->sparams->serverFQDN=conn->serverFQDN;
  1017. s_conn->sparams->service=conn->service;
  1018. s_conn->sparams->user_realm=s_conn->user_realm;
  1019. s_conn->sparams->props=conn->props;
  1020. s_conn->sparams->external_ssf=conn->external.ssf;
  1021. /* Check if we have banished this one already */
  1022. for (cur = s_conn->mech_contexts; cur; cur=cur->next) {
  1023. if (cur->mech == mech) {
  1024. /* If it's not mech_avail'd, then stop now */
  1025. if (!cur->context) {
  1026. return SASL_NOMECH;
  1027. } else {
  1028. context = cur->context;
  1029. mech_context_list_entry = cur;
  1030. }
  1031. break;
  1032. }
  1033. }
  1034. if (conn->props.min_ssf < conn->external.ssf) {
  1035. minssf = 0;
  1036. } else {
  1037. minssf = conn->props.min_ssf - conn->external.ssf;
  1038. }
  1039. /* Generic mechanism */
  1040. if (plug->max_ssf < minssf) {
  1041. sasl_seterror(conn, SASL_NOLOG,
  1042. "mech %s is too weak", plug->mech_name);
  1043. return SASL_TOOWEAK; /* too weak */
  1044. }
  1045. if (plug->mech_avail
  1046. && (ret = plug->mech_avail(plug->glob_context,
  1047. s_conn->sparams,
  1048. (void **)&context)) != SASL_OK ) {
  1049. if (ret == SASL_NOMECH) {
  1050. /* Mark this mech as no good for this connection */
  1051. cur = sasl_ALLOC(sizeof(context_list_t));
  1052. if (!cur) {
  1053. MEMERROR(conn);
  1054. return SASL_NOMECH;
  1055. }
  1056. cur->context = NULL;
  1057. cur->mech = mech;
  1058. cur->next = s_conn->mech_contexts;
  1059. s_conn->mech_contexts = cur;
  1060. }
  1061. /* SASL_NOTDONE might also get us here */
  1062. /* Error should be set by mech_avail call */
  1063. return SASL_NOMECH;
  1064. } else if (context) {
  1065. if (mech_context_list_entry != NULL) {
  1066. /* Update the context. It shouldn't have changed, but who knows */
  1067. mech_context_list_entry->context = context;
  1068. } else {
  1069. /* Save this context */
  1070. cur = sasl_ALLOC(sizeof(context_list_t));
  1071. if (!cur) {
  1072. MEMERROR(conn);
  1073. return SASL_NOMECH;
  1074. }
  1075. cur->context = context;
  1076. cur->mech = mech;
  1077. cur->next = s_conn->mech_contexts;
  1078. s_conn->mech_contexts = cur;
  1079. }
  1080. }
  1081. /* Generic mechanism */
  1082. if (plug->max_ssf < minssf) {
  1083. sasl_seterror(conn, SASL_NOLOG, "too weak");
  1084. return SASL_TOOWEAK; /* too weak */
  1085. }
  1086. /* if there are no users in the secrets database we can't use this
  1087. mechanism */
  1088. if (mech->m.condition == SASL_NOUSER) {
  1089. sasl_seterror(conn, 0, "no users in secrets db");
  1090. return SASL_NOMECH;
  1091. }
  1092. /* Can it meet our features? */
  1093. if ((conn->flags & SASL_NEED_PROXY) &&
  1094. !(plug->features & SASL_FEAT_ALLOWS_PROXY)) {
  1095. return SASL_NOMECH;
  1096. }
  1097. if ((conn->flags & SASL_NEED_HTTP) &&
  1098. !(plug->features & SASL_FEAT_SUPPORTS_HTTP)) {
  1099. return SASL_NOMECH;
  1100. }
  1101. /* security properties---if there are any flags that differ and are
  1102. in what the connection are requesting, then fail */
  1103. /* special case plaintext */
  1104. myflags = conn->props.security_flags;
  1105. /* if there's an external layer this is no longer plaintext */
  1106. if ((conn->props.min_ssf <= conn->external.ssf) &&
  1107. (conn->external.ssf > 1)) {
  1108. myflags &= ~SASL_SEC_NOPLAINTEXT;
  1109. }
  1110. /* do we want to special case SASL_SEC_PASS_CREDENTIALS? nah.. */
  1111. if ((myflags &= (myflags ^ plug->security_flags)) != 0) {
  1112. sasl_seterror(conn, SASL_NOLOG,
  1113. "security flags do not match required");
  1114. return (myflags & SASL_SEC_NOPLAINTEXT) ? SASL_ENCRYPT : SASL_NOMECH;
  1115. }
  1116. /* Check Features */
  1117. if (plug->features & SASL_FEAT_GETSECRET) {
  1118. /* We no longer support sasl_server_{get,put}secret */
  1119. sasl_seterror(conn, 0,
  1120. "mech %s requires unprovided secret facility",
  1121. plug->mech_name);
  1122. return SASL_NOMECH;
  1123. }
  1124. return SASL_OK;
  1125. }
  1126. /*
  1127. * make the authorization
  1128. *
  1129. */
  1130. static int do_authorization(sasl_server_conn_t *s_conn)
  1131. {
  1132. int ret;
  1133. sasl_authorize_t *authproc;
  1134. void *auth_context;
  1135. /* now let's see if authname is allowed to proxy for username! */
  1136. /* check the proxy callback */
  1137. if (_sasl_getcallback(&s_conn->base, SASL_CB_PROXY_POLICY,
  1138. (sasl_callback_ft *)&authproc, &auth_context) != SASL_OK) {
  1139. INTERROR(&s_conn->base, SASL_NOAUTHZ);
  1140. }
  1141. ret = authproc(&(s_conn->base), auth_context,
  1142. s_conn->base.oparams.user, s_conn->base.oparams.ulen,
  1143. s_conn->base.oparams.authid, s_conn->base.oparams.alen,
  1144. s_conn->user_realm,
  1145. (s_conn->user_realm ? (unsigned) strlen(s_conn->user_realm) : 0),
  1146. s_conn->sparams->propctx);
  1147. RETURN(&s_conn->base, ret);
  1148. }
  1149. /* start a mechanism exchange within a connection context
  1150. * mech -- the mechanism name client requested
  1151. * clientin -- client initial response (NUL terminated), NULL if empty
  1152. * clientinlen -- length of initial response
  1153. * serverout -- initial server challenge, NULL if done
  1154. * (library handles freeing this string)
  1155. * serveroutlen -- length of initial server challenge
  1156. * output:
  1157. * pconn -- the connection negotiation state on success
  1158. *
  1159. * Same returns as sasl_server_step() or
  1160. * SASL_NOMECH if mechanism not available.
  1161. */
  1162. int sasl_server_start(sasl_conn_t *conn,
  1163. const char *mech,
  1164. const char *clientin,
  1165. unsigned clientinlen,
  1166. const char **serverout,
  1167. unsigned *serveroutlen)
  1168. {
  1169. sasl_server_conn_t *s_conn=(sasl_server_conn_t *) conn;
  1170. int result;
  1171. context_list_t *cur, **prev;
  1172. mechanism_t *m;
  1173. size_t mech_len;
  1174. int plus = 0;
  1175. if (_sasl_server_active==0) return SASL_NOTINIT;
  1176. /* check parameters */
  1177. if(!conn) return SASL_BADPARAM;
  1178. if (!mech || ((clientin == NULL) && (clientinlen > 0)))
  1179. PARAMERROR(conn);
  1180. if (serverout) *serverout = NULL;
  1181. if (serveroutlen) *serveroutlen = 0;
  1182. /* make sure mech is valid mechanism
  1183. if not return appropriate error */
  1184. m = s_conn->mech_list;
  1185. mech_len = strlen(mech);
  1186. while (m != NULL) {
  1187. if (_sasl_is_equal_mech(mech, m->m.plug->mech_name, mech_len, &plus)) {
  1188. break;
  1189. }
  1190. m = m->next;
  1191. }
  1192. if (m == NULL) {
  1193. sasl_seterror(conn, 0, "Couldn't find mech %s", mech);
  1194. result = SASL_NOMECH;
  1195. goto done;
  1196. }
  1197. /* Make sure that we're willing to use this mech */
  1198. if ((result = mech_permitted(conn, m)) != SASL_OK) {
  1199. goto done;
  1200. }
  1201. if (m->m.condition == SASL_CONTINUE) {
  1202. sasl_server_plug_init_t *entry_point = NULL;
  1203. void *library = NULL;
  1204. sasl_server_plug_t *pluglist = NULL;
  1205. int version, plugcount;
  1206. int l = 0;
  1207. /* need to load this plugin */
  1208. result = _sasl_get_plugin(m->m.f,
  1209. _sasl_find_verifyfile_callback(global_callbacks.callbacks),
  1210. &library);
  1211. if (result == SASL_OK) {
  1212. result = _sasl_locate_entry(library, "sasl_server_plug_init",
  1213. (void **)&entry_point);
  1214. }
  1215. if (result == SASL_OK) {
  1216. result = entry_point(mechlist->utils, SASL_SERVER_PLUG_VERSION,
  1217. &version, &pluglist, &plugcount);
  1218. }
  1219. if (result == SASL_OK) {
  1220. /* find the correct mechanism in this plugin */
  1221. for (l = 0; l < plugcount; l++) {
  1222. if (!strcasecmp(pluglist[l].mech_name,
  1223. m->m.plug->mech_name)) break;
  1224. }
  1225. if (l == plugcount) {
  1226. result = SASL_NOMECH;
  1227. }
  1228. }
  1229. if (result == SASL_OK) {
  1230. /* check that the parameters are the same */
  1231. if ((pluglist[l].max_ssf != m->m.plug->max_ssf) ||
  1232. (pluglist[l].security_flags != m->m.plug->security_flags)) {
  1233. _sasl_log(conn, SASL_LOG_ERR,
  1234. "%s: security parameters don't match mechlist file",
  1235. pluglist[l].mech_name);
  1236. result = SASL_NOMECH;
  1237. }
  1238. }
  1239. if (result == SASL_OK) {
  1240. /* copy mechlist over */
  1241. sasl_FREE((sasl_server_plug_t *) m->m.plug);
  1242. m->m.plug = &pluglist[l];
  1243. m->m.condition = SASL_OK;
  1244. }
  1245. if (result != SASL_OK) {
  1246. /* The library will eventually be freed, don't sweat it */
  1247. RETURN(conn, result);
  1248. }
  1249. }
  1250. if (conn->context) {
  1251. s_conn->mech->m.plug->mech_dispose(conn->context,
  1252. s_conn->sparams->utils);
  1253. conn->context = NULL;
  1254. }
  1255. /* We used to setup sparams HERE, but now it's done
  1256. inside of mech_permitted (which is called above) */
  1257. prev = &s_conn->mech_contexts;
  1258. for (cur = *prev; cur; prev=&cur->next,cur=cur->next) {
  1259. if (cur->mech == m) {
  1260. if (!cur->context) {
  1261. sasl_seterror(conn, 0,
  1262. "Got past mech_permitted with a disallowed mech!");
  1263. return SASL_NOMECH;
  1264. }
  1265. /* If we find it, we need to pull cur out of the
  1266. list so it won't be freed later! */
  1267. *prev = cur->next;
  1268. conn->context = cur->context;
  1269. sasl_FREE(cur);
  1270. break;
  1271. }
  1272. }
  1273. s_conn->mech = m;
  1274. if (!conn->context) {
  1275. /* Note that we don't hand over a new challenge */
  1276. result = s_conn->mech->m.plug->mech_new(s_conn->mech->m.plug->glob_context,
  1277. s_conn->sparams,
  1278. NULL,
  1279. 0,
  1280. &(conn->context));
  1281. } else {
  1282. /* the work was already done by mech_avail! */
  1283. result = SASL_OK;
  1284. }
  1285. if (result == SASL_OK) {
  1286. if (clientin) {
  1287. if (s_conn->mech->m.plug->features & SASL_FEAT_SERVER_FIRST) {
  1288. /* Remote sent first, but mechanism does not support it.
  1289. * RFC 2222 says we fail at this point. */
  1290. sasl_seterror(conn,
  1291. 0,
  1292. "Remote sent first but mech does not allow it.");
  1293. result = SASL_BADPROT;
  1294. } else {
  1295. /* Mech wants client-first, so let them have it */
  1296. result = sasl_server_step(conn,
  1297. clientin,
  1298. clientinlen,
  1299. serverout,
  1300. serveroutlen);
  1301. }
  1302. } else {
  1303. if (s_conn->mech->m.plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
  1304. /* Mech wants client first anyway, so we should do that */
  1305. if (serverout) *serverout = "";
  1306. if (serveroutlen) *serveroutlen = 0;
  1307. result = SASL_CONTINUE;
  1308. } else {
  1309. /* Mech wants server-first, so let them have it */
  1310. result = sasl_server_step(conn,
  1311. clientin,
  1312. clientinlen,
  1313. serverout,
  1314. serveroutlen);
  1315. }
  1316. }
  1317. }
  1318. done:
  1319. if ( result != SASL_OK
  1320. && result != SASL_CONTINUE
  1321. && result != SASL_INTERACT) {
  1322. if (conn->context) {
  1323. s_conn->mech->m.plug->mech_dispose(conn->context,
  1324. s_conn->sparams->utils);
  1325. conn->context = NULL;
  1326. }
  1327. conn->oparams.doneflag = 0;
  1328. }
  1329. RETURN(conn,result);
  1330. }
  1331. /* perform one step of the SASL exchange
  1332. * clientinlen & clientin -- client data
  1333. * NULL on first step if no optional client step
  1334. * serveroutlen & serverout -- set to the server data to transmit
  1335. * to the client in the next step
  1336. * (library handles freeing this)
  1337. *
  1338. * returns:
  1339. * SASL_OK -- exchange is complete.
  1340. * SASL_CONTINUE -- indicates another step is necessary.
  1341. * SASL_TRANS -- entry for user exists, but not for mechanism
  1342. * and transition is possible
  1343. * SASL_BADPARAM -- service name needed
  1344. * SASL_BADPROT -- invalid input from client
  1345. * ...
  1346. */
  1347. int sasl_server_step(sasl_conn_t *conn,
  1348. const char *clientin,
  1349. unsigned clientinlen,
  1350. const char **serverout,
  1351. unsigned *serveroutlen)
  1352. {
  1353. int ret;
  1354. sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
  1355. /* check parameters */
  1356. if (_sasl_server_active==0) return SASL_NOTINIT;
  1357. if (!conn) return SASL_BADPARAM;
  1358. if ((clientin==NULL) && (clientinlen>0))
  1359. PARAMERROR(conn);
  1360. /* If we've already done the last send, return! */
  1361. if (s_conn->sent_last == 1) {
  1362. return SASL_OK;
  1363. }
  1364. /* Don't do another step if the plugin told us that we're done */
  1365. if (conn->oparams.doneflag) {
  1366. _sasl_log(conn, SASL_LOG_ERR, "attempting server step after doneflag");
  1367. return SASL_FAIL;
  1368. }
  1369. if (serverout) *serverout = NULL;
  1370. if (serveroutlen) *serveroutlen = 0;
  1371. ret = s_conn->mech->m.plug->mech_step(conn->context,
  1372. s_conn->sparams,
  1373. clientin,
  1374. clientinlen,
  1375. serverout,
  1376. serveroutlen,
  1377. &conn->oparams);
  1378. if (ret == SASL_OK) {
  1379. ret = do_authorization(s_conn);
  1380. }
  1381. if (ret == SASL_OK) {
  1382. /* if we're done, we need to watch out for the following:
  1383. * 1. the mech does server-send-last
  1384. * 2. the protocol does not
  1385. *
  1386. * in this case, return SASL_CONTINUE and remember we are done.
  1387. */
  1388. if(*serverout && !(conn->flags & SASL_SUCCESS_DATA)) {
  1389. s_conn->sent_last = 1;
  1390. ret = SASL_CONTINUE;
  1391. }
  1392. if(!conn->oparams.maxoutbuf) {
  1393. conn->oparams.maxoutbuf = conn->props.maxbufsize;
  1394. }
  1395. /* Validate channel bindings */
  1396. switch (conn->oparams.cbindingdisp) {
  1397. case SASL_CB_DISP_NONE:
  1398. if (SASL_CB_CRITICAL(s_conn->sparams)) {
  1399. sasl_seterror(conn, 0,
  1400. "server requires channel binding but client provided none");
  1401. ret = SASL_BADBINDING;
  1402. }
  1403. break;
  1404. case SASL_CB_DISP_WANT:
  1405. if (SASL_CB_PRESENT(s_conn->sparams)) {
  1406. sasl_seterror(conn, 0,
  1407. "client incorrectly assumed server had no channel binding");
  1408. ret = SASL_BADAUTH;
  1409. }
  1410. break;
  1411. case SASL_CB_DISP_USED:
  1412. if (!SASL_CB_PRESENT(s_conn->sparams)) {
  1413. sasl_seterror(conn, 0,
  1414. "client provided channel binding but server had none");
  1415. ret = SASL_BADBINDING;
  1416. } else if (strcmp(conn->oparams.cbindingname,
  1417. s_conn->sparams->cbinding->name) != 0) {
  1418. sasl_seterror(conn, 0,
  1419. "client channel binding %s does not match server %s",
  1420. conn->oparams.cbindingname, s_conn->sparams->cbinding->name);
  1421. ret = SASL_BADBINDING;
  1422. }
  1423. break;
  1424. }
  1425. if (ret == SASL_OK &&
  1426. (conn->oparams.user == NULL || conn->oparams.authid == NULL)) {
  1427. sasl_seterror(conn, 0,
  1428. "mech did not call canon_user for both authzid " \
  1429. "and authid");
  1430. ret = SASL_BADPROT;
  1431. }
  1432. }
  1433. if ( ret != SASL_OK
  1434. && ret != SASL_CONTINUE
  1435. && ret != SASL_INTERACT) {
  1436. if (conn->context) {
  1437. s_conn->mech->m.plug->mech_dispose(conn->context,
  1438. s_conn->sparams->utils);
  1439. conn->context = NULL;
  1440. }
  1441. conn->oparams.doneflag = 0;
  1442. }
  1443. RETURN(conn, ret);
  1444. }
  1445. /* returns the length of all the mechanisms
  1446. * added up
  1447. */
  1448. static unsigned mech_names_len(mechanism_t *mech_list)
  1449. {
  1450. mechanism_t *listptr;
  1451. unsigned result = 0;
  1452. for (listptr = mech_list;
  1453. listptr;
  1454. listptr = listptr->next)
  1455. result += (unsigned) strlen(listptr->m.plug->mech_name);
  1456. return result;
  1457. }
  1458. /* This returns a list of mechanisms in a NUL-terminated string
  1459. *
  1460. * The default behavior is to separate with spaces if sep == NULL
  1461. */
  1462. int _sasl_server_listmech(sasl_conn_t *conn,
  1463. const char *user __attribute__((unused)),
  1464. const char *prefix,
  1465. const char *sep,
  1466. const char *suffix,
  1467. const char **result,
  1468. unsigned *plen,
  1469. int *pcount)
  1470. {
  1471. sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn; /* cast */
  1472. int lup;
  1473. mechanism_t *listptr;
  1474. int ret;
  1475. size_t resultlen;
  1476. int flag;
  1477. const char *mysep;
  1478. /* if there hasn't been a sasl_sever_init() fail */
  1479. if (_sasl_server_active==0) return SASL_NOTINIT;
  1480. if (!conn) return SASL_BADPARAM;
  1481. if (conn->type != SASL_CONN_SERVER) PARAMERROR(conn);
  1482. if (! result)
  1483. PARAMERROR(conn);
  1484. if (plen != NULL)
  1485. *plen = 0;
  1486. if (pcount != NULL)
  1487. *pcount = 0;
  1488. if (sep) {
  1489. mysep = sep;
  1490. } else {
  1491. mysep = " ";
  1492. }
  1493. if (!s_conn->mech_list || s_conn->mech_length <= 0)
  1494. INTERROR(conn, SASL_NOMECH);
  1495. resultlen = (prefix ? strlen(prefix) : 0)
  1496. + (strlen(mysep) * (s_conn->mech_length - 1) * 2)
  1497. + (mech_names_len(s_conn->mech_list) * 2) /* including -PLUS variant */
  1498. + (s_conn->mech_length * (sizeof("-PLUS") - 1))
  1499. + (suffix ? strlen(suffix) : 0)
  1500. + 1;
  1501. ret = _buf_alloc(&conn->mechlist_buf,
  1502. &conn->mechlist_buf_len, resultlen);
  1503. if(ret != SASL_OK) MEMERROR(conn);
  1504. if (prefix)
  1505. strcpy (conn->mechlist_buf,prefix);
  1506. else
  1507. *(conn->mechlist_buf) = '\0';
  1508. listptr = s_conn->mech_list;
  1509. flag = 0;
  1510. /* make list */
  1511. for (lup = 0; lup < s_conn->mech_length; lup++) {
  1512. /* currently, we don't use the "user" parameter for anything */
  1513. if (mech_permitted(conn, listptr) == SASL_OK) {
  1514. /*
  1515. * If the server would never succeed in the authentication of
  1516. * the non-PLUS-variant due to policy reasons, it MUST advertise
  1517. * only the PLUS-variant.
  1518. */
  1519. if ((listptr->m.plug->features & SASL_FEAT_CHANNEL_BINDING) &&
  1520. SASL_CB_PRESENT(s_conn->sparams)) {
  1521. if (pcount != NULL) {
  1522. (*pcount)++;
  1523. }
  1524. if (flag) {
  1525. strcat(conn->mechlist_buf, mysep);
  1526. } else {
  1527. flag = 1;
  1528. }
  1529. strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
  1530. strcat(conn->mechlist_buf, "-PLUS");
  1531. }
  1532. /*
  1533. * If the server cannot support channel binding, it SHOULD
  1534. * advertise only the non-PLUS-variant. Here, supporting channel
  1535. * binding means the underlying SASL mechanism supports it and
  1536. * the application has set some channel binding data.
  1537. */
  1538. if (!SASL_CB_PRESENT(s_conn->sparams) ||
  1539. !SASL_CB_CRITICAL(s_conn->sparams)) {
  1540. if (pcount != NULL) {
  1541. (*pcount)++;
  1542. }
  1543. if (flag) {
  1544. strcat(conn->mechlist_buf, mysep);
  1545. } else {
  1546. flag = 1;
  1547. }
  1548. strcat(conn->mechlist_buf, listptr->m.plug->mech_name);
  1549. }
  1550. }
  1551. listptr = listptr->next;
  1552. }
  1553. if (suffix)
  1554. strcat(conn->mechlist_buf,suffix);
  1555. if (plen!=NULL)
  1556. *plen = (unsigned) strlen(conn->mechlist_buf);
  1557. *result = conn->mechlist_buf;
  1558. return SASL_OK;
  1559. }
  1560. sasl_string_list_t *_sasl_server_mechs(void)
  1561. {
  1562. mechanism_t *listptr;
  1563. sasl_string_list_t *retval = NULL, *next=NULL;
  1564. if(!_sasl_server_active) return NULL;
  1565. /* make list */
  1566. for (listptr = mechlist->mech_list; listptr; listptr = listptr->next) {
  1567. next = sasl_ALLOC(sizeof(sasl_string_list_t));
  1568. if(!next && !retval) return NULL;
  1569. else if(!next) {
  1570. next = retval->next;
  1571. do {
  1572. sasl_FREE(retval);
  1573. retval = next;
  1574. next = retval->next;
  1575. } while(next);
  1576. return NULL;
  1577. }
  1578. next->d = listptr->m.plug->mech_name;
  1579. if(!retval) {
  1580. next->next = NULL;
  1581. retval = next;
  1582. } else {
  1583. next->next = retval;
  1584. retval = next;
  1585. }
  1586. }
  1587. return retval;
  1588. }
  1589. #define EOSTR(s,n) (((s)[n] == '\0') || ((s)[n] == ' ') || ((s)[n] == '\t'))
  1590. static int is_mech(const char *t, const char *m)
  1591. {
  1592. size_t sl = strlen(m);
  1593. return ((!strncasecmp(m, t, sl)) && EOSTR(t, sl));
  1594. }
  1595. /* returns OK if it's valid */
  1596. static int _sasl_checkpass(sasl_conn_t *conn,
  1597. const char *user,
  1598. unsigned userlen,
  1599. const char *pass,
  1600. unsigned passlen)
  1601. {
  1602. sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
  1603. int result;
  1604. sasl_getopt_t *getopt;
  1605. sasl_server_userdb_checkpass_t *checkpass_cb;
  1606. void *context;
  1607. const char *mlist = NULL, *mech = NULL;
  1608. struct sasl_verify_password_s *v;
  1609. const char *service = conn->service;
  1610. if (!userlen) userlen = (unsigned) strlen(user);
  1611. if (!passlen) passlen = (unsigned) strlen(pass);
  1612. /* call userdb callback function, if available */
  1613. result = _sasl_getcallback(conn, SASL_CB_SERVER_USERDB_CHECKPASS,
  1614. (sasl_callback_ft *)&checkpass_cb, &context);
  1615. if(result == SASL_OK && checkpass_cb) {
  1616. result = checkpass_cb(conn, context, user, pass, passlen,
  1617. s_conn->sparams->propctx);
  1618. if(result == SASL_OK)
  1619. return SASL_OK;
  1620. }
  1621. /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
  1622. if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
  1623. == SASL_OK) {
  1624. getopt(context, NULL, "pwcheck_method", &mlist, NULL);
  1625. }
  1626. if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
  1627. result = SASL_NOMECH;
  1628. mech = mlist;
  1629. while (*mech && result != SASL_OK) {
  1630. for (v = _sasl_verify_password; v->name; v++) {
  1631. if(is_mech(mech, v->name)) {
  1632. result = v->verify(conn, user, pass, service,
  1633. s_conn->user_realm);
  1634. break;
  1635. }
  1636. }
  1637. if (result != SASL_OK) {
  1638. /* skip to next mech in list */
  1639. while (*mech && !isspace((int) *mech)) mech++;
  1640. while (*mech && isspace((int) *mech)) mech++;
  1641. }
  1642. else if (!is_mech(mech, "auxprop") && s_conn->sparams->transition) {
  1643. s_conn->sparams->transition(conn, pass, passlen);
  1644. }
  1645. }
  1646. if (result == SASL_NOMECH) {
  1647. /* no mechanism available ?!? */
  1648. _sasl_log(conn, SASL_LOG_ERR, "unknown password verifier(s) %s", mlist);
  1649. }
  1650. if (result != SASL_OK)
  1651. sasl_seterror(conn, SASL_NOLOG, "checkpass failed");
  1652. RETURN(conn, result);
  1653. }
  1654. /* check if a plaintext password is valid
  1655. * if user is NULL, check if plaintext passwords are enabled
  1656. * inputs:
  1657. * user -- user to query in current user_domain
  1658. * userlen -- length of username, 0 = strlen(user)
  1659. * pass -- plaintext password to check
  1660. * passlen -- length of password, 0 = strlen(pass)
  1661. * returns
  1662. * SASL_OK -- success
  1663. * SASL_NOMECH -- mechanism not supported
  1664. * SASL_NOVERIFY -- user found, but no verifier
  1665. * SASL_NOUSER -- user not found
  1666. */
  1667. int sasl_checkpass(sasl_conn_t *conn,
  1668. const char *user,
  1669. unsigned userlen,
  1670. const char *pass,
  1671. unsigned passlen)
  1672. {
  1673. int result;
  1674. if (_sasl_server_active==0) return SASL_NOTINIT;
  1675. /* check if it's just a query if we are enabled */
  1676. if (!user)
  1677. return SASL_OK;
  1678. if (!conn) return SASL_BADPARAM;
  1679. /* check params */
  1680. if (pass == NULL)
  1681. PARAMERROR(conn);
  1682. /* canonicalize the username */
  1683. result = _sasl_canon_user(conn, user, userlen,
  1684. SASL_CU_AUTHID | SASL_CU_AUTHZID,
  1685. &(conn->oparams));
  1686. if(result != SASL_OK) RETURN(conn, result);
  1687. user = conn->oparams.user;
  1688. /* Check the password and lookup additional properties */
  1689. result = _sasl_checkpass(conn, user, userlen, pass, passlen);
  1690. /* Do authorization */
  1691. if(result == SASL_OK) {
  1692. result = do_authorization((sasl_server_conn_t *)conn);
  1693. }
  1694. RETURN(conn,result);
  1695. }
  1696. /* check if a user exists on server
  1697. * conn -- connection context (may be NULL, used to hold last error)
  1698. * service -- registered name of the service using SASL (e.g. "imap")
  1699. * user_realm -- permits multiple user realms on server, NULL = default
  1700. * user -- NUL terminated user name
  1701. *
  1702. * returns:
  1703. * SASL_OK -- success
  1704. * SASL_DISABLED -- account disabled [FIXME: currently not detected]
  1705. * SASL_NOUSER -- user not found
  1706. * SASL_NOVERIFY -- user found, but no usable mechanism [FIXME: not supported]
  1707. * SASL_NOMECH -- no mechanisms enabled
  1708. * SASL_UNAVAIL -- remote authentication server unavailable, try again later
  1709. */
  1710. int sasl_user_exists(sasl_conn_t *conn,
  1711. const char *service,
  1712. const char *user_realm,
  1713. const char *user)
  1714. {
  1715. int result=SASL_NOMECH;
  1716. const char *mlist = NULL, *mech = NULL;
  1717. void *context;
  1718. sasl_getopt_t *getopt;
  1719. struct sasl_verify_password_s *v;
  1720. /* check params */
  1721. if (_sasl_server_active==0) return SASL_NOTINIT;
  1722. if (!conn) return SASL_BADPARAM;
  1723. if (!user || conn->type != SASL_CONN_SERVER)
  1724. PARAMERROR(conn);
  1725. if(!service) service = conn->service;
  1726. /* figure out how to check (i.e. auxprop or saslauthd or pwcheck) */
  1727. if (_sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context)
  1728. == SASL_OK) {
  1729. getopt(context, NULL, "pwcheck_method", &mlist, NULL);
  1730. }
  1731. if(!mlist) mlist = DEFAULT_CHECKPASS_MECH;
  1732. result = SASL_NOMECH;
  1733. mech = mlist;
  1734. while (*mech && result != SASL_OK) {
  1735. for (v = _sasl_verify_password; v->name; v++) {
  1736. if(is_mech(mech, v->name)) {
  1737. result = v->verify(conn, user, NULL, service, user_realm);
  1738. break;
  1739. }
  1740. }
  1741. if (result != SASL_OK) {
  1742. /* skip to next mech in list */
  1743. while (*mech && !isspace((int) *mech)) mech++;
  1744. while (*mech && isspace((int) *mech)) mech++;
  1745. }
  1746. }
  1747. /* Screen out the SASL_BADPARAM response
  1748. * we'll get from not giving a password */
  1749. if (result == SASL_BADPARAM) {
  1750. result = SASL_OK;
  1751. }
  1752. if (result == SASL_NOMECH) {
  1753. /* no mechanism available ?!? */
  1754. _sasl_log(conn, SASL_LOG_ERR, "no plaintext password verifier?");
  1755. sasl_seterror(conn, SASL_NOLOG, "no plaintext password verifier?");
  1756. }
  1757. RETURN(conn, result);
  1758. }
  1759. /* check if an apop exchange is valid
  1760. * (note this is an optional part of the SASL API)
  1761. * if challenge is NULL, just check if APOP is enabled
  1762. * inputs:
  1763. * challenge -- challenge which was sent to client
  1764. * challen -- length of challenge, 0 = strlen(challenge)
  1765. * response -- client response, "<user> <digest>" (RFC 1939)
  1766. * resplen -- length of response, 0 = strlen(response)
  1767. * returns
  1768. * SASL_OK -- success
  1769. * SASL_BADAUTH -- authentication failed
  1770. * SASL_BADPARAM -- missing challenge
  1771. * SASL_BADPROT -- protocol error (e.g., response in wrong format)
  1772. * SASL_NOVERIFY -- user found, but no verifier
  1773. * SASL_NOMECH -- mechanism not supported
  1774. * SASL_NOUSER -- user not found
  1775. */
  1776. int sasl_checkapop(sasl_conn_t *conn,
  1777. #ifdef DO_SASL_CHECKAPOP
  1778. const char *challenge,
  1779. unsigned challen __attribute__((unused)),
  1780. const char *response,
  1781. unsigned resplen __attribute__((unused)))
  1782. #else
  1783. const char *challenge __attribute__((unused)),
  1784. unsigned challen __attribute__((unused)),
  1785. const char *response __attribute__((unused)),
  1786. unsigned resplen __attribute__((unused)))
  1787. #endif
  1788. {
  1789. #ifdef DO_SASL_CHECKAPOP
  1790. sasl_server_conn_t *s_conn = (sasl_server_conn_t *) conn;
  1791. char *user, *user_end;
  1792. const char *password_request[] = { SASL_AUX_PASSWORD, NULL };
  1793. size_t user_len;
  1794. int result;
  1795. if (_sasl_server_active==0)
  1796. return SASL_NOTINIT;
  1797. /* check if it's just a query if we are enabled */
  1798. if(!challenge)
  1799. return SASL_OK;
  1800. /* check params */
  1801. if (!conn) return SASL_BADPARAM;
  1802. if (!response)
  1803. PARAMERROR(conn);
  1804. /* Parse out username and digest.
  1805. *
  1806. * Per RFC 1939, response must be "<user> <digest>", where
  1807. * <digest> is a 16-octet value which is sent in hexadecimal
  1808. * format, using lower-case ASCII characters.
  1809. */
  1810. user_end = strrchr(response, ' ');
  1811. if (!user_end || strspn(user_end + 1, "0123456789abcdef") != 32)
  1812. {
  1813. sasl_seterror(conn, 0, "Bad Digest");
  1814. RETURN(conn,SASL_BADPROT);
  1815. }
  1816. user_len = (size_t)(user_end - response);
  1817. user = sasl_ALLOC(user_len + 1);
  1818. memcpy(user, response, user_len);
  1819. user[user_len] = '\0';
  1820. result = prop_request(s_conn->sparams->propctx, password_request);
  1821. if(result != SASL_OK)
  1822. {
  1823. sasl_FREE(user);
  1824. RETURN(conn, result);
  1825. }
  1826. /* erase the plaintext password */
  1827. s_conn->sparams->utils->prop_erase(s_conn->sparams->propctx,
  1828. password_request[0]);
  1829. /* canonicalize the username and lookup any associated properties */
  1830. result = _sasl_canon_user_lookup (conn,
  1831. user,
  1832. user_len,
  1833. SASL_CU_AUTHID | SASL_CU_AUTHZID,
  1834. &(conn->oparams));
  1835. sasl_FREE(user);
  1836. if(result != SASL_OK) RETURN(conn, result);
  1837. /* Do APOP verification */
  1838. result = _sasl_auxprop_verify_apop(conn, conn->oparams.authid,
  1839. challenge, user_end + 1, s_conn->user_realm);
  1840. /* Do authorization */
  1841. if(result == SASL_OK) {
  1842. result = do_authorization((sasl_server_conn_t *)conn);
  1843. } else {
  1844. /* If verification failed, we don't want to encourage getprop to work */
  1845. conn->oparams.user = NULL;
  1846. conn->oparams.authid = NULL;
  1847. }
  1848. RETURN(conn, result);
  1849. #else /* sasl_checkapop was disabled at compile time */
  1850. sasl_seterror(conn, SASL_NOLOG,
  1851. "sasl_checkapop called, but was disabled at compile time");
  1852. RETURN(conn, SASL_NOMECH);
  1853. #endif /* DO_SASL_CHECKAPOP */
  1854. }
  1855. /* It would be nice if we can show other information like Author, Company, Year, plugin version */
  1856. static void
  1857. _sasl_print_mechanism (
  1858. server_sasl_mechanism_t *m,
  1859. sasl_info_callback_stage_t stage,
  1860. void *rock __attribute__((unused))
  1861. )
  1862. {
  1863. char delimiter;
  1864. if (stage == SASL_INFO_LIST_START) {
  1865. printf ("List of server plugins follows\n");
  1866. return;
  1867. } else if (stage == SASL_INFO_LIST_END) {
  1868. return;
  1869. }
  1870. /* Process the mechanism */
  1871. printf ("Plugin \"%s\" ", m->plugname);
  1872. switch (m->condition) {
  1873. case SASL_OK:
  1874. printf ("[loaded]");
  1875. break;
  1876. case SASL_CONTINUE:
  1877. printf ("[delayed]");
  1878. break;
  1879. case SASL_NOUSER:
  1880. printf ("[no users]");
  1881. break;
  1882. default:
  1883. printf ("[unknown]");
  1884. break;
  1885. }
  1886. printf (", \tAPI version: %d\n", m->version);
  1887. if (m->plug != NULL) {
  1888. printf ("\tSASL mechanism: %s, best SSF: %d, supports setpass: %s\n",
  1889. m->plug->mech_name,
  1890. m->plug->max_ssf,
  1891. (m->plug->setpass != NULL) ? "yes" : "no"
  1892. );
  1893. printf ("\tsecurity flags:");
  1894. delimiter = ' ';
  1895. if (m->plug->security_flags & SASL_SEC_NOANONYMOUS) {
  1896. printf ("%cNO_ANONYMOUS", delimiter);
  1897. delimiter = '|';
  1898. }
  1899. if (m->plug->security_flags & SASL_SEC_NOPLAINTEXT) {
  1900. printf ("%cNO_PLAINTEXT", delimiter);
  1901. delimiter = '|';
  1902. }
  1903. if (m->plug->security_flags & SASL_SEC_NOACTIVE) {
  1904. printf ("%cNO_ACTIVE", delimiter);
  1905. delimiter = '|';
  1906. }
  1907. if (m->plug->security_flags & SASL_SEC_NODICTIONARY) {
  1908. printf ("%cNO_DICTIONARY", delimiter);
  1909. delimiter = '|';
  1910. }
  1911. if (m->plug->security_flags & SASL_SEC_FORWARD_SECRECY) {
  1912. printf ("%cFORWARD_SECRECY", delimiter);
  1913. delimiter = '|';
  1914. }
  1915. if (m->plug->security_flags & SASL_SEC_PASS_CREDENTIALS) {
  1916. printf ("%cPASS_CREDENTIALS", delimiter);
  1917. delimiter = '|';
  1918. }
  1919. if (m->plug->security_flags & SASL_SEC_MUTUAL_AUTH) {
  1920. printf ("%cMUTUAL_AUTH", delimiter);
  1921. delimiter = '|';
  1922. }
  1923. printf ("\n\tfeatures:");
  1924. delimiter = ' ';
  1925. if (m->plug->features & SASL_FEAT_WANT_CLIENT_FIRST) {
  1926. printf ("%cWANT_CLIENT_FIRST", delimiter);
  1927. delimiter = '|';
  1928. }
  1929. if (m->plug->features & SASL_FEAT_SERVER_FIRST) {
  1930. printf ("%cSERVER_FIRST", delimiter);
  1931. delimiter = '|';
  1932. }
  1933. if (m->plug->features & SASL_FEAT_ALLOWS_PROXY) {
  1934. printf ("%cPROXY_AUTHENTICATION", delimiter);
  1935. delimiter = '|';
  1936. }
  1937. if (m->plug->features & SASL_FEAT_DONTUSE_USERPASSWD) {
  1938. printf ("%cDONTUSE_USERPASSWD", delimiter);
  1939. delimiter = '|';
  1940. }
  1941. if (m->plug->features & SASL_FEAT_NEEDSERVERFQDN) {
  1942. printf ("%cNEED_SERVER_FQDN", delimiter);
  1943. delimiter = '|';
  1944. }
  1945. /* Is this one used? */
  1946. if (m->plug->features & SASL_FEAT_SERVICE) {
  1947. printf ("%cSERVICE", delimiter);
  1948. delimiter = '|';
  1949. }
  1950. if (m->plug->features & SASL_FEAT_GETSECRET) {
  1951. printf ("%cNEED_GETSECRET", delimiter);
  1952. delimiter = '|';
  1953. }
  1954. if (m->plug->features & SASL_FEAT_GSS_FRAMING) {
  1955. printf ("%cGSS_FRAMING", delimiter);
  1956. delimiter = '|';
  1957. }
  1958. if (m->plug->features & SASL_FEAT_CHANNEL_BINDING) {
  1959. printf ("%cCHANNEL_BINDING", delimiter);
  1960. delimiter = '|';
  1961. }
  1962. if (m->plug->features & SASL_FEAT_SUPPORTS_HTTP) {
  1963. printf ("%cSUPPORTS_HTTP", delimiter);
  1964. delimiter = '|';
  1965. }
  1966. }
  1967. if (m->f) {
  1968. printf ("\n\twill be loaded from \"%s\"", m->f);
  1969. }
  1970. printf ("\n");
  1971. }
  1972. /* Dump information about available server plugins (separate functions should be
  1973. used for canon and auxprop plugins */
  1974. int sasl_server_plugin_info (
  1975. const char *c_mech_list, /* space separated mechanism list or NULL for ALL */
  1976. sasl_server_info_callback_t *info_cb,
  1977. void *info_cb_rock
  1978. )
  1979. {
  1980. mechanism_t *m;
  1981. server_sasl_mechanism_t plug_data;
  1982. char * cur_mech;
  1983. char *mech_list = NULL;
  1984. char * p;
  1985. if (info_cb == NULL) {
  1986. info_cb = _sasl_print_mechanism;
  1987. }
  1988. if (mechlist != NULL) {
  1989. info_cb (NULL, SASL_INFO_LIST_START, info_cb_rock);
  1990. if (c_mech_list == NULL) {
  1991. m = mechlist->mech_list; /* m point to beginning of the list */
  1992. while (m != NULL) {
  1993. memcpy (&plug_data, &m->m, sizeof(plug_data));
  1994. info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
  1995. m = m->next;
  1996. }
  1997. } else {
  1998. mech_list = strdup(c_mech_list);
  1999. cur_mech = mech_list;
  2000. while (cur_mech != NULL) {
  2001. p = strchr (cur_mech, ' ');
  2002. if (p != NULL) {
  2003. *p = '\0';
  2004. p++;
  2005. }
  2006. m = mechlist->mech_list; /* m point to beginning of the list */
  2007. while (m != NULL) {
  2008. if (strcasecmp (cur_mech, m->m.plug->mech_name) == 0) {
  2009. memcpy (&plug_data, &m->m, sizeof(plug_data));
  2010. info_cb (&plug_data, SASL_INFO_LIST_MECH, info_cb_rock);
  2011. }
  2012. m = m->next;
  2013. }
  2014. cur_mech = p;
  2015. }
  2016. free (mech_list);
  2017. }
  2018. info_cb (NULL, SASL_INFO_LIST_END, info_cb_rock);
  2019. return (SASL_OK);
  2020. }
  2021. return (SASL_NOTINIT);
  2022. }