auth2-gss.c revision 1.27
1/* $OpenBSD: auth2-gss.c,v 1.27 2018/07/09 21:37:55 markus 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 (!authctxt->valid || authctxt->user == NULL) 69 return (0); 70 71 if ((r = sshpkt_get_u32(ssh, &mechs)) != 0) 72 fatal("%s: %s", __func__, ssh_err(r)); 73 74 if (mechs == 0) { 75 debug("Mechanism negotiation is not supported"); 76 return (0); 77 } 78 79 do { 80 mechs--; 81 82 free(doid); 83 84 present = 0; 85 if ((r = sshpkt_get_string(ssh, &doid, &len)) != 0) 86 fatal("%s: %s", __func__, ssh_err(r)); 87 88 if (len > 2 && doid[0] == SSH_GSS_OIDTYPE && 89 doid[1] == len - 2) { 90 goid.elements = doid + 2; 91 goid.length = len - 2; 92 ssh_gssapi_test_oid_supported(&ms, &goid, &present); 93 } else { 94 logit("Badly formed OID received"); 95 } 96 } while (mechs > 0 && !present); 97 98 if (!present) { 99 free(doid); 100 authctxt->server_caused_failure = 1; 101 return (0); 102 } 103 104 if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) { 105 if (ctxt != NULL) 106 ssh_gssapi_delete_ctx(&ctxt); 107 free(doid); 108 authctxt->server_caused_failure = 1; 109 return (0); 110 } 111 112 authctxt->methoddata = (void *)ctxt; 113 114 /* Return the OID that we received */ 115 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_GSSAPI_RESPONSE)) != 0 || 116 (r = sshpkt_put_string(ssh, doid, len)) != 0 || 117 (r = sshpkt_send(ssh)) != 0) 118 fatal("%s: %s", __func__, ssh_err(r)); 119 120 free(doid); 121 122 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 123 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 124 authctxt->postponed = 1; 125 126 return (0); 127} 128 129static int 130input_gssapi_token(int type, u_int32_t plen, struct ssh *ssh) 131{ 132 Authctxt *authctxt = ssh->authctxt; 133 Gssctxt *gssctxt; 134 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 135 gss_buffer_desc recv_tok; 136 OM_uint32 maj_status, min_status, flags; 137 u_char *p; 138 size_t len; 139 int r; 140 141 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 142 fatal("No authentication or GSSAPI context"); 143 144 gssctxt = authctxt->methoddata; 145 if ((r = sshpkt_get_string(ssh, &p, &len)) != 0 || 146 (r = sshpkt_get_end(ssh)) != 0) 147 fatal("%s: %s", __func__, ssh_err(r)); 148 149 recv_tok.value = p; 150 recv_tok.length = len; 151 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 152 &send_tok, &flags)); 153 154 free(p); 155 156 if (GSS_ERROR(maj_status)) { 157 if (send_tok.length != 0) { 158 if ((r = sshpkt_start(ssh, 159 SSH2_MSG_USERAUTH_GSSAPI_ERRTOK)) != 0 || 160 (r = sshpkt_put_string(ssh, send_tok.value, 161 send_tok.length)) != 0 || 162 (r = sshpkt_send(ssh)) != 0) 163 fatal("%s: %s", __func__, ssh_err(r)); 164 } 165 authctxt->postponed = 0; 166 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 167 userauth_finish(ssh, 0, "gssapi-with-mic", NULL); 168 } else { 169 if (send_tok.length != 0) { 170 if ((r = sshpkt_start(ssh, 171 SSH2_MSG_USERAUTH_GSSAPI_TOKEN)) != 0 || 172 (r = sshpkt_put_string(ssh, send_tok.value, 173 send_tok.length)) != 0 || 174 (r = sshpkt_send(ssh)) != 0) 175 fatal("%s: %s", __func__, ssh_err(r)); 176 } 177 if (maj_status == GSS_S_COMPLETE) { 178 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 179 if (flags & GSS_C_INTEG_FLAG) 180 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, 181 &input_gssapi_mic); 182 else 183 ssh_dispatch_set(ssh, 184 SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, 185 &input_gssapi_exchange_complete); 186 } 187 } 188 189 gss_release_buffer(&min_status, &send_tok); 190 return 0; 191} 192 193static int 194input_gssapi_errtok(int type, u_int32_t plen, struct ssh *ssh) 195{ 196 Authctxt *authctxt = ssh->authctxt; 197 Gssctxt *gssctxt; 198 gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER; 199 gss_buffer_desc recv_tok; 200 OM_uint32 maj_status; 201 int r; 202 203 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 204 fatal("No authentication or GSSAPI context"); 205 206 gssctxt = authctxt->methoddata; 207 if ((r = sshpkt_get_string(ssh, 208 &recv_tok.value, &recv_tok.length)) != 0 || 209 (r = sshpkt_get_end(ssh)) != 0) 210 fatal("%s: %s", __func__, ssh_err(r)); 211 212 /* Push the error token into GSSAPI to see what it says */ 213 maj_status = PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 214 &send_tok, NULL)); 215 216 free(recv_tok.value); 217 218 /* We can't return anything to the client, even if we wanted to */ 219 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 220 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 221 222 /* The client will have already moved on to the next auth */ 223 224 gss_release_buffer(&maj_status, &send_tok); 225 return 0; 226} 227 228/* 229 * This is called when the client thinks we've completed authentication. 230 * It should only be enabled in the dispatch handler by the function above, 231 * which only enables it once the GSSAPI exchange is complete. 232 */ 233 234static int 235input_gssapi_exchange_complete(int type, u_int32_t plen, struct ssh *ssh) 236{ 237 Authctxt *authctxt = ssh->authctxt; 238 int authenticated; 239 const char *displayname; 240 241 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 242 fatal("No authentication or GSSAPI context"); 243 244 /* 245 * We don't need to check the status, because we're only enabled in 246 * the dispatcher once the exchange is complete 247 */ 248 249 if ((r = sshpkt_get_end(ssh)) != 0) 250 fatal("%s: %s", __func__, ssh_err(r)); 251 252 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 253 254 if ((!use_privsep || mm_is_monitor()) && 255 (displayname = ssh_gssapi_displayname()) != NULL) 256 auth2_record_info(authctxt, "%s", displayname); 257 258 authctxt->postponed = 0; 259 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 260 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 261 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 262 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 263 userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL); 264 return 0; 265} 266 267static int 268input_gssapi_mic(int type, u_int32_t plen, struct ssh *ssh) 269{ 270 Authctxt *authctxt = ssh->authctxt; 271 Gssctxt *gssctxt; 272 int r, authenticated = 0; 273 struct sshbuf *b; 274 gss_buffer_desc mic, gssbuf; 275 const char *displayname; 276 277 if (authctxt == NULL || (authctxt->methoddata == NULL && !use_privsep)) 278 fatal("No authentication or GSSAPI context"); 279 280 gssctxt = authctxt->methoddata; 281 282 if ((r = sshpkt_get_string(ssh, &mic.value, &mic.length)) != 0) 283 fatal("%s: %s", __func__, ssh_err(r)); 284 if ((b = sshbuf_new()) == NULL) 285 fatal("%s: sshbuf_new failed", __func__); 286 ssh_gssapi_buildmic(b, authctxt->user, authctxt->service, 287 "gssapi-with-mic"); 288 289 if ((gssbuf.value = sshbuf_mutable_ptr(b)) == NULL) 290 fatal("%s: sshbuf_mutable_ptr failed", __func__); 291 gssbuf.length = sshbuf_len(b); 292 293 if (!GSS_ERROR(PRIVSEP(ssh_gssapi_checkmic(gssctxt, &gssbuf, &mic)))) 294 authenticated = PRIVSEP(ssh_gssapi_userok(authctxt->user)); 295 else 296 logit("GSSAPI MIC check failed"); 297 298 sshbuf_free(b); 299 free(mic.value); 300 301 if ((!use_privsep || mm_is_monitor()) && 302 (displayname = ssh_gssapi_displayname()) != NULL) 303 auth2_record_info(authctxt, "%s", displayname); 304 305 authctxt->postponed = 0; 306 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 307 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 308 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 309 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 310 userauth_finish(ssh, authenticated, "gssapi-with-mic", NULL); 311 return 0; 312} 313 314Authmethod method_gssapi = { 315 "gssapi-with-mic", 316 userauth_gssapi, 317 &options.gss_authentication 318}; 319#endif 320