kerberosbasic.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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 "kerberosbasic.h"
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #undef PRINTFS
  22. extern PyObject *BasicAuthException_class;
  23. static void set_basicauth_error(krb5_context context, krb5_error_code code);
  24. static krb5_error_code verify_krb5_user(
  25. krb5_context context, krb5_principal principal, const char *password,
  26. krb5_principal server
  27. );
  28. int authenticate_user_krb5pwd(
  29. const char *user, const char *pswd, const char *service,
  30. const char *default_realm
  31. ) {
  32. krb5_context kcontext = NULL;
  33. krb5_error_code code;
  34. krb5_principal client = NULL;
  35. krb5_principal server = NULL;
  36. int ret = 0;
  37. char *name = NULL;
  38. char *p = NULL;
  39. code = krb5_init_context(&kcontext);
  40. if (code)
  41. {
  42. PyErr_SetObject(
  43. BasicAuthException_class,
  44. Py_BuildValue(
  45. "((s:i))", "Cannot initialize Kerberos5 context", code
  46. )
  47. );
  48. return 0;
  49. }
  50. ret = krb5_parse_name (kcontext, service, &server);
  51. if (ret) {
  52. set_basicauth_error(kcontext, ret);
  53. ret = 0;
  54. goto end;
  55. }
  56. code = krb5_unparse_name(kcontext, server, &name);
  57. if (code) {
  58. set_basicauth_error(kcontext, code);
  59. ret = 0;
  60. goto end;
  61. }
  62. #ifdef PRINTFS
  63. printf("Using %s as server principal for password verification\n", name);
  64. #endif
  65. free(name);
  66. name = NULL;
  67. name = (char *)malloc(256);
  68. if (name == NULL)
  69. {
  70. PyErr_NoMemory();
  71. ret = 0;
  72. goto end;
  73. }
  74. p = strchr(user, '@');
  75. if (p == NULL) {
  76. snprintf(name, 256, "%s@%s", user, default_realm);
  77. } else {
  78. snprintf(name, 256, "%s", user);
  79. }
  80. code = krb5_parse_name(kcontext, name, &client);
  81. if (code) {
  82. set_basicauth_error(kcontext, code);
  83. ret = 0;
  84. goto end;
  85. }
  86. code = verify_krb5_user(kcontext, client, pswd, server);
  87. if (code) {
  88. ret = 0;
  89. goto end;
  90. }
  91. ret = 1;
  92. end:
  93. #ifdef PRINTFS
  94. printf(
  95. "kerb_authenticate_user_krb5pwd ret=%d user=%s authtype=%s\n",
  96. ret, user, "Basic"
  97. );
  98. #endif
  99. if (name) {
  100. free(name);
  101. }
  102. if (client) {
  103. krb5_free_principal(kcontext, client);
  104. }
  105. if (server) {
  106. krb5_free_principal(kcontext, server);
  107. }
  108. krb5_free_context(kcontext);
  109. return ret;
  110. }
  111. /* Inspired by krb5_verify_user from Heimdal */
  112. static krb5_error_code verify_krb5_user(
  113. krb5_context context, krb5_principal principal, const char *password,
  114. krb5_principal server
  115. ) {
  116. krb5_creds creds;
  117. krb5_get_init_creds_opt gic_options;
  118. krb5_error_code ret;
  119. char *name = NULL;
  120. memset(&creds, 0, sizeof(creds));
  121. ret = krb5_unparse_name(context, principal, &name);
  122. if (ret == 0) {
  123. #ifdef PRINTFS
  124. printf("Trying to get TGT for user %s\n", name);
  125. #endif
  126. free(name);
  127. }
  128. krb5_get_init_creds_opt_init(&gic_options);
  129. ret = krb5_get_init_creds_password(
  130. context, &creds, principal, (char *)password,
  131. NULL, NULL, 0, NULL, &gic_options
  132. );
  133. if (ret) {
  134. set_basicauth_error(context, ret);
  135. goto end;
  136. }
  137. end:
  138. krb5_free_cred_contents(context, &creds);
  139. return ret;
  140. }
  141. static void set_basicauth_error(krb5_context context, krb5_error_code code)
  142. {
  143. PyErr_SetObject(
  144. BasicAuthException_class,
  145. Py_BuildValue("(s:i)", krb5_get_err_text(context, code), code)
  146. );
  147. }