common.c 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674
  1. /* common.c - Functions that are common to server and clinet
  2. * Rob Siemborski
  3. * Tim Martin
  4. */
  5. /*
  6. * Copyright (c) 1998-2016 Carnegie Mellon University. All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The name "Carnegie Mellon University" must not be used to
  21. * endorse or promote products derived from this software without
  22. * prior written permission. For permission or any other legal
  23. * details, please contact
  24. * Carnegie Mellon University
  25. * Center for Technology Transfer and Enterprise Creation
  26. * 4615 Forbes Avenue
  27. * Suite 302
  28. * Pittsburgh, PA 15213
  29. * (412) 268-7393, fax: (412) 268-7395
  30. * innovation@andrew.cmu.edu
  31. *
  32. * 4. Redistributions of any form whatsoever must retain the following
  33. * acknowledgment:
  34. * "This product includes software developed by Computing Services
  35. * at Carnegie Mellon University (http://www.cmu.edu/computing/)."
  36. *
  37. * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
  38. * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  39. * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
  40. * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  41. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
  42. * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
  43. * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  44. */
  45. #include <config.h>
  46. #include <stdio.h>
  47. #include <string.h>
  48. #include <stdlib.h>
  49. #include <limits.h>
  50. #ifdef HAVE_SYSLOG
  51. #include <syslog.h>
  52. #endif
  53. #include <stdarg.h>
  54. #include <ctype.h>
  55. #include <assert.h>
  56. #include <sasl.h>
  57. #include <saslutil.h>
  58. #include <saslplug.h>
  59. #include "saslint.h"
  60. #ifdef HAVE_UNISTD_H
  61. #include <unistd.h>
  62. #endif
  63. static const char *implementation_string = "Cyrus SASL";
  64. #define VSTR0(maj, min, step) #maj "." #min "." #step
  65. #define VSTR(maj, min, step) VSTR0(maj, min, step)
  66. #define SASL_VERSION_STRING VSTR(SASL_VERSION_MAJOR, SASL_VERSION_MINOR, \
  67. SASL_VERSION_STEP)
  68. static int _sasl_getpath(void *context __attribute__((unused)), const char **path);
  69. static int _sasl_getpath_simple(void *context __attribute__((unused)), const char **path);
  70. static int _sasl_getconfpath(void *context __attribute__((unused)), char ** path);
  71. static int _sasl_getconfpath_simple(void *context __attribute__((unused)), const char **path);
  72. #if !defined(WIN32)
  73. static char * _sasl_get_default_unix_path(void *context __attribute__((unused)),
  74. char * env_var_name, char * default_value);
  75. #else
  76. /* NB: Always returned allocated value */
  77. static char * _sasl_get_default_win_path(void *context __attribute__((unused)),
  78. TCHAR * reg_attr_name, char * default_value);
  79. #endif
  80. /* It turns out to be convenient to have a shared sasl_utils_t */
  81. const sasl_utils_t *sasl_global_utils = NULL;
  82. /* Should be a null-terminated array that lists the available mechanisms */
  83. static char **global_mech_list = NULL;
  84. void *free_mutex = NULL;
  85. int (*_sasl_client_cleanup_hook)(void) = NULL;
  86. int (*_sasl_server_cleanup_hook)(void) = NULL;
  87. int (*_sasl_client_idle_hook)(sasl_conn_t *conn) = NULL;
  88. int (*_sasl_server_idle_hook)(sasl_conn_t *conn) = NULL;
  89. sasl_allocation_utils_t _sasl_allocation_utils={
  90. (sasl_malloc_t *) &malloc,
  91. (sasl_calloc_t *) &calloc,
  92. (sasl_realloc_t *) &realloc,
  93. (sasl_free_t *) &free
  94. };
  95. int _sasl_allocation_locked = 0;
  96. #define SASL_ENCODEV_EXTRA 4096
  97. /* Default getpath/getconfpath callbacks. These can be edited by sasl_set_path(). */
  98. static sasl_callback_t default_getpath_cb = {
  99. SASL_CB_GETPATH, (sasl_callback_ft)&_sasl_getpath, NULL
  100. };
  101. static sasl_callback_t default_getconfpath_cb = {
  102. SASL_CB_GETCONFPATH, (sasl_callback_ft)&_sasl_getconfpath, NULL
  103. };
  104. static char * default_plugin_path = NULL;
  105. static char * default_conf_path = NULL;
  106. static int _sasl_global_getopt(void *context,
  107. const char *plugin_name,
  108. const char *option,
  109. const char ** result,
  110. unsigned *len);
  111. /* Intenal mutex functions do as little as possible (no thread protection) */
  112. static void *sasl_mutex_alloc(void)
  113. {
  114. return (void *)0x1;
  115. }
  116. static int sasl_mutex_lock(void *mutex __attribute__((unused)))
  117. {
  118. return SASL_OK;
  119. }
  120. static int sasl_mutex_unlock(void *mutex __attribute__((unused)))
  121. {
  122. return SASL_OK;
  123. }
  124. static void sasl_mutex_free(void *mutex __attribute__((unused)))
  125. {
  126. return;
  127. }
  128. sasl_mutex_utils_t _sasl_mutex_utils={
  129. &sasl_mutex_alloc,
  130. &sasl_mutex_lock,
  131. &sasl_mutex_unlock,
  132. &sasl_mutex_free
  133. };
  134. void sasl_set_mutex(sasl_mutex_alloc_t *n,
  135. sasl_mutex_lock_t *l,
  136. sasl_mutex_unlock_t *u,
  137. sasl_mutex_free_t *d)
  138. {
  139. /* Disallow mutex function changes once sasl_client_init
  140. and/or sasl_server_init is called */
  141. if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
  142. return;
  143. }
  144. _sasl_mutex_utils.alloc=n;
  145. _sasl_mutex_utils.lock=l;
  146. _sasl_mutex_utils.unlock=u;
  147. _sasl_mutex_utils.free=d;
  148. }
  149. /* copy a string to malloced memory */
  150. int _sasl_strdup(const char *in, char **out, size_t *outlen)
  151. {
  152. size_t len = strlen(in);
  153. if (outlen) *outlen = len;
  154. *out=sasl_ALLOC((unsigned) len + 1);
  155. if (! *out) return SASL_NOMEM;
  156. strcpy((char *) *out, in);
  157. return SASL_OK;
  158. }
  159. /* adds a string to the buffer; reallocing if need be */
  160. int _sasl_add_string(char **out, size_t *alloclen,
  161. size_t *outlen, const char *add)
  162. {
  163. size_t addlen;
  164. if (add==NULL) add = "(null)";
  165. addlen=strlen(add); /* only compute once */
  166. if (_buf_alloc(out, alloclen, (*outlen)+addlen+1)!=SASL_OK)
  167. return SASL_NOMEM;
  168. strcpy(*out + *outlen, add);
  169. *outlen += addlen;
  170. return SASL_OK;
  171. }
  172. /* a simpler way to set plugin path or configuration file path
  173. * without the need to set sasl_getpath_t callback.
  174. *
  175. * This function can be called before sasl_server_init/sasl_client_init.
  176. *
  177. * Don't call this function without locking in a multithreaded application.
  178. */
  179. int sasl_set_path (int path_type, char * path)
  180. {
  181. int result;
  182. if (path == NULL) {
  183. return (SASL_FAIL);
  184. }
  185. switch (path_type) {
  186. case SASL_PATH_TYPE_PLUGIN:
  187. if (default_plugin_path != NULL) {
  188. sasl_FREE (default_plugin_path);
  189. default_plugin_path = NULL;
  190. }
  191. result = _sasl_strdup (path, &default_plugin_path, NULL);
  192. if (result != SASL_OK) {
  193. return (result);
  194. }
  195. /* Update the default getpath_t callback */
  196. default_getpath_cb.proc = (sasl_callback_ft)&_sasl_getpath_simple;
  197. break;
  198. case SASL_PATH_TYPE_CONFIG:
  199. if (default_conf_path != NULL) {
  200. sasl_FREE (default_conf_path);
  201. default_conf_path = NULL;
  202. }
  203. result = _sasl_strdup (path, &default_conf_path, NULL);
  204. if (result != SASL_OK) {
  205. return (result);
  206. }
  207. /* Update the default getpath_t callback */
  208. default_getconfpath_cb.proc = (sasl_callback_ft)&_sasl_getconfpath_simple;
  209. break;
  210. default:
  211. return (SASL_FAIL);
  212. }
  213. return (SASL_OK);
  214. }
  215. /* return the version of the cyrus sasl library as compiled,
  216. * using 32 bits: high byte is major version, second byte is minor version,
  217. * low 16 bits are step #.
  218. * Patch version is not available using this function,
  219. * use sasl_version_info() instead.
  220. */
  221. void sasl_version(const char **implementation, int *version)
  222. {
  223. if(implementation) *implementation = implementation_string;
  224. /* NB: the format is not the same as in SASL_VERSION_FULL */
  225. if(version) *version = (SASL_VERSION_MAJOR << 24) |
  226. (SASL_VERSION_MINOR << 16) |
  227. (SASL_VERSION_STEP);
  228. }
  229. /* Extended version of sasl_version above */
  230. void sasl_version_info (const char **implementation, const char **version_string,
  231. int *version_major, int *version_minor, int *version_step,
  232. int *version_patch)
  233. {
  234. if (implementation) *implementation = implementation_string;
  235. if (version_string) *version_string = SASL_VERSION_STRING;
  236. if (version_major) *version_major = SASL_VERSION_MAJOR;
  237. if (version_minor) *version_minor = SASL_VERSION_MINOR;
  238. if (version_step) *version_step = SASL_VERSION_STEP;
  239. /* Version patch is always 0 for CMU SASL */
  240. if (version_patch) *version_patch = 0;
  241. }
  242. /* security-encode a regular string. Mostly a wrapper for sasl_encodev */
  243. /* output is only valid until next call to sasl_encode or sasl_encodev */
  244. int sasl_encode(sasl_conn_t *conn, const char *input,
  245. unsigned inputlen,
  246. const char **output, unsigned *outputlen)
  247. {
  248. int result;
  249. struct iovec tmp;
  250. if(!conn) return SASL_BADPARAM;
  251. if(!input || !inputlen || !output || !outputlen)
  252. PARAMERROR(conn);
  253. /* maxoutbuf checking is done in sasl_encodev */
  254. /* Note: We are casting a const pointer here, but it's okay
  255. * because we believe people downstream of us are well-behaved, and the
  256. * alternative is an absolute mess, performance-wise. */
  257. tmp.iov_base = (void *)input;
  258. tmp.iov_len = inputlen;
  259. result = sasl_encodev(conn, &tmp, 1, output, outputlen);
  260. RETURN(conn, result);
  261. }
  262. /* Internal function that doesn't do any verification */
  263. static int
  264. _sasl_encodev (sasl_conn_t *conn,
  265. const struct iovec *invec,
  266. unsigned numiov,
  267. int * p_num_packets, /* number of packets generated so far */
  268. const char **output, /* previous output, if *p_num_packets > 0 */
  269. unsigned *outputlen)
  270. {
  271. int result;
  272. char * new_buf;
  273. assert (conn->oparams.encode != NULL);
  274. if (*p_num_packets == 1) {
  275. /* This is the second call to this function,
  276. so we need to allocate a new output buffer
  277. and copy existing data there. */
  278. conn->multipacket_encoded_data.curlen = *outputlen;
  279. if (conn->multipacket_encoded_data.data == NULL) {
  280. conn->multipacket_encoded_data.reallen =
  281. conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
  282. conn->multipacket_encoded_data.data =
  283. sasl_ALLOC(conn->multipacket_encoded_data.reallen + 1);
  284. if (conn->multipacket_encoded_data.data == NULL) {
  285. MEMERROR(conn);
  286. }
  287. } else {
  288. /* A buffer left from a previous sasl_encodev call.
  289. Make sure it is big enough. */
  290. if (conn->multipacket_encoded_data.curlen >
  291. conn->multipacket_encoded_data.reallen) {
  292. conn->multipacket_encoded_data.reallen =
  293. conn->multipacket_encoded_data.curlen + SASL_ENCODEV_EXTRA;
  294. new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
  295. conn->multipacket_encoded_data.reallen + 1);
  296. if (new_buf == NULL) {
  297. MEMERROR(conn);
  298. }
  299. conn->multipacket_encoded_data.data = new_buf;
  300. }
  301. }
  302. memcpy (conn->multipacket_encoded_data.data,
  303. *output,
  304. *outputlen);
  305. }
  306. result = conn->oparams.encode(conn->context,
  307. invec,
  308. numiov,
  309. output,
  310. outputlen);
  311. if (*p_num_packets > 0 && result == SASL_OK) {
  312. /* Is the allocated buffer big enough? If not, grow it. */
  313. if ((conn->multipacket_encoded_data.curlen + *outputlen) >
  314. conn->multipacket_encoded_data.reallen) {
  315. conn->multipacket_encoded_data.reallen =
  316. conn->multipacket_encoded_data.curlen + *outputlen;
  317. new_buf = sasl_REALLOC(conn->multipacket_encoded_data.data,
  318. conn->multipacket_encoded_data.reallen + 1);
  319. if (new_buf == NULL) {
  320. MEMERROR(conn);
  321. }
  322. conn->multipacket_encoded_data.data = new_buf;
  323. }
  324. /* Append new data to the end of the buffer */
  325. memcpy (conn->multipacket_encoded_data.data +
  326. conn->multipacket_encoded_data.curlen,
  327. *output,
  328. *outputlen);
  329. conn->multipacket_encoded_data.curlen += *outputlen;
  330. *output = conn->multipacket_encoded_data.data;
  331. *outputlen = (unsigned)conn->multipacket_encoded_data.curlen;
  332. }
  333. (*p_num_packets)++;
  334. RETURN(conn, result);
  335. }
  336. /* security-encode an iovec */
  337. /* output is only valid until the next call to sasl_encode or sasl_encodev */
  338. int sasl_encodev(sasl_conn_t *conn,
  339. const struct iovec *invec,
  340. unsigned numiov,
  341. const char **output,
  342. unsigned *outputlen)
  343. {
  344. int result = SASL_OK;
  345. unsigned i;
  346. unsigned j;
  347. size_t total_size = 0;
  348. struct iovec *cur_invec = NULL;
  349. struct iovec last_invec;
  350. unsigned cur_numiov;
  351. char * next_buf = NULL;
  352. size_t remainder_len;
  353. unsigned index_offset;
  354. unsigned allocated = 0;
  355. /* Number of generated SASL packets */
  356. int num_packets = 0;
  357. if (!conn) return SASL_BADPARAM;
  358. if (! invec || ! output || ! outputlen || numiov < 1) {
  359. PARAMERROR(conn);
  360. }
  361. if (!conn->props.maxbufsize) {
  362. sasl_seterror(conn, 0,
  363. "called sasl_encode[v] with application that does not support security layers");
  364. return SASL_TOOWEAK;
  365. }
  366. /* If oparams.encode is NULL, this means there is no SASL security
  367. layer in effect, so no SASL framing is needed. */
  368. if (conn->oparams.encode == NULL) {
  369. result = _iovec_to_buf(invec, numiov, &conn->encode_buf);
  370. if (result != SASL_OK) INTERROR(conn, result);
  371. *output = conn->encode_buf->data;
  372. *outputlen = (unsigned) conn->encode_buf->curlen;
  373. RETURN(conn, result);
  374. }
  375. /* This might be better to check on a per-plugin basis, but I think
  376. * it's cleaner and more effective here. It also encourages plugins
  377. * to be honest about what they accept */
  378. last_invec.iov_base = NULL;
  379. remainder_len = 0;
  380. next_buf = NULL;
  381. i = 0;
  382. while (i < numiov) {
  383. if ((total_size + invec[i].iov_len) > conn->oparams.maxoutbuf) {
  384. /* CLAIM: total_size < conn->oparams.maxoutbuf */
  385. /* Fit as many bytes in last_invec, so that we have conn->oparams.maxoutbuf
  386. bytes in total. */
  387. last_invec.iov_len = conn->oparams.maxoutbuf - total_size;
  388. /* Point to the first byte of the current record. */
  389. last_invec.iov_base = invec[i].iov_base;
  390. /* Note that total_size < conn->oparams.maxoutbuf */
  391. /* The total size of the iov is bigger then the other end can accept.
  392. So we allocate a new iov that contains just enough. */
  393. /* +1 --- for the tail record */
  394. cur_numiov = i + 1;
  395. /* +1 --- just in case we need the head record */
  396. if ((cur_numiov + 1) > allocated) {
  397. struct iovec *new_invec;
  398. allocated = cur_numiov + 1;
  399. new_invec = sasl_REALLOC (cur_invec, sizeof(struct iovec) * allocated);
  400. if (new_invec == NULL) {
  401. if (cur_invec != NULL) {
  402. sasl_FREE(cur_invec);
  403. }
  404. MEMERROR(conn);
  405. }
  406. cur_invec = new_invec;
  407. }
  408. if (next_buf != NULL) {
  409. cur_invec[0].iov_base = next_buf;
  410. cur_invec[0].iov_len = (long)remainder_len;
  411. cur_numiov++;
  412. index_offset = 1;
  413. } else {
  414. index_offset = 0;
  415. }
  416. if (i > 0) {
  417. /* Copy all previous chunks */
  418. /* NOTE - The starting index in invec is always 0 */
  419. for (j = 0; j < i; j++) {
  420. cur_invec[j + index_offset] = invec[j];
  421. }
  422. }
  423. /* Initialize the last record */
  424. cur_invec[i + index_offset] = last_invec;
  425. result = _sasl_encodev (conn,
  426. cur_invec,
  427. cur_numiov,
  428. &num_packets,
  429. output,
  430. outputlen);
  431. if (result != SASL_OK) {
  432. goto cleanup;
  433. }
  434. /* Point to the first byte that wouldn't fit into
  435. the conn->oparams.maxoutbuf buffer. */
  436. /* Note, if next_buf points to the very end of the IOV record,
  437. it will be reset to NULL below */
  438. /* Note, that some platforms define iov_base as "void *",
  439. thus the typecase below */
  440. next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
  441. /* Note - remainder_len is how many bytes left to be encoded in
  442. the current IOV slot. */
  443. remainder_len = (total_size + invec[i].iov_len) - conn->oparams.maxoutbuf;
  444. /* Skip all consumed IOV records */
  445. invec += i + 1;
  446. numiov = numiov - (i + 1);
  447. i = 0;
  448. while (remainder_len > conn->oparams.maxoutbuf) {
  449. last_invec.iov_base = next_buf;
  450. last_invec.iov_len = conn->oparams.maxoutbuf;
  451. /* Note, if next_buf points to the very end of the IOV record,
  452. it will be reset to NULL below */
  453. /* Note, that some platforms define iov_base as "void *",
  454. thus the typecase below */
  455. next_buf = (char *) last_invec.iov_base + last_invec.iov_len;
  456. remainder_len = remainder_len - conn->oparams.maxoutbuf;
  457. result = _sasl_encodev (conn,
  458. &last_invec,
  459. 1,
  460. &num_packets,
  461. output,
  462. outputlen);
  463. if (result != SASL_OK) {
  464. goto cleanup;
  465. }
  466. }
  467. total_size = remainder_len;
  468. if (remainder_len == 0) {
  469. /* Just clear next_buf */
  470. next_buf = NULL;
  471. }
  472. } else {
  473. total_size += invec[i].iov_len;
  474. i++;
  475. }
  476. }
  477. /* CLAIM - The remaining data is shorter then conn->oparams.maxoutbuf. */
  478. /* Force encoding of any partial buffer. Might not be optimal on the wire. */
  479. if (next_buf != NULL) {
  480. last_invec.iov_base = next_buf;
  481. last_invec.iov_len = (long)remainder_len;
  482. result = _sasl_encodev (conn,
  483. &last_invec,
  484. 1,
  485. &num_packets,
  486. output,
  487. outputlen);
  488. if (result != SASL_OK) {
  489. goto cleanup;
  490. }
  491. }
  492. if (numiov > 0) {
  493. result = _sasl_encodev (conn,
  494. invec,
  495. numiov,
  496. &num_packets,
  497. output,
  498. outputlen);
  499. }
  500. cleanup:
  501. if (cur_invec != NULL) {
  502. sasl_FREE(cur_invec);
  503. }
  504. RETURN(conn, result);
  505. }
  506. /* output is only valid until next call to sasl_decode */
  507. int sasl_decode(sasl_conn_t *conn,
  508. const char *input, unsigned inputlen,
  509. const char **output, unsigned *outputlen)
  510. {
  511. int result;
  512. if(!conn) return SASL_BADPARAM;
  513. if(!input || !output || !outputlen)
  514. PARAMERROR(conn);
  515. if(!conn->props.maxbufsize) {
  516. sasl_seterror(conn, 0,
  517. "called sasl_decode with application that does not support security layers");
  518. RETURN(conn, SASL_TOOWEAK);
  519. }
  520. if(conn->oparams.decode == NULL)
  521. {
  522. /* Since we know how long the output is maximally, we can
  523. * just allocate it to begin with, and never need another
  524. * allocation! */
  525. /* However, if they pass us more than they actually can take,
  526. * we cannot help them... */
  527. if(inputlen > conn->props.maxbufsize) {
  528. sasl_seterror(conn, 0,
  529. "input too large for default sasl_decode");
  530. RETURN(conn,SASL_BUFOVER);
  531. }
  532. if(!conn->decode_buf)
  533. conn->decode_buf = sasl_ALLOC(conn->props.maxbufsize + 1);
  534. if(!conn->decode_buf)
  535. MEMERROR(conn);
  536. memcpy(conn->decode_buf, input, inputlen);
  537. conn->decode_buf[inputlen] = '\0';
  538. *output = conn->decode_buf;
  539. *outputlen = inputlen;
  540. return SASL_OK;
  541. } else {
  542. result = conn->oparams.decode(conn->context, input, inputlen,
  543. output, outputlen);
  544. /* NULL an empty buffer (for misbehaved applications) */
  545. if (*outputlen == 0) *output = NULL;
  546. RETURN(conn, result);
  547. }
  548. INTERROR(conn, SASL_FAIL);
  549. }
  550. void
  551. sasl_set_alloc(sasl_malloc_t *m,
  552. sasl_calloc_t *c,
  553. sasl_realloc_t *r,
  554. sasl_free_t *f)
  555. {
  556. if (_sasl_allocation_locked++) return;
  557. _sasl_allocation_utils.malloc=m;
  558. _sasl_allocation_utils.calloc=c;
  559. _sasl_allocation_utils.realloc=r;
  560. _sasl_allocation_utils.free=f;
  561. }
  562. void sasl_common_done(void)
  563. {
  564. /* NOTE - the caller will need to reinitialize the values,
  565. if it is going to call sasl_client_init/sasl_server_init again. */
  566. if (default_plugin_path != NULL) {
  567. sasl_FREE (default_plugin_path);
  568. default_plugin_path = NULL;
  569. }
  570. if (default_conf_path != NULL) {
  571. sasl_FREE (default_conf_path);
  572. default_conf_path = NULL;
  573. }
  574. _sasl_canonuser_free();
  575. _sasl_done_with_plugins();
  576. sasl_MUTEX_FREE(free_mutex);
  577. free_mutex = NULL;
  578. _sasl_free_utils(&sasl_global_utils);
  579. if (global_mech_list) {
  580. sasl_FREE(global_mech_list);
  581. global_mech_list = NULL;
  582. }
  583. }
  584. /* This function is for backward compatibility */
  585. void sasl_done(void)
  586. {
  587. if (_sasl_server_cleanup_hook && _sasl_server_cleanup_hook() == SASL_OK) {
  588. _sasl_server_idle_hook = NULL;
  589. _sasl_server_cleanup_hook = NULL;
  590. }
  591. if (_sasl_client_cleanup_hook && _sasl_client_cleanup_hook() == SASL_OK) {
  592. _sasl_client_idle_hook = NULL;
  593. _sasl_client_cleanup_hook = NULL;
  594. }
  595. if (_sasl_server_cleanup_hook || _sasl_client_cleanup_hook) {
  596. return;
  597. }
  598. sasl_common_done();
  599. }
  600. /* fills in the base sasl_conn_t info */
  601. int _sasl_conn_init(sasl_conn_t *conn,
  602. const char *service,
  603. unsigned int flags,
  604. enum Sasl_conn_type type,
  605. int (*idle_hook)(sasl_conn_t *conn),
  606. const char *serverFQDN,
  607. const char *iplocalport,
  608. const char *ipremoteport,
  609. const sasl_callback_t *callbacks,
  610. const sasl_global_callbacks_t *global_callbacks) {
  611. int result = SASL_OK;
  612. conn->type = type;
  613. result = _sasl_strdup(service, &conn->service, NULL);
  614. if (result != SASL_OK)
  615. MEMERROR(conn);
  616. memset(&conn->oparams, 0, sizeof(sasl_out_params_t));
  617. memset(&conn->external, 0, sizeof(_sasl_external_properties_t));
  618. conn->flags = flags;
  619. result = sasl_setprop(conn, SASL_IPLOCALPORT, iplocalport);
  620. if(result != SASL_OK)
  621. RETURN(conn, result);
  622. result = sasl_setprop(conn, SASL_IPREMOTEPORT, ipremoteport);
  623. if(result != SASL_OK)
  624. RETURN(conn, result);
  625. conn->encode_buf = NULL;
  626. conn->context = NULL;
  627. conn->secret = NULL;
  628. conn->idle_hook = idle_hook;
  629. conn->callbacks = callbacks;
  630. conn->global_callbacks = global_callbacks;
  631. memset(&conn->props, 0, sizeof(conn->props));
  632. /* Start this buffer out as an empty string */
  633. conn->error_code = SASL_OK;
  634. conn->errdetail_buf = conn->error_buf = NULL;
  635. conn->errdetail_buf_len = conn->error_buf_len = 150;
  636. result = _buf_alloc(&conn->error_buf, &conn->error_buf_len, 150);
  637. if(result != SASL_OK) MEMERROR(conn);
  638. result = _buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, 150);
  639. if(result != SASL_OK) MEMERROR(conn);
  640. conn->error_buf[0] = '\0';
  641. conn->errdetail_buf[0] = '\0';
  642. conn->decode_buf = NULL;
  643. if(serverFQDN) {
  644. result = _sasl_strdup(serverFQDN, &conn->serverFQDN, NULL);
  645. sasl_strlower (conn->serverFQDN);
  646. } else if (conn->type == SASL_CONN_SERVER) {
  647. /* We can fake it because we *are* the server */
  648. char name[MAXFQDNLEN];
  649. memset(name, 0, sizeof(name));
  650. if (get_fqhostname (name, MAXFQDNLEN, 0) != 0) {
  651. return (SASL_FAIL);
  652. }
  653. result = _sasl_strdup(name, &conn->serverFQDN, NULL);
  654. } else {
  655. conn->serverFQDN = NULL;
  656. }
  657. if(result != SASL_OK) MEMERROR( conn );
  658. RETURN(conn, SASL_OK);
  659. }
  660. int _sasl_common_init(sasl_global_callbacks_t *global_callbacks)
  661. {
  662. int result;
  663. /* The last specified global callback always wins */
  664. if (sasl_global_utils != NULL) {
  665. sasl_utils_t * global_utils = (sasl_utils_t *)sasl_global_utils;
  666. global_utils->getopt = &_sasl_global_getopt;
  667. global_utils->getopt_context = global_callbacks;
  668. }
  669. /* Do nothing if we are already initialized */
  670. if (free_mutex) {
  671. return SASL_OK;
  672. }
  673. /* Setup the global utilities */
  674. if(!sasl_global_utils) {
  675. sasl_global_utils = _sasl_alloc_utils(NULL, global_callbacks);
  676. if(sasl_global_utils == NULL) return SASL_NOMEM;
  677. }
  678. /* Init the canon_user plugin */
  679. result = sasl_canonuser_add_plugin("INTERNAL", internal_canonuser_init);
  680. if(result != SASL_OK) return result;
  681. if (!free_mutex) {
  682. free_mutex = sasl_MUTEX_ALLOC();
  683. }
  684. if (!free_mutex) return SASL_FAIL;
  685. return SASL_OK;
  686. }
  687. /* dispose connection state, sets it to NULL
  688. * checks for pointer to NULL
  689. */
  690. void sasl_dispose(sasl_conn_t **pconn)
  691. {
  692. int result;
  693. if (! pconn) return;
  694. if (! *pconn) return;
  695. /* serialize disposes. this is necessary because we can't
  696. dispose of conn->mutex if someone else is locked on it */
  697. if (!free_mutex) {
  698. free_mutex = sasl_MUTEX_ALLOC();
  699. if (!free_mutex) return;
  700. }
  701. result = sasl_MUTEX_LOCK(free_mutex);
  702. if (result!=SASL_OK) return;
  703. /* *pconn might have become NULL by now */
  704. if (*pconn) {
  705. (*pconn)->destroy_conn(*pconn);
  706. sasl_FREE(*pconn);
  707. *pconn=NULL;
  708. }
  709. sasl_MUTEX_UNLOCK(free_mutex);
  710. }
  711. void _sasl_conn_dispose(sasl_conn_t *conn) {
  712. if (conn->serverFQDN)
  713. sasl_FREE(conn->serverFQDN);
  714. if (conn->external.auth_id)
  715. sasl_FREE(conn->external.auth_id);
  716. if(conn->encode_buf) {
  717. if(conn->encode_buf->data) sasl_FREE(conn->encode_buf->data);
  718. sasl_FREE(conn->encode_buf);
  719. }
  720. if(conn->error_buf)
  721. sasl_FREE(conn->error_buf);
  722. if(conn->errdetail_buf)
  723. sasl_FREE(conn->errdetail_buf);
  724. if(conn->decode_buf)
  725. sasl_FREE(conn->decode_buf);
  726. if(conn->mechlist_buf)
  727. sasl_FREE(conn->mechlist_buf);
  728. if(conn->service)
  729. sasl_FREE(conn->service);
  730. if (conn->multipacket_encoded_data.data) {
  731. sasl_FREE(conn->multipacket_encoded_data.data);
  732. }
  733. /* oparams sub-members should be freed by the plugin, in so much
  734. * as they were allocated by the plugin */
  735. }
  736. /* get property from SASL connection state
  737. * propnum -- property number
  738. * pvalue -- pointer to value
  739. * returns:
  740. * SASL_OK -- no error
  741. * SASL_NOTDONE -- property not available yet
  742. * SASL_BADPARAM -- bad property number or SASL context is NULL
  743. */
  744. int sasl_getprop(sasl_conn_t *conn, int propnum, const void **pvalue)
  745. {
  746. int result = SASL_OK;
  747. sasl_getopt_t *getopt;
  748. void *context;
  749. if (! conn) return SASL_BADPARAM;
  750. if (! pvalue) PARAMERROR(conn);
  751. switch(propnum)
  752. {
  753. case SASL_SSF:
  754. *(sasl_ssf_t **)pvalue= &conn->oparams.mech_ssf;
  755. break;
  756. case SASL_MAXOUTBUF:
  757. *(unsigned **)pvalue = &conn->oparams.maxoutbuf;
  758. break;
  759. case SASL_GETOPTCTX:
  760. result = _sasl_getcallback(conn, SASL_CB_GETOPT, (sasl_callback_ft *)&getopt, &context);
  761. if(result != SASL_OK) break;
  762. *(void **)pvalue = context;
  763. break;
  764. case SASL_CALLBACK:
  765. *(const sasl_callback_t **)pvalue = conn->callbacks;
  766. break;
  767. case SASL_IPLOCALPORT:
  768. if(conn->got_ip_local)
  769. *(const char **)pvalue = conn->iplocalport;
  770. else {
  771. *(const char **)pvalue = NULL;
  772. result = SASL_NOTDONE;
  773. }
  774. break;
  775. case SASL_IPREMOTEPORT:
  776. if(conn->got_ip_remote)
  777. *(const char **)pvalue = conn->ipremoteport;
  778. else {
  779. *(const char **)pvalue = NULL;
  780. result = SASL_NOTDONE;
  781. }
  782. break;
  783. case SASL_USERNAME:
  784. if(! conn->oparams.user)
  785. result = SASL_NOTDONE;
  786. else
  787. *((const char **)pvalue) = conn->oparams.user;
  788. break;
  789. case SASL_AUTHUSER:
  790. if(! conn->oparams.authid)
  791. result = SASL_NOTDONE;
  792. else
  793. *((const char **)pvalue) = conn->oparams.authid;
  794. break;
  795. case SASL_APPNAME:
  796. /* Currently we only support server side contexts, but we should
  797. be able to extend this to support client side contexts as well */
  798. if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
  799. else
  800. *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->sparams->appname;
  801. break;
  802. case SASL_SERVERFQDN:
  803. *((const char **)pvalue) = conn->serverFQDN;
  804. break;
  805. case SASL_DEFUSERREALM:
  806. if(conn->type != SASL_CONN_SERVER) result = SASL_BADPROT;
  807. else
  808. *((const char **)pvalue) = ((sasl_server_conn_t *)conn)->user_realm;
  809. break;
  810. case SASL_SERVICE:
  811. *((const char **)pvalue) = conn->service;
  812. break;
  813. case SASL_AUTHSOURCE: /* name of plugin (not name of mech) */
  814. if(conn->type == SASL_CONN_CLIENT) {
  815. if(!((sasl_client_conn_t *)conn)->mech) {
  816. result = SASL_NOTDONE;
  817. break;
  818. }
  819. *((const char **)pvalue) =
  820. ((sasl_client_conn_t *)conn)->mech->m.plugname;
  821. } else if (conn->type == SASL_CONN_SERVER) {
  822. if(!((sasl_server_conn_t *)conn)->mech) {
  823. result = SASL_NOTDONE;
  824. break;
  825. }
  826. *((const char **)pvalue) =
  827. ((sasl_server_conn_t *)conn)->mech->m.plugname;
  828. } else {
  829. result = SASL_BADPARAM;
  830. }
  831. break;
  832. case SASL_MECHNAME: /* name of mech */
  833. if(conn->type == SASL_CONN_CLIENT) {
  834. if(!((sasl_client_conn_t *)conn)->mech) {
  835. result = SASL_NOTDONE;
  836. break;
  837. }
  838. *((const char **)pvalue) =
  839. ((sasl_client_conn_t *)conn)->mech->m.plug->mech_name;
  840. } else if (conn->type == SASL_CONN_SERVER) {
  841. if(!((sasl_server_conn_t *)conn)->mech) {
  842. result = SASL_NOTDONE;
  843. break;
  844. }
  845. *((const char **)pvalue) =
  846. ((sasl_server_conn_t *)conn)->mech->m.plug->mech_name;
  847. } else {
  848. result = SASL_BADPARAM;
  849. }
  850. if(!(*pvalue) && result == SASL_OK) result = SASL_NOTDONE;
  851. break;
  852. case SASL_PLUGERR:
  853. *((const char **)pvalue) = conn->error_buf;
  854. break;
  855. case SASL_DELEGATEDCREDS:
  856. /* We can't really distinguish between "no delegated credentials"
  857. and "authentication not finished" */
  858. if(! conn->oparams.client_creds)
  859. result = SASL_NOTDONE;
  860. else
  861. *((const char **)pvalue) = conn->oparams.client_creds;
  862. break;
  863. case SASL_GSS_PEER_NAME:
  864. if(! conn->oparams.gss_peer_name)
  865. result = SASL_NOTDONE;
  866. else
  867. *((const char **)pvalue) = conn->oparams.gss_peer_name;
  868. break;
  869. case SASL_GSS_LOCAL_NAME:
  870. if(! conn->oparams.gss_local_name)
  871. result = SASL_NOTDONE;
  872. else
  873. *((const char **)pvalue) = conn->oparams.gss_local_name;
  874. break;
  875. case SASL_SSF_EXTERNAL:
  876. *((const sasl_ssf_t **)pvalue) = &conn->external.ssf;
  877. break;
  878. case SASL_AUTH_EXTERNAL:
  879. *((const char **)pvalue) = conn->external.auth_id;
  880. break;
  881. case SASL_SEC_PROPS:
  882. *((const sasl_security_properties_t **)pvalue) = &conn->props;
  883. break;
  884. case SASL_GSS_CREDS:
  885. if(conn->type == SASL_CONN_CLIENT)
  886. *(const void **)pvalue =
  887. ((sasl_client_conn_t *)conn)->cparams->gss_creds;
  888. else
  889. *(const void **)pvalue =
  890. ((sasl_server_conn_t *)conn)->sparams->gss_creds;
  891. break;
  892. case SASL_HTTP_REQUEST: {
  893. if (conn->type == SASL_CONN_SERVER)
  894. *(const sasl_http_request_t **)pvalue =
  895. ((sasl_server_conn_t *)conn)->sparams->http_request;
  896. else
  897. *(const sasl_http_request_t **)pvalue =
  898. ((sasl_client_conn_t *)conn)->cparams->http_request;
  899. break;
  900. }
  901. default:
  902. result = SASL_BADPARAM;
  903. }
  904. if(result == SASL_BADPARAM) {
  905. PARAMERROR(conn);
  906. } else if(result == SASL_NOTDONE) {
  907. sasl_seterror(conn, SASL_NOLOG,
  908. "Information that was requested is not yet available.");
  909. RETURN(conn, result);
  910. } else if(result != SASL_OK) {
  911. INTERROR(conn, result);
  912. } else
  913. RETURN(conn, result);
  914. }
  915. /* set property in SASL connection state
  916. * returns:
  917. * SASL_OK -- value set
  918. * SASL_BADPARAM -- invalid property or value
  919. */
  920. int sasl_setprop(sasl_conn_t *conn, int propnum, const void *value)
  921. {
  922. int result = SASL_OK;
  923. char *str;
  924. /* make sure the sasl context is valid */
  925. if (!conn)
  926. return SASL_BADPARAM;
  927. switch(propnum)
  928. {
  929. case SASL_SSF_EXTERNAL:
  930. conn->external.ssf = *((sasl_ssf_t *)value);
  931. if(conn->type == SASL_CONN_SERVER) {
  932. ((sasl_server_conn_t*)conn)->sparams->external_ssf =
  933. conn->external.ssf;
  934. } else {
  935. ((sasl_client_conn_t*)conn)->cparams->external_ssf =
  936. conn->external.ssf;
  937. }
  938. break;
  939. case SASL_AUTH_EXTERNAL:
  940. if(value && strlen(value)) {
  941. result = _sasl_strdup(value, &str, NULL);
  942. if(result != SASL_OK) MEMERROR(conn);
  943. } else {
  944. str = NULL;
  945. }
  946. if(conn->external.auth_id)
  947. sasl_FREE(conn->external.auth_id);
  948. conn->external.auth_id = str;
  949. break;
  950. case SASL_DEFUSERREALM:
  951. if(conn->type != SASL_CONN_SERVER) {
  952. sasl_seterror(conn, 0, "Tried to set realm on non-server connection");
  953. result = SASL_BADPROT;
  954. break;
  955. }
  956. if(value && strlen(value)) {
  957. result = _sasl_strdup(value, &str, NULL);
  958. if(result != SASL_OK) MEMERROR(conn);
  959. } else {
  960. PARAMERROR(conn);
  961. }
  962. if(((sasl_server_conn_t *)conn)->user_realm)
  963. sasl_FREE(((sasl_server_conn_t *)conn)->user_realm);
  964. ((sasl_server_conn_t *)conn)->user_realm = str;
  965. ((sasl_server_conn_t *)conn)->sparams->user_realm = str;
  966. break;
  967. case SASL_SEC_PROPS:
  968. {
  969. sasl_security_properties_t *props = (sasl_security_properties_t *)value;
  970. if(props->maxbufsize == 0 && props->min_ssf != 0) {
  971. sasl_seterror(conn, 0,
  972. "Attempt to disable security layers (maxoutbuf == 0) with min_ssf > 0");
  973. RETURN(conn, SASL_TOOWEAK);
  974. }
  975. conn->props = *props;
  976. if(conn->type == SASL_CONN_SERVER) {
  977. ((sasl_server_conn_t*)conn)->sparams->props = *props;
  978. } else {
  979. ((sasl_client_conn_t*)conn)->cparams->props = *props;
  980. }
  981. break;
  982. }
  983. case SASL_IPREMOTEPORT:
  984. {
  985. const char *ipremoteport = (const char *)value;
  986. if(!value) {
  987. conn->got_ip_remote = 0;
  988. } else if (_sasl_ipfromstring(ipremoteport, NULL, 0)
  989. != SASL_OK) {
  990. sasl_seterror(conn, 0, "Bad IPREMOTEPORT value");
  991. RETURN(conn, SASL_BADPARAM);
  992. } else {
  993. strcpy(conn->ipremoteport, ipremoteport);
  994. conn->got_ip_remote = 1;
  995. }
  996. if(conn->got_ip_remote) {
  997. if(conn->type == SASL_CONN_CLIENT) {
  998. ((sasl_client_conn_t *)conn)->cparams->ipremoteport
  999. = conn->ipremoteport;
  1000. ((sasl_client_conn_t *)conn)->cparams->ipremlen =
  1001. (unsigned) strlen(conn->ipremoteport);
  1002. } else if (conn->type == SASL_CONN_SERVER) {
  1003. ((sasl_server_conn_t *)conn)->sparams->ipremoteport
  1004. = conn->ipremoteport;
  1005. ((sasl_server_conn_t *)conn)->sparams->ipremlen =
  1006. (unsigned) strlen(conn->ipremoteport);
  1007. }
  1008. } else {
  1009. if(conn->type == SASL_CONN_CLIENT) {
  1010. ((sasl_client_conn_t *)conn)->cparams->ipremoteport
  1011. = NULL;
  1012. ((sasl_client_conn_t *)conn)->cparams->ipremlen = 0;
  1013. } else if (conn->type == SASL_CONN_SERVER) {
  1014. ((sasl_server_conn_t *)conn)->sparams->ipremoteport
  1015. = NULL;
  1016. ((sasl_server_conn_t *)conn)->sparams->ipremlen = 0;
  1017. }
  1018. }
  1019. break;
  1020. }
  1021. case SASL_IPLOCALPORT:
  1022. {
  1023. const char *iplocalport = (const char *)value;
  1024. if(!value) {
  1025. conn->got_ip_local = 0;
  1026. } else if (_sasl_ipfromstring(iplocalport, NULL, 0)
  1027. != SASL_OK) {
  1028. sasl_seterror(conn, 0, "Bad IPLOCALPORT value");
  1029. RETURN(conn, SASL_BADPARAM);
  1030. } else {
  1031. strcpy(conn->iplocalport, iplocalport);
  1032. conn->got_ip_local = 1;
  1033. }
  1034. if(conn->got_ip_local) {
  1035. if(conn->type == SASL_CONN_CLIENT) {
  1036. ((sasl_client_conn_t *)conn)->cparams->iplocalport
  1037. = conn->iplocalport;
  1038. ((sasl_client_conn_t *)conn)->cparams->iploclen
  1039. = (unsigned) strlen(conn->iplocalport);
  1040. } else if (conn->type == SASL_CONN_SERVER) {
  1041. ((sasl_server_conn_t *)conn)->sparams->iplocalport
  1042. = conn->iplocalport;
  1043. ((sasl_server_conn_t *)conn)->sparams->iploclen
  1044. = (unsigned) strlen(conn->iplocalport);
  1045. }
  1046. } else {
  1047. if(conn->type == SASL_CONN_CLIENT) {
  1048. ((sasl_client_conn_t *)conn)->cparams->iplocalport
  1049. = NULL;
  1050. ((sasl_client_conn_t *)conn)->cparams->iploclen = 0;
  1051. } else if (conn->type == SASL_CONN_SERVER) {
  1052. ((sasl_server_conn_t *)conn)->sparams->iplocalport
  1053. = NULL;
  1054. ((sasl_server_conn_t *)conn)->sparams->iploclen = 0;
  1055. }
  1056. }
  1057. break;
  1058. }
  1059. case SASL_APPNAME:
  1060. /* Currently we only support server side contexts, but we should
  1061. be able to extend this to support client side contexts as well */
  1062. if(conn->type != SASL_CONN_SERVER) {
  1063. sasl_seterror(conn, 0, "Tried to set application name on non-server connection");
  1064. result = SASL_BADPROT;
  1065. break;
  1066. }
  1067. if(((sasl_server_conn_t *)conn)->appname) {
  1068. sasl_FREE(((sasl_server_conn_t *)conn)->appname);
  1069. ((sasl_server_conn_t *)conn)->appname = NULL;
  1070. }
  1071. if(value && strlen(value)) {
  1072. result = _sasl_strdup(value,
  1073. &(((sasl_server_conn_t *)conn)->appname),
  1074. NULL);
  1075. if(result != SASL_OK) MEMERROR(conn);
  1076. ((sasl_server_conn_t *)conn)->sparams->appname =
  1077. ((sasl_server_conn_t *)conn)->appname;
  1078. ((sasl_server_conn_t *)conn)->sparams->applen =
  1079. (unsigned) strlen(((sasl_server_conn_t *)conn)->appname);
  1080. } else {
  1081. ((sasl_server_conn_t *)conn)->sparams->appname = NULL;
  1082. ((sasl_server_conn_t *)conn)->sparams->applen = 0;
  1083. }
  1084. break;
  1085. case SASL_GSS_CREDS:
  1086. if(conn->type == SASL_CONN_CLIENT)
  1087. ((sasl_client_conn_t *)conn)->cparams->gss_creds = value;
  1088. else
  1089. ((sasl_server_conn_t *)conn)->sparams->gss_creds = value;
  1090. break;
  1091. case SASL_CHANNEL_BINDING: {
  1092. const struct sasl_channel_binding *cb = (const struct sasl_channel_binding *)value;
  1093. if (conn->type == SASL_CONN_SERVER)
  1094. ((sasl_server_conn_t *)conn)->sparams->cbinding = cb;
  1095. else
  1096. ((sasl_client_conn_t *)conn)->cparams->cbinding = cb;
  1097. break;
  1098. }
  1099. case SASL_HTTP_REQUEST: {
  1100. const sasl_http_request_t *req = (const sasl_http_request_t *)value;
  1101. if (conn->type == SASL_CONN_SERVER)
  1102. ((sasl_server_conn_t *)conn)->sparams->http_request = req;
  1103. else
  1104. ((sasl_client_conn_t *)conn)->cparams->http_request = req;
  1105. break;
  1106. }
  1107. default:
  1108. sasl_seterror(conn, 0, "Unknown parameter type");
  1109. result = SASL_BADPARAM;
  1110. }
  1111. RETURN(conn, result);
  1112. }
  1113. /* this is apparently no longer a user function */
  1114. static int sasl_usererr(int saslerr)
  1115. {
  1116. /* Hide the difference in a username failure and a password failure */
  1117. if (saslerr == SASL_NOUSER)
  1118. return SASL_BADAUTH;
  1119. /* otherwise return the error given; no transform necessary */
  1120. return saslerr;
  1121. }
  1122. const char *sasl_errstring(int saslerr,
  1123. const char *langlist __attribute__((unused)),
  1124. const char **outlang)
  1125. {
  1126. if (outlang) *outlang="en-us";
  1127. switch(saslerr)
  1128. {
  1129. case SASL_CONTINUE: return "another step is needed in authentication";
  1130. case SASL_OK: return "successful result";
  1131. case SASL_FAIL: return "generic failure";
  1132. case SASL_NOMEM: return "no memory available";
  1133. case SASL_BUFOVER: return "overflowed buffer";
  1134. case SASL_NOMECH: return "no mechanism available";
  1135. case SASL_BADPROT: return "bad protocol / cancel";
  1136. case SASL_NOTDONE: return "can't request information until later in exchange";
  1137. case SASL_BADPARAM: return "invalid parameter supplied";
  1138. case SASL_TRYAGAIN: return "transient failure (e.g., weak key)";
  1139. case SASL_BADMAC: return "integrity check failed";
  1140. case SASL_NOTINIT: return "SASL library is not initialized";
  1141. /* -- client only codes -- */
  1142. case SASL_INTERACT: return "needs user interaction";
  1143. case SASL_BADSERV: return "server failed mutual authentication step";
  1144. case SASL_WRONGMECH: return "mechanism doesn't support requested feature";
  1145. /* -- server only codes -- */
  1146. case SASL_BADAUTH: return "authentication failure";
  1147. case SASL_NOAUTHZ: return "authorization failure";
  1148. case SASL_TOOWEAK: return "mechanism too weak for this user";
  1149. case SASL_ENCRYPT: return "encryption needed to use mechanism";
  1150. case SASL_TRANS: return "One time use of a plaintext password will enable requested mechanism for user";
  1151. case SASL_EXPIRED: return "passphrase expired, has to be reset";
  1152. case SASL_DISABLED: return "account disabled";
  1153. case SASL_NOUSER: return "user not found";
  1154. case SASL_BADVERS: return "version mismatch with plug-in";
  1155. case SASL_UNAVAIL: return "remote authentication server unavailable";
  1156. case SASL_NOVERIFY: return "user exists, but no verifier for user";
  1157. case SASL_PWLOCK: return "passphrase locked";
  1158. case SASL_NOCHANGE: return "requested change was not needed";
  1159. case SASL_WEAKPASS: return "passphrase is too weak for security policy";
  1160. case SASL_NOUSERPASS: return "user supplied passwords are not permitted";
  1161. case SASL_NEED_OLD_PASSWD: return "sasl_setpass needs old password in order "
  1162. "to perform password change";
  1163. case SASL_CONSTRAINT_VIOLAT: return "sasl_setpass can't store a property because "
  1164. "of a constraint violation";
  1165. case SASL_BADBINDING: return "channel binding failure";
  1166. case SASL_CONFIGERR: return "error when parsing configuration file";
  1167. default: return "undefined error!";
  1168. }
  1169. }
  1170. /* Return the sanitized error detail about the last error that occured for
  1171. * a connection */
  1172. const char *sasl_errdetail(sasl_conn_t *conn)
  1173. {
  1174. unsigned need_len;
  1175. const char *errstr;
  1176. char leader[128];
  1177. if(!conn) return NULL;
  1178. errstr = sasl_errstring(conn->error_code, NULL, NULL);
  1179. snprintf(leader,128,"SASL(%d): %s: ",
  1180. sasl_usererr(conn->error_code), errstr);
  1181. need_len = (unsigned) (strlen(leader) + strlen(conn->error_buf) + 12);
  1182. if (_buf_alloc(&conn->errdetail_buf, &conn->errdetail_buf_len, need_len) != SASL_OK) {
  1183. return NULL;
  1184. }
  1185. snprintf(conn->errdetail_buf, need_len, "%s%s", leader, conn->error_buf);
  1186. return conn->errdetail_buf;
  1187. }
  1188. /* Note that this needs the global callbacks, so if you don't give getcallbacks
  1189. * a sasl_conn_t, you're going to need to pass it yourself (or else we couldn't
  1190. * have client and server at the same time */
  1191. static int _sasl_global_getopt(void *context,
  1192. const char *plugin_name,
  1193. const char *option,
  1194. const char ** result,
  1195. unsigned *len)
  1196. {
  1197. const sasl_global_callbacks_t * global_callbacks;
  1198. const sasl_callback_t *callback;
  1199. global_callbacks = (const sasl_global_callbacks_t *) context;
  1200. if (global_callbacks && global_callbacks->callbacks) {
  1201. for (callback = global_callbacks->callbacks;
  1202. callback->id != SASL_CB_LIST_END;
  1203. callback++) {
  1204. if (callback->id == SASL_CB_GETOPT) {
  1205. if (!callback->proc) return SASL_FAIL;
  1206. if (((sasl_getopt_t *)(callback->proc))(callback->context,
  1207. plugin_name,
  1208. option,
  1209. result,
  1210. len)
  1211. == SASL_OK)
  1212. return SASL_OK;
  1213. }
  1214. }
  1215. }
  1216. /* look it up in our configuration file */
  1217. *result = sasl_config_getstring(option, NULL);
  1218. if (*result != NULL) {
  1219. if (len) { *len = (unsigned) strlen(*result); }
  1220. return SASL_OK;
  1221. }
  1222. return SASL_FAIL;
  1223. }
  1224. static int
  1225. _sasl_conn_getopt(void *context,
  1226. const char *plugin_name,
  1227. const char *option,
  1228. const char ** result,
  1229. unsigned *len)
  1230. {
  1231. sasl_conn_t * conn;
  1232. const sasl_callback_t *callback;
  1233. if (! context)
  1234. return SASL_BADPARAM;
  1235. conn = (sasl_conn_t *) context;
  1236. if (conn->callbacks)
  1237. for (callback = conn->callbacks;
  1238. callback->id != SASL_CB_LIST_END;
  1239. callback++)
  1240. if (callback->id == SASL_CB_GETOPT
  1241. && (((sasl_getopt_t *)(callback->proc))(callback->context,
  1242. plugin_name,
  1243. option,
  1244. result,
  1245. len)
  1246. == SASL_OK))
  1247. return SASL_OK;
  1248. /* If we made it here, we didn't find an appropriate callback
  1249. * in the connection's callback list, or the callback we did
  1250. * find didn't return SASL_OK. So we attempt to use the
  1251. * global callback for this connection... */
  1252. return _sasl_global_getopt((void *)conn->global_callbacks,
  1253. plugin_name,
  1254. option,
  1255. result,
  1256. len);
  1257. }
  1258. #ifdef HAVE_SYSLOG
  1259. /* this is the default logging */
  1260. static int _sasl_syslog(void *context,
  1261. int priority,
  1262. const char *message)
  1263. {
  1264. int syslog_priority;
  1265. sasl_server_conn_t *sconn;
  1266. if (context) {
  1267. if (((sasl_conn_t *)context)->type == SASL_CONN_SERVER) {
  1268. sconn = (sasl_server_conn_t *)context;
  1269. if (sconn->sparams->log_level < priority)
  1270. return SASL_OK;
  1271. }
  1272. }
  1273. /* set syslog priority */
  1274. switch(priority) {
  1275. case SASL_LOG_NONE:
  1276. return SASL_OK;
  1277. break;
  1278. case SASL_LOG_ERR:
  1279. syslog_priority = LOG_ERR;
  1280. break;
  1281. case SASL_LOG_WARN:
  1282. syslog_priority = LOG_WARNING;
  1283. break;
  1284. case SASL_LOG_NOTE:
  1285. case SASL_LOG_FAIL:
  1286. syslog_priority = LOG_NOTICE;
  1287. break;
  1288. case SASL_LOG_PASS:
  1289. case SASL_LOG_TRACE:
  1290. case SASL_LOG_DEBUG:
  1291. default:
  1292. syslog_priority = LOG_DEBUG;
  1293. break;
  1294. }
  1295. /* do the syslog call. Do not need to call openlog? */
  1296. syslog(syslog_priority | LOG_AUTH, "%s", message);
  1297. return SASL_OK;
  1298. }
  1299. #endif /* HAVE_SYSLOG */
  1300. static int
  1301. _sasl_getsimple(void *context,
  1302. int id,
  1303. const char ** result,
  1304. size_t *len)
  1305. {
  1306. const char *userid;
  1307. if (! context || ! result) return SASL_BADPARAM;
  1308. switch(id) {
  1309. case SASL_CB_AUTHNAME:
  1310. userid = getenv("USER");
  1311. if (userid != NULL) {
  1312. *result = userid;
  1313. if (len) *len = strlen(userid);
  1314. return SASL_OK;
  1315. }
  1316. userid = getenv("USERNAME");
  1317. if (userid != NULL) {
  1318. *result = userid;
  1319. if (len) *len = strlen(userid);
  1320. return SASL_OK;
  1321. }
  1322. #ifdef WIN32
  1323. /* for win32, try using the GetUserName standard call */
  1324. {
  1325. DWORD i;
  1326. BOOL rval;
  1327. static char sender[128];
  1328. TCHAR tsender[128];
  1329. i = sizeof(tsender) / sizeof(tsender[0]);
  1330. rval = GetUserName(tsender, &i);
  1331. if ( rval) { /* got a userid */
  1332. WideCharToMultiByte(CP_UTF8, 0, tsender, -1, sender, sizeof(sender), NULL, NULL); /* -1 ensures null-terminated utf8 */
  1333. *result = sender;
  1334. if (len) *len = strlen(sender);
  1335. return SASL_OK;
  1336. }
  1337. }
  1338. #endif /* WIN32 */
  1339. return SASL_FAIL;
  1340. default:
  1341. return SASL_BADPARAM;
  1342. }
  1343. }
  1344. static int
  1345. _sasl_getpath(void *context __attribute__((unused)),
  1346. const char ** path_dest)
  1347. {
  1348. #if !defined(WIN32)
  1349. char *path;
  1350. #endif
  1351. int res = SASL_OK;
  1352. if (! path_dest) {
  1353. return SASL_BADPARAM;
  1354. }
  1355. /* Only calculate the path once. */
  1356. if (default_plugin_path == NULL) {
  1357. #if defined(WIN32)
  1358. /* NB: On Windows platforms this value is always allocated */
  1359. default_plugin_path = _sasl_get_default_win_path(context,
  1360. SASL_PLUGIN_PATH_ATTR,
  1361. PLUGINDIR);
  1362. #else
  1363. /* NB: On Unix platforms this value is never allocated */
  1364. path = _sasl_get_default_unix_path(context,
  1365. SASL_PATH_ENV_VAR,
  1366. PLUGINDIR);
  1367. res = _sasl_strdup(path, &default_plugin_path, NULL);
  1368. #endif
  1369. }
  1370. if (res == SASL_OK) {
  1371. *path_dest = default_plugin_path;
  1372. }
  1373. return res;
  1374. }
  1375. static int
  1376. _sasl_getpath_simple(void *context __attribute__((unused)),
  1377. const char **path)
  1378. {
  1379. if (! path) {
  1380. return SASL_BADPARAM;
  1381. }
  1382. if (default_plugin_path == NULL) {
  1383. return SASL_FAIL;
  1384. }
  1385. *path = default_plugin_path;
  1386. return SASL_OK;
  1387. }
  1388. static int
  1389. _sasl_getconfpath(void *context __attribute__((unused)),
  1390. char ** path_dest)
  1391. {
  1392. #if !defined(WIN32)
  1393. char *path;
  1394. #endif
  1395. int res = SASL_OK;
  1396. if (! path_dest) {
  1397. return SASL_BADPARAM;
  1398. }
  1399. /* Only calculate the path once. */
  1400. if (default_conf_path == NULL) {
  1401. #if defined(WIN32)
  1402. /* NB: On Windows platforms this value is always allocated */
  1403. default_conf_path = _sasl_get_default_win_path(context,
  1404. SASL_CONF_PATH_ATTR,
  1405. CONFIGDIR);
  1406. #else
  1407. /* NB: On Unix platforms this value is never allocated */
  1408. path = _sasl_get_default_unix_path(context,
  1409. SASL_CONF_PATH_ENV_VAR,
  1410. CONFIGDIR);
  1411. res = _sasl_strdup(path, &default_conf_path, NULL);
  1412. #endif
  1413. }
  1414. if (res == SASL_OK) {
  1415. *path_dest = default_conf_path;
  1416. }
  1417. return res;
  1418. }
  1419. static int
  1420. _sasl_getconfpath_simple(void *context __attribute__((unused)),
  1421. const char **path)
  1422. {
  1423. if (! path) {
  1424. return SASL_BADPARAM;
  1425. }
  1426. if (default_conf_path == NULL) {
  1427. return SASL_FAIL;
  1428. }
  1429. *path = default_conf_path;
  1430. return SASL_OK;
  1431. }
  1432. static int
  1433. _sasl_verifyfile(void *context __attribute__((unused)),
  1434. char *file __attribute__((unused)),
  1435. int type __attribute__((unused)))
  1436. {
  1437. /* always say ok */
  1438. return SASL_OK;
  1439. }
  1440. static int
  1441. _sasl_proxy_policy(sasl_conn_t *conn,
  1442. void *context __attribute__((unused)),
  1443. const char *requested_user, unsigned rlen,
  1444. const char *auth_identity, unsigned alen,
  1445. const char *def_realm __attribute__((unused)),
  1446. unsigned urlen __attribute__((unused)),
  1447. struct propctx *propctx __attribute__((unused)))
  1448. {
  1449. if (!conn)
  1450. return SASL_BADPARAM;
  1451. if (!requested_user || *requested_user == '\0')
  1452. return SASL_OK;
  1453. if (!auth_identity || !requested_user || rlen != alen ||
  1454. (memcmp(auth_identity, requested_user, rlen) != 0)) {
  1455. sasl_seterror(conn, 0,
  1456. "Requested identity not authenticated identity");
  1457. RETURN(conn, SASL_BADAUTH);
  1458. }
  1459. return SASL_OK;
  1460. }
  1461. int _sasl_getcallback(sasl_conn_t * conn,
  1462. unsigned long callbackid,
  1463. sasl_callback_ft *pproc,
  1464. void **pcontext)
  1465. {
  1466. const sasl_callback_t *callback;
  1467. if (!pproc || !pcontext)
  1468. PARAMERROR(conn);
  1469. /* Some callbacks are always provided by the library */
  1470. switch (callbackid) {
  1471. case SASL_CB_LIST_END:
  1472. /* Nothing ever gets to provide this */
  1473. INTERROR(conn, SASL_FAIL);
  1474. case SASL_CB_GETOPT:
  1475. if (conn) {
  1476. *pproc = (sasl_callback_ft)&_sasl_conn_getopt;
  1477. *pcontext = conn;
  1478. } else {
  1479. *pproc = (sasl_callback_ft)&_sasl_global_getopt;
  1480. *pcontext = NULL;
  1481. }
  1482. return SASL_OK;
  1483. }
  1484. /* If it's not always provided by the library, see if there's
  1485. * a version provided by the application for this connection... */
  1486. if (conn && conn->callbacks) {
  1487. for (callback = conn->callbacks; callback->id != SASL_CB_LIST_END;
  1488. callback++) {
  1489. if (callback->id == callbackid) {
  1490. *pproc = callback->proc;
  1491. *pcontext = callback->context;
  1492. if (callback->proc) {
  1493. return SASL_OK;
  1494. } else {
  1495. return SASL_INTERACT;
  1496. }
  1497. }
  1498. }
  1499. }
  1500. /* And, if not for this connection, see if there's one
  1501. * for all {server,client} connections... */
  1502. if (conn && conn->global_callbacks && conn->global_callbacks->callbacks) {
  1503. for (callback = conn->global_callbacks->callbacks;
  1504. callback->id != SASL_CB_LIST_END;
  1505. callback++) {
  1506. if (callback->id == callbackid) {
  1507. *pproc = callback->proc;
  1508. *pcontext = callback->context;
  1509. if (callback->proc) {
  1510. return SASL_OK;
  1511. } else {
  1512. return SASL_INTERACT;
  1513. }
  1514. }
  1515. }
  1516. }
  1517. /* Otherwise, see if the library provides a default callback. */
  1518. switch (callbackid) {
  1519. #ifdef HAVE_SYSLOG
  1520. case SASL_CB_LOG:
  1521. *pproc = (sasl_callback_ft)&_sasl_syslog;
  1522. *pcontext = conn;
  1523. return SASL_OK;
  1524. #endif /* HAVE_SYSLOG */
  1525. case SASL_CB_GETPATH:
  1526. *pproc = default_getpath_cb.proc;
  1527. *pcontext = default_getpath_cb.context;
  1528. return SASL_OK;
  1529. case SASL_CB_GETCONFPATH:
  1530. *pproc = default_getconfpath_cb.proc;
  1531. *pcontext = default_getconfpath_cb.context;
  1532. return SASL_OK;
  1533. case SASL_CB_AUTHNAME:
  1534. *pproc = (sasl_callback_ft)&_sasl_getsimple;
  1535. *pcontext = conn;
  1536. return SASL_OK;
  1537. case SASL_CB_VERIFYFILE:
  1538. *pproc = (sasl_callback_ft)&_sasl_verifyfile;
  1539. *pcontext = NULL;
  1540. return SASL_OK;
  1541. case SASL_CB_PROXY_POLICY:
  1542. *pproc = (sasl_callback_ft)&_sasl_proxy_policy;
  1543. *pcontext = NULL;
  1544. return SASL_OK;
  1545. }
  1546. /* Unable to find a callback... */
  1547. *pproc = NULL;
  1548. *pcontext = NULL;
  1549. sasl_seterror(conn, SASL_NOLOG, "Unable to find a callback: %d", callbackid);
  1550. RETURN(conn,SASL_FAIL);
  1551. }
  1552. /*
  1553. * This function is typically called from a plugin.
  1554. * It creates a string from the formatting and varargs given
  1555. * and calls the logging callback (syslog by default)
  1556. *
  1557. * %m will parse the value in the next argument as an errno string
  1558. * %z will parse the next argument as a SASL error code.
  1559. */
  1560. void
  1561. _sasl_log (sasl_conn_t *conn,
  1562. int level,
  1563. const char *fmt,
  1564. ...)
  1565. {
  1566. char *out = NULL;
  1567. size_t alloclen=100; /* current allocated length */
  1568. size_t outlen=0; /* current length of output buffer */
  1569. size_t formatlen;
  1570. size_t pos=0; /* current position in format string */
  1571. int result;
  1572. sasl_log_t *log_cb;
  1573. void *log_ctx;
  1574. int ival;
  1575. unsigned int uval;
  1576. char *cval;
  1577. va_list ap; /* varargs thing */
  1578. if(!fmt) return;
  1579. out = (char *) sasl_ALLOC(250);
  1580. if(!out) return;
  1581. formatlen = strlen(fmt);
  1582. /* See if we have a logging callback... */
  1583. result = _sasl_getcallback(conn, SASL_CB_LOG, (sasl_callback_ft *)&log_cb, &log_ctx);
  1584. if (result == SASL_OK && ! log_cb)
  1585. result = SASL_FAIL;
  1586. if (result != SASL_OK) goto done;
  1587. va_start(ap, fmt); /* start varargs */
  1588. while(pos<formatlen)
  1589. {
  1590. if (fmt[pos]!='%') /* regular character */
  1591. {
  1592. result = _buf_alloc(&out, &alloclen, outlen+1);
  1593. if (result != SASL_OK) goto done;
  1594. out[outlen]=fmt[pos];
  1595. outlen++;
  1596. pos++;
  1597. } else { /* formating thing */
  1598. int done=0;
  1599. char frmt[10];
  1600. int frmtpos=1;
  1601. char tempbuf[21];
  1602. frmt[0]='%';
  1603. pos++;
  1604. while (done==0)
  1605. {
  1606. switch(fmt[pos])
  1607. {
  1608. case 's': /* need to handle this */
  1609. cval = va_arg(ap, char *); /* get the next arg */
  1610. result = _sasl_add_string(&out, &alloclen,
  1611. &outlen, cval);
  1612. if (result != SASL_OK) /* add the string */
  1613. goto done;
  1614. done=1;
  1615. break;
  1616. case '%': /* double % output the '%' character */
  1617. result = _buf_alloc(&out,&alloclen,outlen+1);
  1618. if (result != SASL_OK)
  1619. goto done;
  1620. out[outlen]='%';
  1621. outlen++;
  1622. done=1;
  1623. break;
  1624. case 'm': /* insert the errno string */
  1625. result = _sasl_add_string(&out, &alloclen, &outlen,
  1626. strerror(va_arg(ap, int)));
  1627. if (result != SASL_OK)
  1628. goto done;
  1629. done=1;
  1630. break;
  1631. case 'z': /* insert the sasl error string */
  1632. result = _sasl_add_string(&out, &alloclen, &outlen,
  1633. (char *) sasl_errstring(va_arg(ap, int),NULL,NULL));
  1634. if (result != SASL_OK)
  1635. goto done;
  1636. done=1;
  1637. break;
  1638. case 'c':
  1639. frmt[frmtpos++]=fmt[pos];
  1640. frmt[frmtpos]=0;
  1641. tempbuf[0] = (char) va_arg(ap, int); /* get the next arg */
  1642. tempbuf[1]='\0';
  1643. /* now add the character */
  1644. result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
  1645. if (result != SASL_OK)
  1646. goto done;
  1647. done=1;
  1648. break;
  1649. case 'd':
  1650. case 'i':
  1651. frmt[frmtpos++]=fmt[pos];
  1652. frmt[frmtpos]=0;
  1653. ival = va_arg(ap, int); /* get the next arg */
  1654. snprintf(tempbuf,20,frmt,ival); /* have snprintf do the work */
  1655. /* now add the string */
  1656. result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
  1657. if (result != SASL_OK)
  1658. goto done;
  1659. done=1;
  1660. break;
  1661. case 'o':
  1662. case 'u':
  1663. case 'x':
  1664. case 'X':
  1665. frmt[frmtpos++]=fmt[pos];
  1666. frmt[frmtpos]=0;
  1667. uval = va_arg(ap, unsigned int); /* get the next arg */
  1668. snprintf(tempbuf,20,frmt,uval); /* have snprintf do the work */
  1669. /* now add the string */
  1670. result = _sasl_add_string(&out, &alloclen, &outlen, tempbuf);
  1671. if (result != SASL_OK)
  1672. goto done;
  1673. done=1;
  1674. break;
  1675. default:
  1676. frmt[frmtpos++]=fmt[pos]; /* add to the formating */
  1677. frmt[frmtpos]=0;
  1678. if (frmtpos>9)
  1679. done=1;
  1680. }
  1681. pos++;
  1682. if (pos>formatlen)
  1683. done=1;
  1684. }
  1685. }
  1686. }
  1687. /* put 0 at end */
  1688. result = _buf_alloc(&out, &alloclen, outlen+1);
  1689. if (result != SASL_OK) goto done;
  1690. out[outlen]=0;
  1691. /* send log message */
  1692. result = log_cb(log_ctx, level, out);
  1693. done:
  1694. va_end(ap);
  1695. if(out) sasl_FREE(out);
  1696. }
  1697. /* Allocate and Init a sasl_utils_t structure */
  1698. sasl_utils_t *
  1699. _sasl_alloc_utils(sasl_conn_t *conn,
  1700. sasl_global_callbacks_t *global_callbacks)
  1701. {
  1702. sasl_utils_t *utils;
  1703. /* set util functions - need to do rest*/
  1704. utils=sasl_ALLOC(sizeof(sasl_utils_t));
  1705. if (utils==NULL)
  1706. return NULL;
  1707. utils->conn = conn;
  1708. sasl_randcreate(&utils->rpool);
  1709. if (conn) {
  1710. utils->getopt = &_sasl_conn_getopt;
  1711. utils->getopt_context = conn;
  1712. } else {
  1713. utils->getopt = &_sasl_global_getopt;
  1714. utils->getopt_context = global_callbacks;
  1715. }
  1716. utils->malloc=_sasl_allocation_utils.malloc;
  1717. utils->calloc=_sasl_allocation_utils.calloc;
  1718. utils->realloc=_sasl_allocation_utils.realloc;
  1719. utils->free=_sasl_allocation_utils.free;
  1720. utils->mutex_alloc = _sasl_mutex_utils.alloc;
  1721. utils->mutex_lock = _sasl_mutex_utils.lock;
  1722. utils->mutex_unlock = _sasl_mutex_utils.unlock;
  1723. utils->mutex_free = _sasl_mutex_utils.free;
  1724. utils->MD5Init = &_sasl_MD5Init;
  1725. utils->MD5Update= &_sasl_MD5Update;
  1726. utils->MD5Final = &_sasl_MD5Final;
  1727. utils->hmac_md5 = &_sasl_hmac_md5;
  1728. utils->hmac_md5_init = &_sasl_hmac_md5_init;
  1729. utils->hmac_md5_final = &_sasl_hmac_md5_final;
  1730. utils->hmac_md5_precalc = &_sasl_hmac_md5_precalc;
  1731. utils->hmac_md5_import = &_sasl_hmac_md5_import;
  1732. utils->mkchal = &sasl_mkchal;
  1733. utils->utf8verify = &sasl_utf8verify;
  1734. utils->rand=&sasl_rand;
  1735. utils->churn=&sasl_churn;
  1736. utils->checkpass=NULL;
  1737. utils->encode64=&sasl_encode64;
  1738. utils->decode64=&sasl_decode64;
  1739. utils->erasebuffer=&sasl_erasebuffer;
  1740. utils->getprop=&sasl_getprop;
  1741. utils->setprop=&sasl_setprop;
  1742. utils->getcallback=&_sasl_getcallback;
  1743. utils->log=&_sasl_log;
  1744. utils->seterror=&sasl_seterror;
  1745. #ifndef macintosh
  1746. /* Aux Property Utilities */
  1747. utils->prop_new=&prop_new;
  1748. utils->prop_dup=&prop_dup;
  1749. utils->prop_request=&prop_request;
  1750. utils->prop_get=&prop_get;
  1751. utils->prop_getnames=&prop_getnames;
  1752. utils->prop_clear=&prop_clear;
  1753. utils->prop_dispose=&prop_dispose;
  1754. utils->prop_format=&prop_format;
  1755. utils->prop_set=&prop_set;
  1756. utils->prop_setvals=&prop_setvals;
  1757. utils->prop_erase=&prop_erase;
  1758. utils->auxprop_store=&sasl_auxprop_store;
  1759. #endif
  1760. /* Spares */
  1761. utils->spare_fptr = NULL;
  1762. utils->spare_fptr1 = utils->spare_fptr2 = NULL;
  1763. return utils;
  1764. }
  1765. int
  1766. _sasl_free_utils(const sasl_utils_t ** utils)
  1767. {
  1768. sasl_utils_t *nonconst;
  1769. if(!utils) return SASL_BADPARAM;
  1770. if(!*utils) return SASL_OK;
  1771. /* I wish we could avoid this cast, it's pretty gratuitous but it
  1772. * does make life easier to have it const everywhere else. */
  1773. nonconst = (sasl_utils_t *)(*utils);
  1774. sasl_randfree(&(nonconst->rpool));
  1775. sasl_FREE(nonconst);
  1776. *utils = NULL;
  1777. return SASL_OK;
  1778. }
  1779. int sasl_idle(sasl_conn_t *conn)
  1780. {
  1781. if (! conn) {
  1782. if (_sasl_server_idle_hook
  1783. && _sasl_server_idle_hook(NULL))
  1784. return 1;
  1785. if (_sasl_client_idle_hook
  1786. && _sasl_client_idle_hook(NULL))
  1787. return 1;
  1788. return 0;
  1789. }
  1790. if (conn->idle_hook)
  1791. return conn->idle_hook(conn);
  1792. return 0;
  1793. }
  1794. static const sasl_callback_t *
  1795. _sasl_find_callback_by_type (const sasl_callback_t *callbacks,
  1796. unsigned long id)
  1797. {
  1798. if (callbacks) {
  1799. while (callbacks->id != SASL_CB_LIST_END) {
  1800. if (callbacks->id == id) {
  1801. return callbacks;
  1802. } else {
  1803. ++callbacks;
  1804. }
  1805. }
  1806. }
  1807. return NULL;
  1808. }
  1809. const sasl_callback_t *
  1810. _sasl_find_getpath_callback(const sasl_callback_t *callbacks)
  1811. {
  1812. callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETPATH);
  1813. if (callbacks != NULL) {
  1814. return callbacks;
  1815. } else {
  1816. return &default_getpath_cb;
  1817. }
  1818. }
  1819. const sasl_callback_t *
  1820. _sasl_find_getconfpath_callback(const sasl_callback_t *callbacks)
  1821. {
  1822. callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_GETCONFPATH);
  1823. if (callbacks != NULL) {
  1824. return callbacks;
  1825. } else {
  1826. return &default_getconfpath_cb;
  1827. }
  1828. }
  1829. const sasl_callback_t *
  1830. _sasl_find_verifyfile_callback(const sasl_callback_t *callbacks)
  1831. {
  1832. static const sasl_callback_t default_verifyfile_cb = {
  1833. SASL_CB_VERIFYFILE,
  1834. (sasl_callback_ft)&_sasl_verifyfile,
  1835. NULL
  1836. };
  1837. callbacks = _sasl_find_callback_by_type (callbacks, SASL_CB_VERIFYFILE);
  1838. if (callbacks != NULL) {
  1839. return callbacks;
  1840. } else {
  1841. return &default_verifyfile_cb;
  1842. }
  1843. }
  1844. /* Basically a conditional call to realloc(), if we need more */
  1845. int _buf_alloc(char **rwbuf, size_t *curlen, size_t newlen)
  1846. {
  1847. if(!(*rwbuf)) {
  1848. *rwbuf = sasl_ALLOC((unsigned)newlen);
  1849. if (*rwbuf == NULL) {
  1850. *curlen = 0;
  1851. return SASL_NOMEM;
  1852. }
  1853. *curlen = newlen;
  1854. } else if(*rwbuf && *curlen < newlen) {
  1855. size_t needed = 2*(*curlen);
  1856. while(needed < newlen)
  1857. needed *= 2;
  1858. /* WARN - We will leak the old buffer on failure */
  1859. *rwbuf = sasl_REALLOC(*rwbuf, (unsigned)needed);
  1860. if (*rwbuf == NULL) {
  1861. *curlen = 0;
  1862. return SASL_NOMEM;
  1863. }
  1864. *curlen = needed;
  1865. }
  1866. return SASL_OK;
  1867. }
  1868. /* for the mac os x cfm glue: this lets the calling function
  1869. get pointers to the error buffer without having to touch the sasl_conn_t struct */
  1870. void _sasl_get_errorbuf(sasl_conn_t *conn, char ***bufhdl, size_t **lenhdl)
  1871. {
  1872. *bufhdl = &conn->error_buf;
  1873. *lenhdl = &conn->error_buf_len;
  1874. }
  1875. /* convert an iovec to a single buffer */
  1876. int _iovec_to_buf(const struct iovec *vec,
  1877. unsigned numiov, buffer_info_t **output)
  1878. {
  1879. unsigned i;
  1880. int ret;
  1881. buffer_info_t *out;
  1882. char *pos;
  1883. if (!vec || !output) return SASL_BADPARAM;
  1884. if (!(*output)) {
  1885. *output = sasl_ALLOC(sizeof(buffer_info_t));
  1886. if (!*output) return SASL_NOMEM;
  1887. memset(*output,0,sizeof(buffer_info_t));
  1888. }
  1889. out = *output;
  1890. out->curlen = 0;
  1891. for (i = 0; i < numiov; i++) {
  1892. out->curlen += vec[i].iov_len;
  1893. }
  1894. ret = _buf_alloc(&out->data, &out->reallen, out->curlen);
  1895. if (ret != SASL_OK) return SASL_NOMEM;
  1896. memset(out->data, 0, out->reallen);
  1897. pos = out->data;
  1898. for (i = 0; i < numiov; i++) {
  1899. memcpy(pos, vec[i].iov_base, vec[i].iov_len);
  1900. pos += vec[i].iov_len;
  1901. }
  1902. return SASL_OK;
  1903. }
  1904. /* This code might be useful in the future, but it isn't now, so.... */
  1905. #if 0
  1906. int _sasl_iptostring(const struct sockaddr *addr, socklen_t addrlen,
  1907. char *out, unsigned outlen) {
  1908. char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV];
  1909. int niflags;
  1910. if(!addr || !out) return SASL_BADPARAM;
  1911. niflags = (NI_NUMERICHOST | NI_NUMERICSERV);
  1912. #ifdef NI_WITHSCOPEID
  1913. if (addr->sa_family == AF_INET6)
  1914. niflags |= NI_WITHSCOPEID;
  1915. #endif
  1916. if (getnameinfo(addr, addrlen, hbuf, sizeof(hbuf), pbuf, sizeof(pbuf),
  1917. niflags) != 0)
  1918. return SASL_BADPARAM;
  1919. if(outlen < strlen(hbuf) + strlen(pbuf) + 2)
  1920. return SASL_BUFOVER;
  1921. snprintf(out, outlen, "%s;%s", hbuf, pbuf);
  1922. return SASL_OK;
  1923. }
  1924. #endif
  1925. int _sasl_ipfromstring(const char *addr,
  1926. struct sockaddr *out, socklen_t outlen)
  1927. {
  1928. int i, j;
  1929. struct addrinfo hints, *ai = NULL;
  1930. char hbuf[NI_MAXHOST];
  1931. /* A NULL out pointer just implies we don't do a copy, just verify it */
  1932. if(!addr) return SASL_BADPARAM;
  1933. /* Parse the address */
  1934. for (i = 0; addr[i] != '\0' && addr[i] != ';'; i++) {
  1935. if (i >= NI_MAXHOST)
  1936. return SASL_BADPARAM;
  1937. hbuf[i] = addr[i];
  1938. }
  1939. hbuf[i] = '\0';
  1940. if (addr[i] == ';')
  1941. i++;
  1942. /* XXX: Do we need this check? */
  1943. for (j = i; addr[j] != '\0'; j++)
  1944. if (!isdigit((int)(addr[j])))
  1945. return SASL_BADPARAM;
  1946. memset(&hints, 0, sizeof(hints));
  1947. hints.ai_family = PF_UNSPEC;
  1948. hints.ai_socktype = SOCK_STREAM;
  1949. hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
  1950. if (getaddrinfo(hbuf, &addr[i], &hints, &ai) != 0)
  1951. return SASL_BADPARAM;
  1952. if (out) {
  1953. if (outlen < (socklen_t)ai->ai_addrlen) {
  1954. freeaddrinfo(ai);
  1955. return SASL_BUFOVER;
  1956. }
  1957. memcpy(out, ai->ai_addr, ai->ai_addrlen);
  1958. }
  1959. freeaddrinfo(ai);
  1960. return SASL_OK;
  1961. }
  1962. int _sasl_build_mechlist(void)
  1963. {
  1964. int count = 0;
  1965. sasl_string_list_t *clist = NULL, *slist = NULL, *olist = NULL;
  1966. sasl_string_list_t *p, *q, **last, *p_next;
  1967. clist = _sasl_client_mechs();
  1968. slist = _sasl_server_mechs();
  1969. if(!clist) {
  1970. olist = slist;
  1971. } else {
  1972. int flag;
  1973. /* append slist to clist, and set olist to clist */
  1974. for(p = slist; p; p = p_next) {
  1975. flag = 0;
  1976. p_next = p->next;
  1977. last = &clist;
  1978. for(q = clist; q; q = q->next) {
  1979. if(!strcmp(q->d, p->d)) {
  1980. /* They match, set the flag */
  1981. flag = 1;
  1982. break;
  1983. }
  1984. last = &(q->next);
  1985. }
  1986. if(!flag) {
  1987. *last = p;
  1988. p->next = NULL;
  1989. } else {
  1990. sasl_FREE(p);
  1991. }
  1992. }
  1993. olist = clist;
  1994. }
  1995. if(!olist) {
  1996. /* This is not going to be very useful */
  1997. printf ("no olist");
  1998. return SASL_FAIL;
  1999. }
  2000. for (p = olist; p; p = p->next) count++;
  2001. if(global_mech_list) {
  2002. sasl_FREE(global_mech_list);
  2003. global_mech_list = NULL;
  2004. }
  2005. global_mech_list = sasl_ALLOC((count + 1) * sizeof(char *));
  2006. if(!global_mech_list) return SASL_NOMEM;
  2007. memset(global_mech_list, 0, (count + 1) * sizeof(char *));
  2008. count = 0;
  2009. for (p = olist; p; p = p_next) {
  2010. p_next = p->next;
  2011. global_mech_list[count++] = (char *) p->d;
  2012. sasl_FREE(p);
  2013. }
  2014. return SASL_OK;
  2015. }
  2016. const char ** sasl_global_listmech(void)
  2017. {
  2018. return (const char **)global_mech_list;
  2019. }
  2020. int sasl_listmech(sasl_conn_t *conn,
  2021. const char *user,
  2022. const char *prefix,
  2023. const char *sep,
  2024. const char *suffix,
  2025. const char **result,
  2026. unsigned *plen,
  2027. int *pcount)
  2028. {
  2029. if(!conn) {
  2030. return SASL_BADPARAM;
  2031. } else if(conn->type == SASL_CONN_SERVER) {
  2032. RETURN(conn, _sasl_server_listmech(conn, user, prefix, sep, suffix,
  2033. result, plen, pcount));
  2034. } else if (conn->type == SASL_CONN_CLIENT) {
  2035. RETURN(conn, _sasl_client_listmech(conn, prefix, sep, suffix,
  2036. result, plen, pcount));
  2037. }
  2038. PARAMERROR(conn);
  2039. }
  2040. int _sasl_is_equal_mech(const char *req_mech,
  2041. const char *plug_mech,
  2042. size_t req_mech_len,
  2043. int *plus)
  2044. {
  2045. size_t n;
  2046. if (req_mech_len > 5 &&
  2047. strcasecmp(&req_mech[req_mech_len - 5], "-PLUS") == 0) {
  2048. n = req_mech_len - 5;
  2049. *plus = 1;
  2050. } else {
  2051. n = req_mech_len;
  2052. *plus = 0;
  2053. }
  2054. if (n < strlen(plug_mech)) {
  2055. /* Don't allow arbitrary prefix match */
  2056. return 0;
  2057. }
  2058. return (strncasecmp(req_mech, plug_mech, n) == 0);
  2059. }
  2060. #ifndef WIN32
  2061. static char *
  2062. _sasl_get_default_unix_path(void *context __attribute__((unused)),
  2063. char * env_var_name,
  2064. char * default_value)
  2065. {
  2066. char *path = NULL;
  2067. /* Honor external variable only in a safe environment */
  2068. if (getuid() == geteuid() && getgid() == getegid()) {
  2069. path = getenv(env_var_name);
  2070. }
  2071. if (! path) {
  2072. path = default_value;
  2073. }
  2074. return path;
  2075. }
  2076. #else /*WIN32*/
  2077. /* Return NULL on failure */
  2078. static char *
  2079. _sasl_get_default_win_path(void *context __attribute__((unused)),
  2080. TCHAR * reg_attr_name,
  2081. char * default_value)
  2082. {
  2083. /* Open registry entry, and find all registered SASL libraries.
  2084. *
  2085. * Registry location:
  2086. *
  2087. * SOFTWARE\\Carnegie Mellon\\Project Cyrus\\SASL Library
  2088. *
  2089. * Key - value:
  2090. *
  2091. * "SearchPath" - value: PATH like (';' delimited) list
  2092. * of directories where to search for plugins
  2093. * The list may contain references to environment
  2094. * variables (e.g. %PATH%).
  2095. *
  2096. */
  2097. HKEY hKey;
  2098. DWORD ret;
  2099. DWORD ValueType; /* value type */
  2100. DWORD cbData; /* value size in bytes and later number of wchars */
  2101. TCHAR * ValueData; /* value */
  2102. DWORD cbExpandedData; /* "expanded" value size in wchars */
  2103. TCHAR * ExpandedValueData; /* "expanded" value */
  2104. TCHAR * return_value; /* function return value */
  2105. TCHAR * tmp;
  2106. /* Initialization */
  2107. ExpandedValueData = NULL;
  2108. ValueData = NULL;
  2109. return_value = NULL;
  2110. /* Open the registry */
  2111. ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  2112. SASL_ROOT_KEY,
  2113. 0,
  2114. KEY_READ,
  2115. &hKey);
  2116. if (ret != ERROR_SUCCESS) {
  2117. /* no registry entry */
  2118. char *ret;
  2119. (void) _sasl_strdup (default_value, &ret, NULL);
  2120. return ret;
  2121. }
  2122. /* figure out value type and required buffer size */
  2123. /* the size will include space for terminating NUL if required */
  2124. RegQueryValueEx (hKey,
  2125. reg_attr_name,
  2126. NULL, /* reserved */
  2127. &ValueType,
  2128. NULL,
  2129. &cbData);
  2130. /* Only accept string related types */
  2131. if (ValueType != REG_EXPAND_SZ &&
  2132. ValueType != REG_MULTI_SZ &&
  2133. ValueType != REG_SZ) {
  2134. return_value = NULL;
  2135. goto CLEANUP;
  2136. }
  2137. /* Any high water mark? */
  2138. ValueData = sasl_ALLOC(cbData + 2 * sizeof(TCHAR)); /* extra bytes to insert null-terminator if it's missed */
  2139. if (ValueData == NULL) {
  2140. return_value = NULL;
  2141. goto CLEANUP;
  2142. };
  2143. if (RegQueryValueEx(hKey,
  2144. reg_attr_name,
  2145. NULL, /* reserved */
  2146. &ValueType,
  2147. (LPBYTE)ValueData,
  2148. &cbData) != ERROR_SUCCESS) {
  2149. return_value = NULL;
  2150. goto CLEANUP;
  2151. }
  2152. cbData /= sizeof(TCHAR); /* covert to number of symbols */
  2153. ValueData[cbData] = '\0'; /* MS docs say we have to to that */
  2154. ValueData[cbData + 1] = '\0'; /* for MULTI */
  2155. switch (ValueType) {
  2156. case REG_EXPAND_SZ:
  2157. /* : A random starting guess */
  2158. cbExpandedData = cbData + 1024;
  2159. ExpandedValueData = (TCHAR*)sasl_ALLOC(cbExpandedData * sizeof(TCHAR));
  2160. if (ExpandedValueData == NULL) {
  2161. return_value = NULL;
  2162. goto CLEANUP;
  2163. };
  2164. cbExpandedData = ExpandEnvironmentStrings(
  2165. ValueData,
  2166. ExpandedValueData,
  2167. cbExpandedData);
  2168. if (cbExpandedData == 0) {
  2169. /* : GetLastError() contains the reason for failure */
  2170. return_value = NULL;
  2171. goto CLEANUP;
  2172. }
  2173. /* : Must retry expansion with the bigger buffer */
  2174. if (cbExpandedData > cbData + 1024) {
  2175. /* : Memory leak here if can't realloc */
  2176. ExpandedValueData = sasl_REALLOC(ExpandedValueData, cbExpandedData * sizeof(TCHAR));
  2177. if (ExpandedValueData == NULL) {
  2178. return_value = NULL;
  2179. goto CLEANUP;
  2180. };
  2181. cbExpandedData = ExpandEnvironmentStrings(
  2182. ValueData,
  2183. ExpandedValueData,
  2184. cbExpandedData);
  2185. /* : This should not happen */
  2186. if (cbExpandedData == 0) {
  2187. /* : GetLastError() contains the reason for failure */
  2188. return_value = NULL;
  2189. goto CLEANUP;
  2190. }
  2191. }
  2192. sasl_FREE(ValueData);
  2193. ValueData = ExpandedValueData;
  2194. /* : This is to prevent automatical freeing of this block on cleanup */
  2195. ExpandedValueData = NULL;
  2196. break;
  2197. case REG_MULTI_SZ:
  2198. tmp = ValueData;
  2199. /* : We shouldn't overflow here, as the buffer is guarantied
  2200. : to contain at least two consequent NULs */
  2201. while (1) {
  2202. if (tmp[0] == '\0') {
  2203. /* : Stop the process if we found the end of the string (two consequent NULs) */
  2204. if (tmp[1] == '\0') {
  2205. break;
  2206. }
  2207. /* : Replace delimiting NUL with our delimiter characted */
  2208. tmp[0] = PATHS_DELIMITER;
  2209. }
  2210. tmp += (_tcslen(tmp));
  2211. }
  2212. break;
  2213. case REG_SZ:
  2214. /* Do nothing, it is good as is */
  2215. break;
  2216. default:
  2217. return_value = NULL;
  2218. goto CLEANUP;
  2219. }
  2220. return_value = ValueData; /* just to flag we have a result */
  2221. CLEANUP:
  2222. RegCloseKey(hKey);
  2223. if (ExpandedValueData != NULL) sasl_FREE(ExpandedValueData);
  2224. if (return_value == NULL) {
  2225. if (ValueData != NULL) sasl_FREE(ValueData);
  2226. return NULL;
  2227. }
  2228. if (sizeof(TCHAR) == sizeof(char)) {
  2229. return (char*)return_value;
  2230. }
  2231. /* convert to utf-8 for compatibility with other OS' */
  2232. {
  2233. char *tmp = _sasl_wchar_to_utf8(return_value);
  2234. sasl_FREE(return_value);
  2235. return tmp;
  2236. }
  2237. }
  2238. char* _sasl_wchar_to_utf8(WCHAR *str)
  2239. {
  2240. size_t bufLen = WideCharToMultiByte(CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL);
  2241. char *buf = sasl_ALLOC(bufLen);
  2242. if (buf) {
  2243. if (WideCharToMultiByte(CP_UTF8, 0, str, -1, buf, bufLen, NULL, NULL) == 0) { /* -1 ensures null-terminated utf8 */
  2244. sasl_FREE(buf);
  2245. buf = NULL;
  2246. }
  2247. }
  2248. return buf;
  2249. }
  2250. WCHAR* _sasl_utf8_to_wchar(const char *str)
  2251. {
  2252. size_t bufLen = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
  2253. WCHAR *buf = sasl_ALLOC(bufLen * sizeof(WCHAR));
  2254. if (buf) {
  2255. if (MultiByteToWideChar(CP_UTF8, 0, str, -1, buf, bufLen) == 0) { /* -1 ensures null-terminated utf8 */
  2256. sasl_FREE(buf);
  2257. buf = NULL;
  2258. }
  2259. }
  2260. return buf;
  2261. }
  2262. #endif /*WIN32*/