kerberospw.c 4.3 KB

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