kerberosgss.c 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007
  1. /**
  2. * Copyright (c) 2006-2018 Apple Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. **/
  16. #include <Python.h>
  17. #include "kerberosgss.h"
  18. #include "base64.h"
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <arpa/inet.h>
  23. static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min);
  24. int create_krb5_ccache(
  25. gss_server_state *state, krb5_context kcontext, krb5_principal princ,
  26. krb5_ccache *ccache
  27. );
  28. extern PyObject *GssException_class;
  29. extern PyObject *KrbException_class;
  30. char* server_principal_details(const char* service, const char* hostname)
  31. {
  32. char match[1024];
  33. size_t match_len = 0;
  34. char* result = NULL;
  35. int code;
  36. krb5_context kcontext;
  37. krb5_keytab kt = NULL;
  38. krb5_kt_cursor cursor = NULL;
  39. krb5_keytab_entry entry;
  40. char* pname = NULL;
  41. // Generate the principal prefix we want to match
  42. snprintf(match, 1024, "%s/%s@", service, hostname);
  43. match_len = strlen(match);
  44. code = krb5_init_context(&kcontext);
  45. if (code) {
  46. PyErr_SetObject(
  47. KrbException_class,
  48. Py_BuildValue(
  49. "((s:i))", "Cannot initialize Kerberos5 context", code
  50. )
  51. );
  52. return NULL;
  53. }
  54. if ((code = krb5_kt_default(kcontext, &kt))) {
  55. PyErr_SetObject(
  56. KrbException_class,
  57. Py_BuildValue("((s:i))", "Cannot get default keytab", code)
  58. );
  59. goto end;
  60. }
  61. if ((code = krb5_kt_start_seq_get(kcontext, kt, &cursor))) {
  62. PyErr_SetObject(
  63. KrbException_class,
  64. Py_BuildValue(
  65. "((s:i))", "Cannot get sequence cursor from keytab", code
  66. )
  67. );
  68. goto end;
  69. }
  70. while ((code = krb5_kt_next_entry(kcontext, kt, &entry, &cursor)) == 0) {
  71. if ((code = krb5_unparse_name(kcontext, entry.principal, &pname))) {
  72. PyErr_SetObject(
  73. KrbException_class,
  74. Py_BuildValue(
  75. "((s:i))", "Cannot parse principal name from keytab", code
  76. )
  77. );
  78. goto end;
  79. }
  80. if (strncmp(pname, match, match_len) == 0) {
  81. result = malloc(strlen(pname) + 1);
  82. if (result == NULL) {
  83. PyErr_NoMemory();
  84. goto end;
  85. }
  86. strcpy(result, pname);
  87. krb5_free_unparsed_name(kcontext, pname);
  88. krb5_free_keytab_entry_contents(kcontext, &entry);
  89. break;
  90. }
  91. krb5_free_unparsed_name(kcontext, pname);
  92. krb5_free_keytab_entry_contents(kcontext, &entry);
  93. }
  94. if (result == NULL) {
  95. PyErr_SetObject(
  96. KrbException_class,
  97. Py_BuildValue("((s:i))", "Principal not found in keytab", -1)
  98. );
  99. }
  100. end:
  101. if (cursor) {
  102. krb5_kt_end_seq_get(kcontext, kt, &cursor);
  103. }
  104. if (kt) {
  105. krb5_kt_close(kcontext, kt);
  106. }
  107. krb5_free_context(kcontext);
  108. return result;
  109. }
  110. int authenticate_gss_client_init(
  111. const char* service, const char* principal, long int gss_flags,
  112. gss_server_state* delegatestate, gss_OID mech_oid, gss_client_state* state
  113. )
  114. {
  115. OM_uint32 maj_stat;
  116. OM_uint32 min_stat;
  117. gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
  118. gss_buffer_desc principal_token = GSS_C_EMPTY_BUFFER;
  119. int ret = AUTH_GSS_COMPLETE;
  120. state->server_name = GSS_C_NO_NAME;
  121. state->mech_oid = mech_oid;
  122. state->context = GSS_C_NO_CONTEXT;
  123. state->gss_flags = gss_flags;
  124. state->client_creds = GSS_C_NO_CREDENTIAL;
  125. state->username = NULL;
  126. state->response = NULL;
  127. // Import server name first
  128. name_token.length = strlen(service);
  129. name_token.value = (char *)service;
  130. maj_stat = gss_import_name(
  131. &min_stat, &name_token, gss_krb5_nt_service_name, &state->server_name
  132. );
  133. if (GSS_ERROR(maj_stat)) {
  134. set_gss_error(maj_stat, min_stat);
  135. ret = AUTH_GSS_ERROR;
  136. goto end;
  137. }
  138. // Use the delegate credentials if they exist
  139. if (delegatestate && delegatestate->client_creds != GSS_C_NO_CREDENTIAL) {
  140. state->client_creds = delegatestate->client_creds;
  141. }
  142. // If available use the principal to extract its associated credentials
  143. else if (principal && *principal) {
  144. gss_name_t name;
  145. principal_token.length = strlen(principal);
  146. principal_token.value = (char *)principal;
  147. maj_stat = gss_import_name(
  148. &min_stat, &principal_token, GSS_C_NT_USER_NAME, &name
  149. );
  150. if (GSS_ERROR(maj_stat)) {
  151. set_gss_error(maj_stat, min_stat);
  152. ret = AUTH_GSS_ERROR;
  153. goto end;
  154. }
  155. maj_stat = gss_acquire_cred(
  156. &min_stat, name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
  157. GSS_C_INITIATE, &state->client_creds, NULL, NULL
  158. );
  159. if (GSS_ERROR(maj_stat)) {
  160. set_gss_error(maj_stat, min_stat);
  161. ret = AUTH_GSS_ERROR;
  162. goto end;
  163. }
  164. maj_stat = gss_release_name(&min_stat, &name);
  165. if (GSS_ERROR(maj_stat)) {
  166. set_gss_error(maj_stat, min_stat);
  167. ret = AUTH_GSS_ERROR;
  168. goto end;
  169. }
  170. }
  171. end:
  172. return ret;
  173. }
  174. int authenticate_gss_client_clean(gss_client_state *state)
  175. {
  176. OM_uint32 maj_stat;
  177. OM_uint32 min_stat;
  178. int ret = AUTH_GSS_COMPLETE;
  179. if (state->context != GSS_C_NO_CONTEXT) {
  180. maj_stat = gss_delete_sec_context(
  181. &min_stat, &state->context, GSS_C_NO_BUFFER
  182. );
  183. }
  184. if (state->server_name != GSS_C_NO_NAME) {
  185. maj_stat = gss_release_name(&min_stat, &state->server_name);
  186. }
  187. if (
  188. state->client_creds != GSS_C_NO_CREDENTIAL &&
  189. ! (state->gss_flags & GSS_C_DELEG_FLAG)
  190. ) {
  191. maj_stat = gss_release_cred(&min_stat, &state->client_creds);
  192. }
  193. if (state->username != NULL) {
  194. free(state->username);
  195. state->username = NULL;
  196. }
  197. if (state->response != NULL) {
  198. free(state->response);
  199. state->response = NULL;
  200. }
  201. return ret;
  202. }
  203. int authenticate_gss_client_step(
  204. gss_client_state* state, const char* challenge, struct gss_channel_bindings_struct* channel_bindings
  205. ) {
  206. OM_uint32 maj_stat;
  207. OM_uint32 min_stat;
  208. gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  209. gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  210. int ret = AUTH_GSS_CONTINUE;
  211. // Always clear out the old response
  212. if (state->response != NULL) {
  213. free(state->response);
  214. state->response = NULL;
  215. }
  216. // If there is a challenge (data from the server) we need to give it to GSS
  217. if (challenge && *challenge) {
  218. size_t len;
  219. input_token.value = base64_decode(challenge, &len);
  220. if (input_token.value == NULL)
  221. {
  222. PyErr_NoMemory();
  223. ret = AUTH_GSS_ERROR;
  224. goto end;
  225. }
  226. input_token.length = len;
  227. }
  228. // Do GSSAPI step
  229. Py_BEGIN_ALLOW_THREADS
  230. maj_stat = gss_init_sec_context(
  231. &min_stat,
  232. state->client_creds,
  233. &state->context,
  234. state->server_name,
  235. state->mech_oid,
  236. (OM_uint32)state->gss_flags,
  237. 0,
  238. channel_bindings,
  239. &input_token,
  240. NULL,
  241. &output_token,
  242. NULL,
  243. NULL
  244. );
  245. Py_END_ALLOW_THREADS
  246. if ((maj_stat != GSS_S_COMPLETE) && (maj_stat != GSS_S_CONTINUE_NEEDED)) {
  247. set_gss_error(maj_stat, min_stat);
  248. ret = AUTH_GSS_ERROR;
  249. goto end;
  250. }
  251. ret = (maj_stat == GSS_S_COMPLETE) ? AUTH_GSS_COMPLETE : AUTH_GSS_CONTINUE;
  252. // Grab the client response to send back to the server
  253. if (output_token.length) {
  254. state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
  255. if (state->response == NULL) {
  256. PyErr_NoMemory();
  257. ret = AUTH_GSS_ERROR;
  258. goto end;
  259. }
  260. maj_stat = gss_release_buffer(&min_stat, &output_token);
  261. }
  262. // Try to get the user name if we have completed all GSS operations
  263. if (ret == AUTH_GSS_COMPLETE) {
  264. gss_name_t gssuser = GSS_C_NO_NAME;
  265. maj_stat = gss_inquire_context(&min_stat, state->context, &gssuser, NULL, NULL, NULL, NULL, NULL, NULL);
  266. if (GSS_ERROR(maj_stat)) {
  267. set_gss_error(maj_stat, min_stat);
  268. ret = AUTH_GSS_ERROR;
  269. goto end;
  270. }
  271. gss_buffer_desc name_token;
  272. name_token.length = 0;
  273. maj_stat = gss_display_name(&min_stat, gssuser, &name_token, NULL);
  274. if (GSS_ERROR(maj_stat)) {
  275. if (name_token.value) {
  276. gss_release_buffer(&min_stat, &name_token);
  277. }
  278. gss_release_name(&min_stat, &gssuser);
  279. set_gss_error(maj_stat, min_stat);
  280. ret = AUTH_GSS_ERROR;
  281. goto end;
  282. } else {
  283. if (state->username != NULL) {
  284. free(state->username);
  285. state->username = NULL;
  286. }
  287. state->username = (char *)malloc(name_token.length + 1);
  288. if (state->username == NULL) {
  289. PyErr_NoMemory();
  290. ret = AUTH_GSS_ERROR;
  291. goto end;
  292. }
  293. strncpy(state->username, (char*) name_token.value, name_token.length);
  294. state->username[name_token.length] = 0;
  295. gss_release_buffer(&min_stat, &name_token);
  296. gss_release_name(&min_stat, &gssuser);
  297. }
  298. }
  299. end:
  300. if (output_token.value) {
  301. gss_release_buffer(&min_stat, &output_token);
  302. }
  303. if (input_token.value) {
  304. free(input_token.value);
  305. }
  306. return ret;
  307. }
  308. int authenticate_gss_client_unwrap(
  309. gss_client_state *state, const char *challenge
  310. ) {
  311. OM_uint32 maj_stat;
  312. OM_uint32 min_stat;
  313. gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  314. gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  315. int ret = AUTH_GSS_CONTINUE;
  316. int conf = 0;
  317. // Always clear out the old response
  318. if (state->response != NULL) {
  319. free(state->response);
  320. state->response = NULL;
  321. state->responseConf = 0;
  322. }
  323. // If there is a challenge (data from the server) we need to give it to GSS
  324. if (challenge && *challenge) {
  325. size_t len;
  326. input_token.value = base64_decode(challenge, &len);
  327. if (input_token.value == NULL) {
  328. PyErr_NoMemory();
  329. ret = AUTH_GSS_ERROR;
  330. goto end;
  331. }
  332. input_token.length = len;
  333. }
  334. // Do GSSAPI step
  335. maj_stat = gss_unwrap(
  336. &min_stat,
  337. state->context,
  338. &input_token,
  339. &output_token,
  340. &conf,
  341. NULL
  342. );
  343. if (maj_stat != GSS_S_COMPLETE) {
  344. set_gss_error(maj_stat, min_stat);
  345. ret = AUTH_GSS_ERROR;
  346. goto end;
  347. } else {
  348. ret = AUTH_GSS_COMPLETE;
  349. }
  350. // Grab the client response
  351. if (output_token.length) {
  352. state->response = base64_encode(
  353. (const unsigned char *)output_token.value, output_token.length
  354. );
  355. if (state->response == NULL)
  356. {
  357. PyErr_NoMemory();
  358. ret = AUTH_GSS_ERROR;
  359. goto end;
  360. }
  361. state->responseConf = conf;
  362. maj_stat = gss_release_buffer(&min_stat, &output_token);
  363. }
  364. end:
  365. if (output_token.value) {
  366. gss_release_buffer(&min_stat, &output_token);
  367. }
  368. if (input_token.value) {
  369. free(input_token.value);
  370. }
  371. return ret;
  372. }
  373. int authenticate_gss_client_wrap(
  374. gss_client_state* state, const char* challenge, const char* user,
  375. int protect
  376. ) {
  377. OM_uint32 maj_stat;
  378. OM_uint32 min_stat;
  379. gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  380. gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  381. int ret = AUTH_GSS_CONTINUE;
  382. char buf[4096], server_conf_flags;
  383. unsigned long buf_size;
  384. // Always clear out the old response
  385. if (state->response != NULL) {
  386. free(state->response);
  387. state->response = NULL;
  388. }
  389. if (challenge && *challenge) {
  390. size_t len;
  391. input_token.value = base64_decode(challenge, &len);
  392. if (input_token.value == NULL)
  393. {
  394. PyErr_NoMemory();
  395. ret = AUTH_GSS_ERROR;
  396. goto end;
  397. }
  398. input_token.length = len;
  399. }
  400. if (user) {
  401. // get bufsize
  402. server_conf_flags = ((char*) input_token.value)[0];
  403. ((char*) input_token.value)[0] = 0;
  404. buf_size = ntohl(*((long *) input_token.value));
  405. free(input_token.value);
  406. #ifdef PRINTFS
  407. printf(
  408. "User: %s, %c%c%c\n", user,
  409. server_conf_flags & GSS_AUTH_P_NONE ? 'N' : '-',
  410. server_conf_flags & GSS_AUTH_P_INTEGRITY ? 'I' : '-',
  411. server_conf_flags & GSS_AUTH_P_PRIVACY ? 'P' : '-'
  412. );
  413. printf("Maximum GSS token size is %ld\n", buf_size);
  414. #endif
  415. // agree to terms (hack!)
  416. buf_size = htonl(buf_size); // not relevant without integrity/privacy
  417. memcpy(buf, &buf_size, 4);
  418. buf[0] = GSS_AUTH_P_NONE;
  419. // server decides if principal can log in as user
  420. strncpy(buf + 4, user, sizeof(buf) - 4);
  421. input_token.value = buf;
  422. input_token.length = 4 + strlen(user);
  423. }
  424. // Do GSSAPI wrap
  425. maj_stat = gss_wrap(
  426. &min_stat,
  427. state->context,
  428. protect,
  429. GSS_C_QOP_DEFAULT,
  430. &input_token,
  431. NULL,
  432. &output_token
  433. );
  434. if (maj_stat != GSS_S_COMPLETE) {
  435. set_gss_error(maj_stat, min_stat);
  436. ret = AUTH_GSS_ERROR;
  437. goto end;
  438. } else {
  439. ret = AUTH_GSS_COMPLETE;
  440. }
  441. // Grab the client response to send back to the server
  442. if (output_token.length) {
  443. state->response = base64_encode((const unsigned char *)output_token.value, output_token.length);
  444. if (state->response == NULL) {
  445. PyErr_NoMemory();
  446. ret = AUTH_GSS_ERROR;
  447. goto end;
  448. }
  449. maj_stat = gss_release_buffer(&min_stat, &output_token);
  450. }
  451. end:
  452. if (output_token.value) {
  453. gss_release_buffer(&min_stat, &output_token);
  454. }
  455. return ret;
  456. }
  457. int authenticate_gss_client_inquire_cred(gss_client_state* state)
  458. {
  459. OM_uint32 maj_stat;
  460. OM_uint32 min_stat;
  461. gss_cred_id_t client_creds = GSS_C_NO_CREDENTIAL;
  462. gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
  463. gss_name_t name = GSS_C_NO_NAME;
  464. int ret = AUTH_GSS_COMPLETE;
  465. // Check whether credentials have already been obtained.
  466. if (state->username != NULL) {
  467. goto end;
  468. }
  469. // Get credentials
  470. maj_stat = gss_acquire_cred(
  471. &min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE,
  472. GSS_C_NO_OID_SET, GSS_C_INITIATE, &client_creds, NULL, NULL
  473. );
  474. if (GSS_ERROR(maj_stat)) {
  475. set_gss_error(maj_stat, min_stat);
  476. ret = AUTH_GSS_ERROR;
  477. goto end;
  478. }
  479. // Get the name
  480. maj_stat = gss_inquire_cred(
  481. &min_stat, client_creds, &name, NULL, NULL, NULL
  482. );
  483. if (GSS_ERROR(maj_stat)) {
  484. set_gss_error(maj_stat, min_stat);
  485. ret = AUTH_GSS_ERROR;
  486. goto end;
  487. }
  488. maj_stat = gss_display_name(&min_stat, name, &name_token, NULL);
  489. if (GSS_ERROR(maj_stat)) {
  490. set_gss_error(maj_stat, min_stat);
  491. ret = AUTH_GSS_ERROR;
  492. goto end;
  493. }
  494. state->username = (char *)malloc(name_token.length + 1);
  495. if (state->username == NULL) {
  496. PyErr_NoMemory();
  497. ret = AUTH_GSS_ERROR;
  498. goto end;
  499. }
  500. strncpy(state->username, (char*) name_token.value, name_token.length);
  501. state->username[name_token.length] = 0;
  502. end:
  503. if (client_creds != GSS_C_NO_CREDENTIAL) {
  504. gss_release_cred(&min_stat, &client_creds);
  505. }
  506. if (name_token.length) {
  507. gss_release_buffer(&min_stat, &name_token);
  508. }
  509. if (name != GSS_C_NO_NAME) {
  510. gss_release_name(&min_stat, &name);
  511. }
  512. return ret;
  513. }
  514. int authenticate_gss_server_init(const char *service, gss_server_state *state)
  515. {
  516. OM_uint32 maj_stat;
  517. OM_uint32 min_stat;
  518. gss_buffer_desc name_token = GSS_C_EMPTY_BUFFER;
  519. int ret = AUTH_GSS_COMPLETE;
  520. state->context = GSS_C_NO_CONTEXT;
  521. state->server_name = GSS_C_NO_NAME;
  522. state->client_name = GSS_C_NO_NAME;
  523. state->server_creds = GSS_C_NO_CREDENTIAL;
  524. state->client_creds = GSS_C_NO_CREDENTIAL;
  525. state->username = NULL;
  526. state->targetname = NULL;
  527. state->response = NULL;
  528. state->ccname = NULL;
  529. int cred_usage = GSS_C_ACCEPT;
  530. // Server name may be empty which means we aren't going to create our own creds
  531. size_t service_len = strlen(service);
  532. if (service_len != 0) {
  533. // Import server name first
  534. if (strcmp(service, "DELEGATE") == 0) {
  535. cred_usage = GSS_C_BOTH;
  536. }
  537. else {
  538. name_token.length = strlen(service);
  539. name_token.value = (char *)service;
  540. maj_stat = gss_import_name(
  541. &min_stat, &name_token, GSS_C_NT_HOSTBASED_SERVICE,
  542. &state->server_name
  543. );
  544. if (GSS_ERROR(maj_stat)) {
  545. set_gss_error(maj_stat, min_stat);
  546. ret = AUTH_GSS_ERROR;
  547. goto end;
  548. }
  549. }
  550. // Get credentials
  551. maj_stat = gss_acquire_cred(
  552. &min_stat, state->server_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET,
  553. cred_usage, &state->server_creds, NULL, NULL
  554. );
  555. if (GSS_ERROR(maj_stat)) {
  556. set_gss_error(maj_stat, min_stat);
  557. ret = AUTH_GSS_ERROR;
  558. goto end;
  559. }
  560. }
  561. end:
  562. return ret;
  563. }
  564. int authenticate_gss_server_clean(gss_server_state *state)
  565. {
  566. OM_uint32 maj_stat;
  567. OM_uint32 min_stat;
  568. int ret = AUTH_GSS_COMPLETE;
  569. if (state->context != GSS_C_NO_CONTEXT) {
  570. maj_stat = gss_delete_sec_context(
  571. &min_stat, &state->context, GSS_C_NO_BUFFER
  572. );
  573. }
  574. if (state->server_name != GSS_C_NO_NAME) {
  575. maj_stat = gss_release_name(&min_stat, &state->server_name);
  576. }
  577. if (state->client_name != GSS_C_NO_NAME) {
  578. maj_stat = gss_release_name(&min_stat, &state->client_name);
  579. }
  580. if (state->server_creds != GSS_C_NO_CREDENTIAL) {
  581. maj_stat = gss_release_cred(&min_stat, &state->server_creds);
  582. }
  583. if (state->client_creds != GSS_C_NO_CREDENTIAL) {
  584. maj_stat = gss_release_cred(&min_stat, &state->client_creds);
  585. }
  586. if (state->username != NULL) {
  587. free(state->username);
  588. state->username = NULL;
  589. }
  590. if (state->targetname != NULL) {
  591. free(state->targetname);
  592. state->targetname = NULL;
  593. }
  594. if (state->response != NULL) {
  595. free(state->response);
  596. state->response = NULL;
  597. }
  598. if (state->ccname != NULL) {
  599. free(state->ccname);
  600. state->ccname = NULL;
  601. }
  602. return ret;
  603. }
  604. int authenticate_gss_server_step(
  605. gss_server_state *state, const char *challenge
  606. ) {
  607. OM_uint32 maj_stat;
  608. OM_uint32 min_stat;
  609. gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
  610. gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
  611. int ret = AUTH_GSS_CONTINUE;
  612. // Always clear out the old response
  613. if (state->response != NULL) {
  614. free(state->response);
  615. state->response = NULL;
  616. }
  617. // If there is a challenge (data from the server) we need to give it to GSS
  618. if (challenge && *challenge) {
  619. size_t len;
  620. input_token.value = base64_decode(challenge, &len);
  621. if (input_token.value == NULL)
  622. {
  623. PyErr_NoMemory();
  624. ret = AUTH_GSS_ERROR;
  625. goto end;
  626. }
  627. input_token.length = len;
  628. } else {
  629. PyErr_SetString(
  630. KrbException_class, "No challenge parameter in request from client"
  631. );
  632. ret = AUTH_GSS_ERROR;
  633. goto end;
  634. }
  635. Py_BEGIN_ALLOW_THREADS
  636. maj_stat = gss_accept_sec_context(
  637. &min_stat,
  638. &state->context,
  639. state->server_creds,
  640. &input_token,
  641. GSS_C_NO_CHANNEL_BINDINGS,
  642. &state->client_name,
  643. NULL,
  644. &output_token,
  645. NULL,
  646. NULL,
  647. &state->client_creds
  648. );
  649. Py_END_ALLOW_THREADS
  650. if (GSS_ERROR(maj_stat)) {
  651. set_gss_error(maj_stat, min_stat);
  652. ret = AUTH_GSS_ERROR;
  653. goto end;
  654. }
  655. // Grab the server response to send back to the client
  656. if (output_token.length) {
  657. state->response = base64_encode(
  658. (const unsigned char *)output_token.value, output_token.length
  659. );
  660. if (state->response == NULL)
  661. {
  662. PyErr_NoMemory();
  663. ret = AUTH_GSS_ERROR;
  664. goto end;
  665. }
  666. maj_stat = gss_release_buffer(&min_stat, &output_token);
  667. }
  668. // Get the user name
  669. maj_stat = gss_display_name(
  670. &min_stat, state->client_name, &output_token, NULL
  671. );
  672. if (GSS_ERROR(maj_stat)) {
  673. set_gss_error(maj_stat, min_stat);
  674. ret = AUTH_GSS_ERROR;
  675. goto end;
  676. }
  677. state->username = (char *)malloc(output_token.length + 1);
  678. if (state->username == NULL)
  679. {
  680. PyErr_NoMemory();
  681. ret = AUTH_GSS_ERROR;
  682. goto end;
  683. }
  684. strncpy(state->username, (char*) output_token.value, output_token.length);
  685. state->username[output_token.length] = 0;
  686. // Get the target name if no server creds were supplied
  687. if (state->server_creds == GSS_C_NO_CREDENTIAL) {
  688. gss_name_t target_name = GSS_C_NO_NAME;
  689. maj_stat = gss_inquire_context(
  690. &min_stat, state->context, NULL, &target_name, NULL, NULL, NULL,
  691. NULL, NULL
  692. );
  693. if (GSS_ERROR(maj_stat)) {
  694. set_gss_error(maj_stat, min_stat);
  695. ret = AUTH_GSS_ERROR;
  696. goto end;
  697. }
  698. maj_stat = gss_display_name(
  699. &min_stat, target_name, &output_token, NULL
  700. );
  701. if (GSS_ERROR(maj_stat)) {
  702. set_gss_error(maj_stat, min_stat);
  703. ret = AUTH_GSS_ERROR;
  704. goto end;
  705. }
  706. state->targetname = (char *)malloc(output_token.length + 1);
  707. if (state->targetname == NULL)
  708. {
  709. PyErr_NoMemory();
  710. ret = AUTH_GSS_ERROR;
  711. goto end;
  712. }
  713. strncpy(
  714. state->targetname, (char*) output_token.value, output_token.length
  715. );
  716. state->targetname[output_token.length] = 0;
  717. }
  718. ret = AUTH_GSS_COMPLETE;
  719. end:
  720. if (output_token.length) {
  721. gss_release_buffer(&min_stat, &output_token);
  722. }
  723. if (input_token.value) {
  724. free(input_token.value);
  725. }
  726. return ret;
  727. }
  728. int authenticate_gss_server_has_delegated(gss_server_state *state)
  729. {
  730. return (state->client_creds != GSS_C_NO_CREDENTIAL);
  731. }
  732. static void set_gss_error(OM_uint32 err_maj, OM_uint32 err_min)
  733. {
  734. OM_uint32 maj_stat, min_stat;
  735. OM_uint32 msg_ctx = 0;
  736. gss_buffer_desc status_string;
  737. char buf_maj[512];
  738. char buf_min[512];
  739. do {
  740. maj_stat = gss_display_status(
  741. &min_stat,
  742. err_maj,
  743. GSS_C_GSS_CODE,
  744. GSS_C_NO_OID,
  745. &msg_ctx,
  746. &status_string
  747. );
  748. if (GSS_ERROR(maj_stat)) {
  749. break;
  750. }
  751. strncpy(buf_maj, (char*) status_string.value, sizeof(buf_maj));
  752. gss_release_buffer(&min_stat, &status_string);
  753. maj_stat = gss_display_status(
  754. &min_stat,
  755. err_min,
  756. GSS_C_MECH_CODE,
  757. GSS_C_NULL_OID,
  758. &msg_ctx,
  759. &status_string
  760. );
  761. if (! GSS_ERROR(maj_stat)) {
  762. strncpy(buf_min, (char*) status_string.value, sizeof(buf_min));
  763. gss_release_buffer(&min_stat, &status_string);
  764. }
  765. } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
  766. PyErr_SetObject(
  767. GssException_class,
  768. Py_BuildValue("((s:i)(s:i))", buf_maj, err_maj, buf_min, err_min)
  769. );
  770. }
  771. int authenticate_gss_server_store_delegate(gss_server_state *state)
  772. {
  773. gss_cred_id_t delegated_cred = state->client_creds;
  774. char *princ_name = state->username;
  775. OM_uint32 maj_stat, min_stat;
  776. krb5_principal princ = NULL;
  777. krb5_ccache ccache = NULL;
  778. krb5_error_code problem;
  779. krb5_context context;
  780. int ret = 500;
  781. if (delegated_cred == GSS_C_NO_CREDENTIAL){
  782. PyErr_SetObject(
  783. KrbException_class,
  784. Py_BuildValue("(s)", "Ticket is not delegatable")
  785. );
  786. return AUTH_GSS_ERROR;
  787. }
  788. problem = krb5_init_context(&context);
  789. if (problem) {
  790. PyErr_SetObject(
  791. KrbException_class,
  792. Py_BuildValue("(s)", "Cannot initialize krb5 context")
  793. );
  794. return AUTH_GSS_ERROR;
  795. }
  796. problem = krb5_parse_name(context, princ_name, &princ);
  797. if (problem) {
  798. PyErr_SetObject(
  799. KrbException_class,
  800. Py_BuildValue(
  801. "(s:s)", "Cannot parse delegated username",
  802. krb5_get_err_text(context, problem)
  803. )
  804. );
  805. ret = AUTH_GSS_ERROR;
  806. goto end;
  807. }
  808. problem = create_krb5_ccache(state, context, princ, &ccache);
  809. if (problem) {
  810. PyErr_SetObject(
  811. KrbException_class,
  812. Py_BuildValue(
  813. "(s:s)", "Error in creating krb5 cache",
  814. krb5_get_err_text(context, problem)
  815. )
  816. );
  817. ret = AUTH_GSS_ERROR;
  818. goto end;
  819. }
  820. maj_stat = gss_krb5_copy_ccache(&min_stat, delegated_cred, ccache);
  821. if (GSS_ERROR(maj_stat)) {
  822. set_gss_error(maj_stat, min_stat);
  823. ret = AUTH_GSS_ERROR;
  824. goto end;
  825. }
  826. krb5_cc_close(context, ccache);
  827. ccache = NULL;
  828. ret = 0;
  829. end:
  830. if (princ) {
  831. krb5_free_principal(context, princ);
  832. }
  833. if (ccache) {
  834. krb5_cc_destroy(context, ccache);
  835. }
  836. krb5_free_context(context);
  837. return ret;
  838. }
  839. int create_krb5_ccache(
  840. gss_server_state *state, krb5_context kcontext, krb5_principal princ,
  841. krb5_ccache *ccache
  842. ) {
  843. int fd;
  844. char ccname[32];
  845. krb5_error_code problem;
  846. int ret;
  847. krb5_ccache tmp_ccache = NULL;
  848. snprintf(ccname, sizeof(ccname), "/tmp/krb5cc_pyserv_XXXXXX");
  849. fd = mkstemp(ccname);
  850. if (fd < 0) {
  851. PyErr_SetObject(
  852. KrbException_class,
  853. Py_BuildValue("(s:s)", "Error in mkstemp", strerror(errno))
  854. );
  855. ret = 1;
  856. goto end;
  857. }
  858. close(fd);
  859. problem = krb5_cc_resolve(kcontext, ccname, &tmp_ccache);
  860. if (problem) {
  861. PyErr_SetObject(
  862. KrbException_class,
  863. Py_BuildValue(
  864. "(s:s)", "Error resolving the credential cache",
  865. krb5_get_err_text(kcontext, problem)
  866. )
  867. );
  868. ret = 1;
  869. unlink(ccname);
  870. goto end;
  871. }
  872. problem = krb5_cc_initialize(kcontext, tmp_ccache, princ);
  873. if (problem) {
  874. PyErr_SetObject(
  875. KrbException_class,
  876. Py_BuildValue(
  877. "(s:s)", "Error initialising the credential cache",
  878. krb5_get_err_text(kcontext, problem)
  879. )
  880. );
  881. ret = 1;
  882. goto end;
  883. }
  884. *ccache = tmp_ccache;
  885. tmp_ccache = NULL;
  886. ret = 0;
  887. end:
  888. if (tmp_ccache) {
  889. krb5_cc_destroy(kcontext, tmp_ccache);
  890. }
  891. state->ccname = (char *)malloc(32*sizeof(char));
  892. if (state->ccname == NULL) {
  893. PyErr_NoMemory();
  894. return 1;
  895. }
  896. strcpy(state->ccname, ccname);
  897. return ret;
  898. }