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