/crypto/heimdal/lib/gssapi/spnego/accept_sec_context.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 917 lines · 711 code · 142 blank · 64 comment · 228 complexity · 02631e154b048c774f7125ccd0e1c580 MD5 · raw file

  1. /*
  2. * Copyright (c) 1997 - 2006 Kungliga Tekniska Hรถgskolan
  3. * (Royal Institute of Technology, Stockholm, Sweden).
  4. * Portions Copyright (c) 2004 PADL Software Pty Ltd.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. *
  13. * 2. Redistributions in binary form must reproduce the above copyright
  14. * notice, this list of conditions and the following disclaimer in the
  15. * documentation and/or other materials provided with the distribution.
  16. *
  17. * 3. Neither the name of the Institute nor the names of its contributors
  18. * may be used to endorse or promote products derived from this software
  19. * without specific prior written permission.
  20. *
  21. * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24. * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. */
  33. #include "spnego_locl.h"
  34. static OM_uint32
  35. send_reject (OM_uint32 *minor_status,
  36. gss_buffer_t output_token)
  37. {
  38. NegotiationToken nt;
  39. size_t size;
  40. nt.element = choice_NegotiationToken_negTokenResp;
  41. ALLOC(nt.u.negTokenResp.negResult, 1);
  42. if (nt.u.negTokenResp.negResult == NULL) {
  43. *minor_status = ENOMEM;
  44. return GSS_S_FAILURE;
  45. }
  46. *(nt.u.negTokenResp.negResult) = reject;
  47. nt.u.negTokenResp.supportedMech = NULL;
  48. nt.u.negTokenResp.responseToken = NULL;
  49. nt.u.negTokenResp.mechListMIC = NULL;
  50. ASN1_MALLOC_ENCODE(NegotiationToken,
  51. output_token->value, output_token->length, &nt,
  52. &size, *minor_status);
  53. free_NegotiationToken(&nt);
  54. if (*minor_status != 0)
  55. return GSS_S_FAILURE;
  56. return GSS_S_BAD_MECH;
  57. }
  58. static OM_uint32
  59. acceptor_approved(gss_name_t target_name, gss_OID mech)
  60. {
  61. gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
  62. gss_OID_set oidset;
  63. OM_uint32 junk, ret;
  64. if (target_name == GSS_C_NO_NAME)
  65. return GSS_S_COMPLETE;
  66. gss_create_empty_oid_set(&junk, &oidset);
  67. gss_add_oid_set_member(&junk, mech, &oidset);
  68. ret = gss_acquire_cred(&junk, target_name, GSS_C_INDEFINITE, oidset,
  69. GSS_C_ACCEPT, &cred, NULL, NULL);
  70. gss_release_oid_set(&junk, &oidset);
  71. if (ret != GSS_S_COMPLETE)
  72. return ret;
  73. gss_release_cred(&junk, &cred);
  74. return GSS_S_COMPLETE;
  75. }
  76. static OM_uint32
  77. send_supported_mechs (OM_uint32 *minor_status,
  78. gss_buffer_t output_token)
  79. {
  80. NegotiationTokenWin nt;
  81. size_t buf_len = 0;
  82. gss_buffer_desc data;
  83. OM_uint32 ret;
  84. memset(&nt, 0, sizeof(nt));
  85. nt.element = choice_NegotiationTokenWin_negTokenInit;
  86. nt.u.negTokenInit.reqFlags = NULL;
  87. nt.u.negTokenInit.mechToken = NULL;
  88. nt.u.negTokenInit.negHints = NULL;
  89. ret = _gss_spnego_indicate_mechtypelist(minor_status, GSS_C_NO_NAME,
  90. acceptor_approved, 1, NULL,
  91. &nt.u.negTokenInit.mechTypes, NULL);
  92. if (ret != GSS_S_COMPLETE) {
  93. return ret;
  94. }
  95. ALLOC(nt.u.negTokenInit.negHints, 1);
  96. if (nt.u.negTokenInit.negHints == NULL) {
  97. *minor_status = ENOMEM;
  98. free_NegotiationTokenWin(&nt);
  99. return GSS_S_FAILURE;
  100. }
  101. ALLOC(nt.u.negTokenInit.negHints->hintName, 1);
  102. if (nt.u.negTokenInit.negHints->hintName == NULL) {
  103. *minor_status = ENOMEM;
  104. free_NegotiationTokenWin(&nt);
  105. return GSS_S_FAILURE;
  106. }
  107. *nt.u.negTokenInit.negHints->hintName = strdup("not_defined_in_RFC4178@please_ignore");
  108. nt.u.negTokenInit.negHints->hintAddress = NULL;
  109. ASN1_MALLOC_ENCODE(NegotiationTokenWin,
  110. data.value, data.length, &nt, &buf_len, ret);
  111. free_NegotiationTokenWin(&nt);
  112. if (ret) {
  113. *minor_status = ret;
  114. return GSS_S_FAILURE;
  115. }
  116. if (data.length != buf_len) {
  117. abort();
  118. UNREACHABLE(return GSS_S_FAILURE);
  119. }
  120. ret = gss_encapsulate_token(&data, GSS_SPNEGO_MECHANISM, output_token);
  121. free (data.value);
  122. if (ret != GSS_S_COMPLETE)
  123. return ret;
  124. *minor_status = 0;
  125. return GSS_S_CONTINUE_NEEDED;
  126. }
  127. static OM_uint32
  128. send_accept (OM_uint32 *minor_status,
  129. gssspnego_ctx context_handle,
  130. gss_buffer_t mech_token,
  131. int initial_response,
  132. gss_buffer_t mech_buf,
  133. gss_buffer_t output_token)
  134. {
  135. NegotiationToken nt;
  136. OM_uint32 ret;
  137. gss_buffer_desc mech_mic_buf;
  138. size_t size;
  139. memset(&nt, 0, sizeof(nt));
  140. nt.element = choice_NegotiationToken_negTokenResp;
  141. ALLOC(nt.u.negTokenResp.negResult, 1);
  142. if (nt.u.negTokenResp.negResult == NULL) {
  143. *minor_status = ENOMEM;
  144. return GSS_S_FAILURE;
  145. }
  146. if (context_handle->open) {
  147. if (mech_token != GSS_C_NO_BUFFER
  148. && mech_token->length != 0
  149. && mech_buf != GSS_C_NO_BUFFER)
  150. *(nt.u.negTokenResp.negResult) = accept_incomplete;
  151. else
  152. *(nt.u.negTokenResp.negResult) = accept_completed;
  153. } else {
  154. if (initial_response && context_handle->require_mic)
  155. *(nt.u.negTokenResp.negResult) = request_mic;
  156. else
  157. *(nt.u.negTokenResp.negResult) = accept_incomplete;
  158. }
  159. if (initial_response) {
  160. ALLOC(nt.u.negTokenResp.supportedMech, 1);
  161. if (nt.u.negTokenResp.supportedMech == NULL) {
  162. free_NegotiationToken(&nt);
  163. *minor_status = ENOMEM;
  164. return GSS_S_FAILURE;
  165. }
  166. ret = der_get_oid(context_handle->preferred_mech_type->elements,
  167. context_handle->preferred_mech_type->length,
  168. nt.u.negTokenResp.supportedMech,
  169. NULL);
  170. if (ret) {
  171. free_NegotiationToken(&nt);
  172. *minor_status = ENOMEM;
  173. return GSS_S_FAILURE;
  174. }
  175. } else {
  176. nt.u.negTokenResp.supportedMech = NULL;
  177. }
  178. if (mech_token != GSS_C_NO_BUFFER && mech_token->length != 0) {
  179. ALLOC(nt.u.negTokenResp.responseToken, 1);
  180. if (nt.u.negTokenResp.responseToken == NULL) {
  181. free_NegotiationToken(&nt);
  182. *minor_status = ENOMEM;
  183. return GSS_S_FAILURE;
  184. }
  185. nt.u.negTokenResp.responseToken->length = mech_token->length;
  186. nt.u.negTokenResp.responseToken->data = mech_token->value;
  187. mech_token->length = 0;
  188. mech_token->value = NULL;
  189. } else {
  190. nt.u.negTokenResp.responseToken = NULL;
  191. }
  192. if (mech_buf != GSS_C_NO_BUFFER) {
  193. ret = gss_get_mic(minor_status,
  194. context_handle->negotiated_ctx_id,
  195. 0,
  196. mech_buf,
  197. &mech_mic_buf);
  198. if (ret == GSS_S_COMPLETE) {
  199. ALLOC(nt.u.negTokenResp.mechListMIC, 1);
  200. if (nt.u.negTokenResp.mechListMIC == NULL) {
  201. gss_release_buffer(minor_status, &mech_mic_buf);
  202. free_NegotiationToken(&nt);
  203. *minor_status = ENOMEM;
  204. return GSS_S_FAILURE;
  205. }
  206. nt.u.negTokenResp.mechListMIC->length = mech_mic_buf.length;
  207. nt.u.negTokenResp.mechListMIC->data = mech_mic_buf.value;
  208. } else if (ret == GSS_S_UNAVAILABLE) {
  209. nt.u.negTokenResp.mechListMIC = NULL;
  210. } else {
  211. free_NegotiationToken(&nt);
  212. return ret;
  213. }
  214. } else
  215. nt.u.negTokenResp.mechListMIC = NULL;
  216. ASN1_MALLOC_ENCODE(NegotiationToken,
  217. output_token->value, output_token->length,
  218. &nt, &size, ret);
  219. if (ret) {
  220. free_NegotiationToken(&nt);
  221. *minor_status = ret;
  222. return GSS_S_FAILURE;
  223. }
  224. /*
  225. * The response should not be encapsulated, because
  226. * it is a SubsequentContextToken (note though RFC 1964
  227. * specifies encapsulation for all _Kerberos_ tokens).
  228. */
  229. if (*(nt.u.negTokenResp.negResult) == accept_completed)
  230. ret = GSS_S_COMPLETE;
  231. else
  232. ret = GSS_S_CONTINUE_NEEDED;
  233. free_NegotiationToken(&nt);
  234. return ret;
  235. }
  236. static OM_uint32
  237. verify_mechlist_mic
  238. (OM_uint32 *minor_status,
  239. gssspnego_ctx context_handle,
  240. gss_buffer_t mech_buf,
  241. heim_octet_string *mechListMIC
  242. )
  243. {
  244. OM_uint32 ret;
  245. gss_buffer_desc mic_buf;
  246. if (context_handle->verified_mic) {
  247. /* This doesn't make sense, we've already verified it? */
  248. *minor_status = 0;
  249. return GSS_S_DUPLICATE_TOKEN;
  250. }
  251. if (mechListMIC == NULL) {
  252. *minor_status = 0;
  253. return GSS_S_DEFECTIVE_TOKEN;
  254. }
  255. mic_buf.length = mechListMIC->length;
  256. mic_buf.value = mechListMIC->data;
  257. ret = gss_verify_mic(minor_status,
  258. context_handle->negotiated_ctx_id,
  259. mech_buf,
  260. &mic_buf,
  261. NULL);
  262. if (ret != GSS_S_COMPLETE)
  263. ret = GSS_S_DEFECTIVE_TOKEN;
  264. return ret;
  265. }
  266. static OM_uint32
  267. select_mech(OM_uint32 *minor_status, MechType *mechType, int verify_p,
  268. gss_OID *mech_p)
  269. {
  270. char mechbuf[64];
  271. size_t mech_len;
  272. gss_OID_desc oid;
  273. gss_OID oidp;
  274. gss_OID_set mechs;
  275. size_t i;
  276. OM_uint32 ret, junk;
  277. ret = der_put_oid ((unsigned char *)mechbuf + sizeof(mechbuf) - 1,
  278. sizeof(mechbuf),
  279. mechType,
  280. &mech_len);
  281. if (ret) {
  282. return GSS_S_DEFECTIVE_TOKEN;
  283. }
  284. oid.length = mech_len;
  285. oid.elements = mechbuf + sizeof(mechbuf) - mech_len;
  286. if (gss_oid_equal(&oid, GSS_SPNEGO_MECHANISM)) {
  287. return GSS_S_BAD_MECH;
  288. }
  289. *minor_status = 0;
  290. /* Translate broken MS Kebreros OID */
  291. if (gss_oid_equal(&oid, &_gss_spnego_mskrb_mechanism_oid_desc))
  292. oidp = &_gss_spnego_krb5_mechanism_oid_desc;
  293. else
  294. oidp = &oid;
  295. ret = gss_indicate_mechs(&junk, &mechs);
  296. if (ret)
  297. return (ret);
  298. for (i = 0; i < mechs->count; i++)
  299. if (gss_oid_equal(&mechs->elements[i], oidp))
  300. break;
  301. if (i == mechs->count) {
  302. gss_release_oid_set(&junk, &mechs);
  303. return GSS_S_BAD_MECH;
  304. }
  305. gss_release_oid_set(&junk, &mechs);
  306. ret = gss_duplicate_oid(minor_status,
  307. &oid, /* possibly this should be oidp */
  308. mech_p);
  309. if (verify_p) {
  310. gss_name_t name = GSS_C_NO_NAME;
  311. gss_buffer_desc namebuf;
  312. char *str = NULL, *host, hostname[MAXHOSTNAMELEN];
  313. host = getenv("GSSAPI_SPNEGO_NAME");
  314. if (host == NULL || issuid()) {
  315. int rv;
  316. if (gethostname(hostname, sizeof(hostname)) != 0) {
  317. *minor_status = errno;
  318. return GSS_S_FAILURE;
  319. }
  320. rv = asprintf(&str, "host@%s", hostname);
  321. if (rv < 0 || str == NULL) {
  322. *minor_status = ENOMEM;
  323. return GSS_S_FAILURE;
  324. }
  325. host = str;
  326. }
  327. namebuf.length = strlen(host);
  328. namebuf.value = host;
  329. ret = gss_import_name(minor_status, &namebuf,
  330. GSS_C_NT_HOSTBASED_SERVICE, &name);
  331. if (str)
  332. free(str);
  333. if (ret != GSS_S_COMPLETE)
  334. return ret;
  335. ret = acceptor_approved(name, *mech_p);
  336. gss_release_name(&junk, &name);
  337. }
  338. return ret;
  339. }
  340. static OM_uint32
  341. acceptor_complete(OM_uint32 * minor_status,
  342. gssspnego_ctx ctx,
  343. int *get_mic,
  344. gss_buffer_t mech_buf,
  345. gss_buffer_t mech_input_token,
  346. gss_buffer_t mech_output_token,
  347. heim_octet_string *mic,
  348. gss_buffer_t output_token)
  349. {
  350. OM_uint32 ret;
  351. int require_mic, verify_mic;
  352. ret = _gss_spnego_require_mechlist_mic(minor_status, ctx, &require_mic);
  353. if (ret)
  354. return ret;
  355. ctx->require_mic = require_mic;
  356. if (mic != NULL)
  357. require_mic = 1;
  358. if (ctx->open && require_mic) {
  359. if (mech_input_token == GSS_C_NO_BUFFER) { /* Even/One */
  360. verify_mic = 1;
  361. *get_mic = 0;
  362. } else if (mech_output_token != GSS_C_NO_BUFFER &&
  363. mech_output_token->length == 0) { /* Odd */
  364. *get_mic = verify_mic = 1;
  365. } else { /* Even/One */
  366. verify_mic = 0;
  367. *get_mic = 1;
  368. }
  369. if (verify_mic || *get_mic) {
  370. int eret;
  371. size_t buf_len = 0;
  372. ASN1_MALLOC_ENCODE(MechTypeList,
  373. mech_buf->value, mech_buf->length,
  374. &ctx->initiator_mech_types, &buf_len, eret);
  375. if (eret) {
  376. *minor_status = eret;
  377. return GSS_S_FAILURE;
  378. }
  379. heim_assert(mech_buf->length == buf_len, "Internal ASN.1 error");
  380. UNREACHABLE(return GSS_S_FAILURE);
  381. }
  382. if (verify_mic) {
  383. ret = verify_mechlist_mic(minor_status, ctx, mech_buf, mic);
  384. if (ret) {
  385. if (*get_mic)
  386. send_reject (minor_status, output_token);
  387. return ret;
  388. }
  389. ctx->verified_mic = 1;
  390. }
  391. } else
  392. *get_mic = 0;
  393. return GSS_S_COMPLETE;
  394. }
  395. static OM_uint32 GSSAPI_CALLCONV
  396. acceptor_start
  397. (OM_uint32 * minor_status,
  398. gss_ctx_id_t * context_handle,
  399. const gss_cred_id_t acceptor_cred_handle,
  400. const gss_buffer_t input_token_buffer,
  401. const gss_channel_bindings_t input_chan_bindings,
  402. gss_name_t * src_name,
  403. gss_OID * mech_type,
  404. gss_buffer_t output_token,
  405. OM_uint32 * ret_flags,
  406. OM_uint32 * time_rec,
  407. gss_cred_id_t *delegated_cred_handle
  408. )
  409. {
  410. OM_uint32 ret, junk;
  411. NegotiationToken nt;
  412. size_t nt_len;
  413. NegTokenInit *ni;
  414. gss_buffer_desc data;
  415. gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
  416. gss_buffer_desc mech_output_token;
  417. gss_buffer_desc mech_buf;
  418. gss_OID preferred_mech_type = GSS_C_NO_OID;
  419. gssspnego_ctx ctx;
  420. int get_mic = 0;
  421. int first_ok = 0;
  422. mech_output_token.value = NULL;
  423. mech_output_token.length = 0;
  424. mech_buf.value = NULL;
  425. if (input_token_buffer->length == 0)
  426. return send_supported_mechs (minor_status, output_token);
  427. ret = _gss_spnego_alloc_sec_context(minor_status, context_handle);
  428. if (ret != GSS_S_COMPLETE)
  429. return ret;
  430. ctx = (gssspnego_ctx)*context_handle;
  431. /*
  432. * The GSS-API encapsulation is only present on the initial
  433. * context token (negTokenInit).
  434. */
  435. ret = gss_decapsulate_token (input_token_buffer,
  436. GSS_SPNEGO_MECHANISM,
  437. &data);
  438. if (ret)
  439. return ret;
  440. ret = decode_NegotiationToken(data.value, data.length, &nt, &nt_len);
  441. gss_release_buffer(minor_status, &data);
  442. if (ret) {
  443. *minor_status = ret;
  444. return GSS_S_DEFECTIVE_TOKEN;
  445. }
  446. if (nt.element != choice_NegotiationToken_negTokenInit) {
  447. *minor_status = 0;
  448. return GSS_S_DEFECTIVE_TOKEN;
  449. }
  450. ni = &nt.u.negTokenInit;
  451. if (ni->mechTypes.len < 1) {
  452. free_NegotiationToken(&nt);
  453. *minor_status = 0;
  454. return GSS_S_DEFECTIVE_TOKEN;
  455. }
  456. HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
  457. ret = copy_MechTypeList(&ni->mechTypes, &ctx->initiator_mech_types);
  458. if (ret) {
  459. HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  460. free_NegotiationToken(&nt);
  461. *minor_status = ret;
  462. return GSS_S_FAILURE;
  463. }
  464. /*
  465. * First we try the opportunistic token if we have support for it,
  466. * don't try to verify we have credential for the token,
  467. * gss_accept_sec_context() will (hopefully) tell us that.
  468. * If that failes,
  469. */
  470. ret = select_mech(minor_status,
  471. &ni->mechTypes.val[0],
  472. 0,
  473. &preferred_mech_type);
  474. if (ret == 0 && ni->mechToken != NULL) {
  475. gss_buffer_desc ibuf;
  476. ibuf.length = ni->mechToken->length;
  477. ibuf.value = ni->mechToken->data;
  478. mech_input_token = &ibuf;
  479. if (ctx->mech_src_name != GSS_C_NO_NAME)
  480. gss_release_name(&junk, &ctx->mech_src_name);
  481. ret = gss_accept_sec_context(minor_status,
  482. &ctx->negotiated_ctx_id,
  483. acceptor_cred_handle,
  484. mech_input_token,
  485. input_chan_bindings,
  486. &ctx->mech_src_name,
  487. &ctx->negotiated_mech_type,
  488. &mech_output_token,
  489. &ctx->mech_flags,
  490. &ctx->mech_time_rec,
  491. delegated_cred_handle);
  492. if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
  493. ctx->preferred_mech_type = preferred_mech_type;
  494. if (ret == GSS_S_COMPLETE)
  495. ctx->open = 1;
  496. ret = acceptor_complete(minor_status,
  497. ctx,
  498. &get_mic,
  499. &mech_buf,
  500. mech_input_token,
  501. &mech_output_token,
  502. ni->mechListMIC,
  503. output_token);
  504. if (ret != GSS_S_COMPLETE)
  505. goto out;
  506. first_ok = 1;
  507. } else {
  508. gss_mg_collect_error(preferred_mech_type, ret, *minor_status);
  509. }
  510. }
  511. /*
  512. * If opportunistic token failed, lets try the other mechs.
  513. */
  514. if (!first_ok && ni->mechToken != NULL) {
  515. size_t j;
  516. preferred_mech_type = GSS_C_NO_OID;
  517. /* Call glue layer to find first mech we support */
  518. for (j = 1; j < ni->mechTypes.len; ++j) {
  519. ret = select_mech(minor_status,
  520. &ni->mechTypes.val[j],
  521. 1,
  522. &preferred_mech_type);
  523. if (ret == 0)
  524. break;
  525. }
  526. if (preferred_mech_type == GSS_C_NO_OID) {
  527. HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  528. free_NegotiationToken(&nt);
  529. return ret;
  530. }
  531. ctx->preferred_mech_type = preferred_mech_type;
  532. }
  533. /*
  534. * The initial token always have a response
  535. */
  536. ret = send_accept (minor_status,
  537. ctx,
  538. &mech_output_token,
  539. 1,
  540. get_mic ? &mech_buf : NULL,
  541. output_token);
  542. if (ret)
  543. goto out;
  544. out:
  545. if (mech_output_token.value != NULL)
  546. gss_release_buffer(&junk, &mech_output_token);
  547. if (mech_buf.value != NULL) {
  548. free(mech_buf.value);
  549. mech_buf.value = NULL;
  550. }
  551. free_NegotiationToken(&nt);
  552. if (ret == GSS_S_COMPLETE) {
  553. if (src_name != NULL && ctx->mech_src_name != NULL) {
  554. spnego_name name;
  555. name = calloc(1, sizeof(*name));
  556. if (name) {
  557. name->mech = ctx->mech_src_name;
  558. ctx->mech_src_name = NULL;
  559. *src_name = (gss_name_t)name;
  560. }
  561. }
  562. }
  563. if (mech_type != NULL)
  564. *mech_type = ctx->negotiated_mech_type;
  565. if (ret_flags != NULL)
  566. *ret_flags = ctx->mech_flags;
  567. if (time_rec != NULL)
  568. *time_rec = ctx->mech_time_rec;
  569. if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
  570. HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  571. return ret;
  572. }
  573. _gss_spnego_internal_delete_sec_context(&junk, context_handle,
  574. GSS_C_NO_BUFFER);
  575. return ret;
  576. }
  577. static OM_uint32 GSSAPI_CALLCONV
  578. acceptor_continue
  579. (OM_uint32 * minor_status,
  580. gss_ctx_id_t * context_handle,
  581. const gss_cred_id_t acceptor_cred_handle,
  582. const gss_buffer_t input_token_buffer,
  583. const gss_channel_bindings_t input_chan_bindings,
  584. gss_name_t * src_name,
  585. gss_OID * mech_type,
  586. gss_buffer_t output_token,
  587. OM_uint32 * ret_flags,
  588. OM_uint32 * time_rec,
  589. gss_cred_id_t *delegated_cred_handle
  590. )
  591. {
  592. OM_uint32 ret, ret2, minor;
  593. NegotiationToken nt;
  594. size_t nt_len;
  595. NegTokenResp *na;
  596. unsigned int negResult = accept_incomplete;
  597. gss_buffer_t mech_input_token = GSS_C_NO_BUFFER;
  598. gss_buffer_t mech_output_token = GSS_C_NO_BUFFER;
  599. gss_buffer_desc mech_buf;
  600. gssspnego_ctx ctx;
  601. mech_buf.value = NULL;
  602. ctx = (gssspnego_ctx)*context_handle;
  603. /*
  604. * The GSS-API encapsulation is only present on the initial
  605. * context token (negTokenInit).
  606. */
  607. ret = decode_NegotiationToken(input_token_buffer->value,
  608. input_token_buffer->length,
  609. &nt, &nt_len);
  610. if (ret) {
  611. *minor_status = ret;
  612. return GSS_S_DEFECTIVE_TOKEN;
  613. }
  614. if (nt.element != choice_NegotiationToken_negTokenResp) {
  615. *minor_status = 0;
  616. return GSS_S_DEFECTIVE_TOKEN;
  617. }
  618. na = &nt.u.negTokenResp;
  619. if (na->negResult != NULL) {
  620. negResult = *(na->negResult);
  621. }
  622. HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
  623. {
  624. gss_buffer_desc ibuf, obuf;
  625. int require_mic, get_mic = 0;
  626. int require_response;
  627. heim_octet_string *mic;
  628. if (na->responseToken != NULL) {
  629. ibuf.length = na->responseToken->length;
  630. ibuf.value = na->responseToken->data;
  631. mech_input_token = &ibuf;
  632. } else {
  633. ibuf.value = NULL;
  634. ibuf.length = 0;
  635. }
  636. if (mech_input_token != GSS_C_NO_BUFFER) {
  637. if (ctx->mech_src_name != GSS_C_NO_NAME)
  638. gss_release_name(&minor, &ctx->mech_src_name);
  639. ret = gss_accept_sec_context(&minor,
  640. &ctx->negotiated_ctx_id,
  641. acceptor_cred_handle,
  642. mech_input_token,
  643. input_chan_bindings,
  644. &ctx->mech_src_name,
  645. &ctx->negotiated_mech_type,
  646. &obuf,
  647. &ctx->mech_flags,
  648. &ctx->mech_time_rec,
  649. delegated_cred_handle);
  650. if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
  651. mech_output_token = &obuf;
  652. }
  653. if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
  654. free_NegotiationToken(&nt);
  655. gss_mg_collect_error(ctx->negotiated_mech_type, ret, minor);
  656. send_reject (minor_status, output_token);
  657. HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  658. return ret;
  659. }
  660. if (ret == GSS_S_COMPLETE)
  661. ctx->open = 1;
  662. } else
  663. ret = GSS_S_COMPLETE;
  664. ret2 = _gss_spnego_require_mechlist_mic(minor_status,
  665. ctx,
  666. &require_mic);
  667. if (ret2)
  668. goto out;
  669. ctx->require_mic = require_mic;
  670. mic = na->mechListMIC;
  671. if (mic != NULL)
  672. require_mic = 1;
  673. if (ret == GSS_S_COMPLETE)
  674. ret = acceptor_complete(minor_status,
  675. ctx,
  676. &get_mic,
  677. &mech_buf,
  678. mech_input_token,
  679. mech_output_token,
  680. na->mechListMIC,
  681. output_token);
  682. if (ctx->mech_flags & GSS_C_DCE_STYLE)
  683. require_response = (negResult != accept_completed);
  684. else
  685. require_response = 0;
  686. /*
  687. * Check whether we need to send a result: there should be only
  688. * one accept_completed response sent in the entire negotiation
  689. */
  690. if ((mech_output_token != GSS_C_NO_BUFFER &&
  691. mech_output_token->length != 0)
  692. || (ctx->open && negResult == accept_incomplete)
  693. || require_response
  694. || get_mic) {
  695. ret2 = send_accept (minor_status,
  696. ctx,
  697. mech_output_token,
  698. 0,
  699. get_mic ? &mech_buf : NULL,
  700. output_token);
  701. if (ret2)
  702. goto out;
  703. }
  704. out:
  705. if (ret2 != GSS_S_COMPLETE)
  706. ret = ret2;
  707. if (mech_output_token != NULL)
  708. gss_release_buffer(&minor, mech_output_token);
  709. if (mech_buf.value != NULL)
  710. free(mech_buf.value);
  711. free_NegotiationToken(&nt);
  712. }
  713. if (ret == GSS_S_COMPLETE) {
  714. if (src_name != NULL && ctx->mech_src_name != NULL) {
  715. spnego_name name;
  716. name = calloc(1, sizeof(*name));
  717. if (name) {
  718. name->mech = ctx->mech_src_name;
  719. ctx->mech_src_name = NULL;
  720. *src_name = (gss_name_t)name;
  721. }
  722. }
  723. }
  724. if (mech_type != NULL)
  725. *mech_type = ctx->negotiated_mech_type;
  726. if (ret_flags != NULL)
  727. *ret_flags = ctx->mech_flags;
  728. if (time_rec != NULL)
  729. *time_rec = ctx->mech_time_rec;
  730. if (ret == GSS_S_COMPLETE || ret == GSS_S_CONTINUE_NEEDED) {
  731. HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
  732. return ret;
  733. }
  734. _gss_spnego_internal_delete_sec_context(&minor, context_handle,
  735. GSS_C_NO_BUFFER);
  736. return ret;
  737. }
  738. OM_uint32 GSSAPI_CALLCONV
  739. _gss_spnego_accept_sec_context
  740. (OM_uint32 * minor_status,
  741. gss_ctx_id_t * context_handle,
  742. const gss_cred_id_t acceptor_cred_handle,
  743. const gss_buffer_t input_token_buffer,
  744. const gss_channel_bindings_t input_chan_bindings,
  745. gss_name_t * src_name,
  746. gss_OID * mech_type,
  747. gss_buffer_t output_token,
  748. OM_uint32 * ret_flags,
  749. OM_uint32 * time_rec,
  750. gss_cred_id_t *delegated_cred_handle
  751. )
  752. {
  753. _gss_accept_sec_context_t *func;
  754. *minor_status = 0;
  755. output_token->length = 0;
  756. output_token->value = NULL;
  757. if (src_name != NULL)
  758. *src_name = GSS_C_NO_NAME;
  759. if (mech_type != NULL)
  760. *mech_type = GSS_C_NO_OID;
  761. if (ret_flags != NULL)
  762. *ret_flags = 0;
  763. if (time_rec != NULL)
  764. *time_rec = 0;
  765. if (delegated_cred_handle != NULL)
  766. *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
  767. if (*context_handle == GSS_C_NO_CONTEXT)
  768. func = acceptor_start;
  769. else
  770. func = acceptor_continue;
  771. return (*func)(minor_status, context_handle, acceptor_cred_handle,
  772. input_token_buffer, input_chan_bindings,
  773. src_name, mech_type, output_token, ret_flags,
  774. time_rec, delegated_cred_handle);
  775. }