TDE base libraries and programs
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
5.5KB

  1. /*
  2. * Copyright (C) 1998 Caldera, Inc.
  3. * Copyright (C) 2003 Oswald Buddenhagen <ossi@kde.org>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public
  7. * License as published by the Free Software Foundation; either
  8. * version 2 of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  13. * General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public
  16. * License along with this program; if not, write to the Free
  17. * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18. */
  19. #include "kcheckpass.h"
  20. #ifdef HAVE_PAM
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <syslog.h>
  25. #ifdef HAVE_PAM_PAM_APPL_H
  26. #include <pam/pam_appl.h>
  27. #else
  28. #include <security/pam_appl.h>
  29. #endif
  30. struct pam_data {
  31. char *(*conv) (ConvRequest, const char *);
  32. int abort:1;
  33. int classic:1;
  34. };
  35. #ifdef PAM_MESSAGE_NONCONST
  36. typedef struct pam_message pam_message_type;
  37. typedef void *pam_gi_type;
  38. #else
  39. typedef const struct pam_message pam_message_type;
  40. typedef const void *pam_gi_type;
  41. #endif
  42. static int
  43. PAM_conv (int num_msg, pam_message_type **msg,
  44. struct pam_response **resp,
  45. void *appdata_ptr)
  46. {
  47. int count;
  48. struct pam_response *repl;
  49. struct pam_data *pd = (struct pam_data *)appdata_ptr;
  50. if (!(repl = calloc(num_msg, sizeof(struct pam_response))))
  51. return PAM_CONV_ERR;
  52. for (count = 0; count < num_msg; count++)
  53. switch (msg[count]->msg_style) {
  54. case PAM_TEXT_INFO:
  55. pd->conv(ConvPutInfo, msg[count]->msg);
  56. break;
  57. case PAM_ERROR_MSG:
  58. pd->conv(ConvPutError, msg[count]->msg);
  59. break;
  60. default:
  61. switch (msg[count]->msg_style) {
  62. case PAM_PROMPT_ECHO_ON:
  63. repl[count].resp = pd->conv(ConvGetNormal, msg[count]->msg);
  64. break;
  65. case PAM_PROMPT_ECHO_OFF:
  66. if (pd->classic) {
  67. // WARNING
  68. // This is far from foolproof, but it's the best we can do at this time...
  69. // Try to detect PIN entry requests
  70. if (strstr(msg[count]->msg, "PIN")) {
  71. repl[count].resp = pd->conv(ConvGetHidden, msg[count]->msg);
  72. }
  73. else {
  74. repl[count].resp = pd->conv(ConvGetHidden, 0);
  75. }
  76. }
  77. else {
  78. repl[count].resp = pd->conv(ConvGetHidden, msg[count]->msg);
  79. }
  80. break;
  81. #ifdef PAM_BINARY_PROMPT
  82. case PAM_BINARY_PROMPT:
  83. repl[count].resp = pd->conv(ConvGetBinary, msg[count]->msg);
  84. break;
  85. #endif
  86. default:
  87. /* Must be an error of some sort... */
  88. goto conv_err;
  89. }
  90. if (!repl[count].resp) {
  91. pd->abort = 1;
  92. goto conv_err;
  93. }
  94. repl[count].resp_retcode = PAM_SUCCESS;
  95. break;
  96. }
  97. *resp = repl;
  98. return PAM_SUCCESS;
  99. conv_err:
  100. for (; count >= 0; count--)
  101. if (repl[count].resp)
  102. switch (msg[count]->msg_style) {
  103. case PAM_PROMPT_ECHO_OFF:
  104. dispose(repl[count].resp);
  105. break;
  106. #ifdef PAM_BINARY_PROMPT
  107. case PAM_BINARY_PROMPT: /* handle differently? */
  108. #endif
  109. case PAM_PROMPT_ECHO_ON:
  110. free(repl[count].resp);
  111. break;
  112. }
  113. free(repl);
  114. return PAM_CONV_ERR;
  115. }
  116. static struct pam_data PAM_data;
  117. static struct pam_conv PAM_conversation = {
  118. &PAM_conv,
  119. &PAM_data
  120. };
  121. #ifdef PAM_FAIL_DELAY
  122. static void
  123. fail_delay(int retval ATTR_UNUSED, unsigned usec_delay ATTR_UNUSED,
  124. void *appdata_ptr ATTR_UNUSED)
  125. {}
  126. #endif
  127. AuthReturn Authenticate(const char *caller, const char *method,
  128. const char *user, char *(*conv) (ConvRequest, const char *))
  129. {
  130. const char *tty;
  131. pam_handle_t *pamh;
  132. pam_gi_type pam_item;
  133. const char *pam_service;
  134. char pservb[64];
  135. int pam_error;
  136. openlog("kcheckpass", LOG_PID, LOG_AUTH);
  137. PAM_data.conv = conv;
  138. if (!strcmp(method, "classic")) {
  139. PAM_data.classic = 1;
  140. pam_service = caller;
  141. }
  142. else if (!strcmp(method, "pam")) {
  143. pam_service = caller;
  144. } else {
  145. sprintf(pservb, "%.31s-%.31s", caller, method);
  146. pam_service = pservb;
  147. }
  148. pam_error = pam_start(pam_service, user, &PAM_conversation, &pamh);
  149. if (pam_error != PAM_SUCCESS)
  150. return AuthError;
  151. tty = ttyname(0);
  152. if (!tty)
  153. tty = getenv ("DISPLAY");
  154. pam_error = pam_set_item (pamh, PAM_TTY, tty);
  155. if (pam_error != PAM_SUCCESS) {
  156. pam_end(pamh, pam_error);
  157. return AuthError;
  158. }
  159. # ifdef PAM_FAIL_DELAY
  160. pam_set_item (pamh, PAM_FAIL_DELAY, (void *)fail_delay);
  161. # endif
  162. pam_error = pam_authenticate(pamh, 0);
  163. if (pam_error != PAM_SUCCESS) {
  164. pam_end(pamh, pam_error);
  165. switch (pam_error) {
  166. case PAM_USER_UNKNOWN:
  167. case PAM_AUTH_ERR:
  168. case PAM_MAXTRIES: /* should handle this better ... */
  169. case PAM_AUTHINFO_UNAVAIL: /* returned for unknown users ... bogus */
  170. return AuthBad;
  171. case PAM_SERVICE_ERR:
  172. return AuthError;
  173. default:
  174. return AuthError;
  175. }
  176. }
  177. /* just in case some module is stupid enough to ignore a preset PAM_USER */
  178. pam_error = pam_get_item (pamh, PAM_USER, &pam_item);
  179. if (pam_error != PAM_SUCCESS) {
  180. pam_end(pamh, pam_error);
  181. return AuthError;
  182. }
  183. if (strcmp((const char *)pam_item, user)) {
  184. pam_end(pamh, PAM_SUCCESS); /* maybe use PAM_AUTH_ERR? */
  185. return AuthBad;
  186. }
  187. pam_error = pam_setcred(pamh, PAM_REFRESH_CRED);
  188. /* ignore errors on refresh credentials. If this did not work we use the old once. */
  189. pam_end(pamh, PAM_SUCCESS);
  190. return AuthOk;
  191. }
  192. #endif