auth2-gss.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /* $OpenBSD: auth2-gss.c,v 1.29 2018/07/31 03:10:27 djm Exp $ */
  2. /*
  3. * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions
  7. * are met:
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
  15. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  16. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  17. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  18. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  19. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  23. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "includes.h"
  26. #ifdef GSSAPI
  27. #include <sys/types.h>
  28. #include <stdarg.h>
  29. #include "xmalloc.h"
  30. #include "sshkey.h"
  31. #include "hostfile.h"
  32. #include "auth.h"
  33. #include "ssh2.h"
  34. #include "log.h"
  35. #include "dispatch.h"
  36. #include "sshbuf.h"
  37. #include "ssherr.h"
  38. #include "misc.h"
  39. #include "servconf.h"
  40. #include "packet.h"
  41. #include "kex.h"
  42. #include "ssh-gss.h"
  43. #include "monitor_wrap.h"
  44. extern ServerOptions options;
  45. static int input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh);
  46. static int input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh);
  47. static int input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh);
  48. static int input_gssapi_errtok(int, u_int32_t, struct ssh *);
  49. /*
  50. * We only support those mechanisms that we know about (ie ones that we know
  51. * how to check local user kuserok and the like)
  52. */
  53. static int
  54. userauth_gssapi(struct ssh *ssh)
  55. {
  56. Authctxt *authctxt = ssh->authctxt;
  57. gss_OID_desc goid = {0, NULL};
  58. Gssctxt *ctxt = NULL;
  59. int r, present;
  60. u_int mechs;
  61. OM_uint32 ms;
  62. size_t len;
  63. u_char *doid = NULL;
  64. if ((r = sshpkt_get_u32(ssh, &mechs)) != 0)
  65. fatal("%s: %s", __func__, ssh_err(r));
  66. if (mechs == 0) {
  67. debug("Mechanism negotiation is not supported");
  68. return (0);
  69. }
  70. do {
  71. mechs--;
  72. free(doid);
  73. present = 0;
  74. if ((r = sshpkt_get_string(ssh, &doid, &len)) != 0)
  75. fatal("%s: %s", __func__, ssh_err(r));
  76. if (len > 2 && doid[0] == SSH_GSS_OIDTYPE &&
  77. doid[1] == len - 2) {
  78. goid.elements = doid + 2;
  79. goid.length = len - 2;
  80. ssh_gssapi_test_oid_supported(&ms, &goid, &present);
  81. } else {
  82. logit("Badly formed OID received");
  83. }
  84. } while (mechs > 0 && !present);
  85. if (!present) {
  86. free(doid);
  87. authctxt->server_caused_failure = 1;
  88. return (0);
  89. }
  90. if (!authctxt->valid || authctxt->user == NULL) {
  91. debug2("%s: disabled because of invalid user", __func__);
  92. free(doid);
  93. return (0);
  94. }
  95. if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
  96. if (ctxt != NULL)
  97. ssh_gssapi_delete_ctx(&ctxt);
  98. free(doid);
  99. authctxt->server_caused_failure = 1;
  100. return (0);
  101. }
  102. authctxt->methoddata = (void *)ctxt;
  103. /* Return the OID that we received */
  104. if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE)) != 0 ||
  105. (r = sshpkt_put_string(ssh, doid, len)) != 0 ||
  106. (r = sshpkt_send(ssh)) != 0)
  107. fatal("%s: %s", __func__, ssh_err(r));
  108. free(doid);
  109. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
  110. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
  111. authctxt->postponed = 1;
  112. return (0);
  113. }
  114. static int
  115. input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh)
  116. {
  117. Authctxt *authctxt = ssh->authctxt;
  118. Gssctxt *gssctxt;
  119. gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
  120. gss_buffer_desc recv_tok;
  121. OM_uint32 maj_status, min_status, flags;
  122. u_char *p;
  123. size_t len;
  124. int r;
  125. if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
  126. fatal("No authentication or GSSAPI context");
  127. gssctxt = authctxt->methoddata;
  128. if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
  129. (r = sshpkt_get_end(ssh)) != 0)
  130. fatal("%s: %s", __func__, ssh_err(r));
  131. recv_tok.value = p;
  132. recv_tok.length = len;
  133. maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
  134. &send_tok, &flags));
  135. free(p);
  136. if (GSS_ERROR(maj_status)) {
  137. if (send_tok.length != 0) {
  138. if ((r = sshpkt_start(ssh,
  139. SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 ||
  140. (r = sshpkt_put_string(ssh, send_tok.value,
  141. send_tok.length)) != 0 ||
  142. (r = sshpkt_send(ssh)) != 0)
  143. fatal("%s: %s", __func__, ssh_err(r));
  144. }
  145. authctxt->postponed = 0;
  146. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
  147. userauth_finish(ssh, 0, "gssapi-with-mic", NULL);
  148. } else {
  149. if (send_tok.length != 0) {
  150. if ((r = sshpkt_start(ssh,
  151. SSH2_MSG_USERAUTH_GSSAPI_TOKEN)) != 0 ||
  152. (r = sshpkt_put_string(ssh, send_tok.value,
  153. send_tok.length)) != 0 ||
  154. (r = sshpkt_send(ssh)) != 0)
  155. fatal("%s: %s", __func__, ssh_err(r));
  156. }
  157. if (maj_status == GSS_S_COMPLETE) {
  158. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
  159. if (flags & GSS_C_INTEG_FLAG)
  160. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC,
  161. &input_gssapi_mic);
  162. else
  163. ssh_dispatch_set(ssh,
  164. SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
  165. &input_gssapi_exchange_complete);
  166. }
  167. }
  168. gss_release_buffer(&min_status, &send_tok);
  169. return 0;
  170. }
  171. static int
  172. input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh)
  173. {
  174. Authctxt *authctxt = ssh->authctxt;
  175. Gssctxt *gssctxt;
  176. gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
  177. gss_buffer_desc recv_tok;
  178. OM_uint32 maj_status;
  179. int r;
  180. u_char *p;
  181. size_t len;
  182. if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
  183. fatal("No authentication or GSSAPI context");
  184. gssctxt = authctxt->methoddata;
  185. if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 ||
  186. (r = sshpkt_get_end(ssh)) != 0)
  187. fatal("%s: %s", __func__, ssh_err(r));
  188. recv_tok.value = p;
  189. recv_tok.length = len;
  190. /* Push the error token into GSSAPI to see what it says */
  191. maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok,
  192. &send_tok, NULL));
  193. free(recv_tok.value);
  194. /* We can't return anything to the client, even if we wanted to */
  195. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
  196. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
  197. /* The client will have already moved on to the next auth */
  198. gss_release_buffer(&maj_status, &send_tok);
  199. return 0;
  200. }
  201. /*
  202. * This is called when the client thinks we've completed authentication.
  203. * It should only be enabled in the dispatch handler by the function above,
  204. * which only enables it once the GSSAPI exchange is complete.
  205. */
  206. static int
  207. input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh)
  208. {
  209. Authctxt *authctxt = ssh->authctxt;
  210. int r, authenticated;
  211. const char *displayname;
  212. if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
  213. fatal("No authentication or GSSAPI context");
  214. /*
  215. * We don't need to check the status, because we're only enabled in
  216. * the dispatcher once the exchange is complete
  217. */
  218. if ((r = sshpkt_get_end(ssh)) != 0)
  219. fatal("%s: %s", __func__, ssh_err(r));
  220. authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
  221. if ((!use_privsep || mm_is_monitor()) &&
  222. (displayname = ssh_gssapi_displayname()) != NULL)
  223. auth2_record_info(authctxt, "%s", displayname);
  224. authctxt->postponed = 0;
  225. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
  226. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
  227. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
  228. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
  229. userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL);
  230. return 0;
  231. }
  232. static int
  233. input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh)
  234. {
  235. Authctxt *authctxt = ssh->authctxt;
  236. Gssctxt *gssctxt;
  237. int r, authenticated = 0;
  238. char *micuser;
  239. struct sshbuf *b;
  240. gss_buffer_desc mic, gssbuf;
  241. const char *displayname;
  242. u_char *p;
  243. size_t len;
  244. if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep))
  245. fatal("No authentication or GSSAPI context");
  246. gssctxt = authctxt->methoddata;
  247. if ((r = sshpkt_get_string(ssh, &p, &len)) != 0)
  248. fatal("%s: %s", __func__, ssh_err(r));
  249. if ((b = sshbuf_new()) == NULL)
  250. fatal("%s: sshbuf_new failed", __func__);
  251. mic.value = p;
  252. mic.length = len;
  253. #ifdef WITH_SELINUX
  254. if (authctxt->role && authctxt->role[0] != 0)
  255. xasprintf(&micuser, "%s/%s", authctxt->user, authctxt->role);
  256. else
  257. #endif
  258. micuser = authctxt->user;
  259. ssh_gssapi_buildmic(b, micuser, authctxt->service,
  260. "gssapi-with-mic", ssh->kex->session_id);
  261. if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL)
  262. fatal("%s: sshbuf_mutable_ptr failed", __func__);
  263. gssbuf.length = sshbuf_len(b);
  264. if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic))))
  265. authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user));
  266. else
  267. logit("GSSAPI MIC check failed");
  268. sshbuf_free(b);
  269. if (micuser != authctxt->user)
  270. free(micuser);
  271. free(mic.value);
  272. if ((!use_privsep || mm_is_monitor()) &&
  273. (displayname = ssh_gssapi_displayname()) != NULL)
  274. auth2_record_info(authctxt, "%s", displayname);
  275. authctxt->postponed = 0;
  276. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
  277. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
  278. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
  279. ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
  280. userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL);
  281. return 0;
  282. }
  283. Authmethod method_gssapi = {
  284. "gssapi-with-mic",
  285. userauth_gssapi,
  286. &options.gss_authentication
  287. };
  288. #endif /* GSSAPI */