Annotation of src/usr.bin/ssh/gss-serv.c, Revision 1.1
1.1 ! markus 1: /* $OpenBSD$ */
! 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: #include "includes.h"
! 28:
! 29: #ifdef GSSAPI
! 30:
! 31: #include "bufaux.h"
! 32: #include "compat.h"
! 33: #include "auth.h"
! 34: #include "log.h"
! 35: #include "channels.h"
! 36: #include "session.h"
! 37: #include "servconf.h"
! 38: #include "monitor_wrap.h"
! 39: #include "xmalloc.h"
! 40: #include "getput.h"
! 41:
! 42: #include "ssh-gss.h"
! 43:
! 44: extern ServerOptions options;
! 45:
! 46: static ssh_gssapi_client gssapi_client =
! 47: { GSS_C_EMPTY_BUFFER, GSS_C_EMPTY_BUFFER,
! 48: GSS_C_NO_CREDENTIAL, NULL, {NULL, NULL, NULL}};
! 49:
! 50: ssh_gssapi_mech gssapi_null_mech =
! 51: { NULL, NULL, {0, NULL}, NULL, NULL, NULL, NULL};
! 52:
! 53: #ifdef KRB5
! 54: extern ssh_gssapi_mech gssapi_kerberos_mech;
! 55: #endif
! 56:
! 57: ssh_gssapi_mech* supported_mechs[]= {
! 58: #ifdef KRB5
! 59: &gssapi_kerberos_mech,
! 60: #endif
! 61: &gssapi_null_mech,
! 62: };
! 63:
! 64: /* Unpriviledged */
! 65: void
! 66: ssh_gssapi_supported_oids(gss_OID_set *oidset)
! 67: {
! 68: int i = 0;
! 69: OM_uint32 min_status;
! 70: int present;
! 71: gss_OID_set supported;
! 72:
! 73: gss_create_empty_oid_set(&min_status, oidset);
! 74: gss_indicate_mechs(&min_status, &supported);
! 75:
! 76: while (supported_mechs[i]->name != NULL) {
! 77: if (GSS_ERROR(gss_test_oid_set_member(&min_status,
! 78: &supported_mechs[i]->oid, supported, &present)))
! 79: present = 0;
! 80: if (present)
! 81: gss_add_oid_set_member(&min_status,
! 82: &supported_mechs[i]->oid, oidset);
! 83: i++;
! 84: }
! 85: }
! 86:
! 87:
! 88: /* Wrapper around accept_sec_context
! 89: * Requires that the context contains:
! 90: * oid
! 91: * credentials (from ssh_gssapi_acquire_cred)
! 92: */
! 93: /* Priviledged */
! 94: OM_uint32
! 95: ssh_gssapi_accept_ctx(Gssctxt *ctx, gss_buffer_desc *recv_tok,
! 96: gss_buffer_desc *send_tok, OM_uint32 *flags)
! 97: {
! 98: OM_uint32 status;
! 99: gss_OID mech;
! 100:
! 101: ctx->major = gss_accept_sec_context(&ctx->minor,
! 102: &ctx->context, ctx->creds, recv_tok,
! 103: GSS_C_NO_CHANNEL_BINDINGS, &ctx->client, &mech,
! 104: send_tok, flags, NULL, &ctx->client_creds);
! 105:
! 106: if (GSS_ERROR(ctx->major))
! 107: ssh_gssapi_error(ctx);
! 108:
! 109: if (ctx->client_creds)
! 110: debug("Received some client credentials");
! 111: else
! 112: debug("Got no client credentials");
! 113:
! 114: status = ctx->major;
! 115:
! 116: /* Now, if we're complete and we have the right flags, then
! 117: * we flag the user as also having been authenticated
! 118: */
! 119:
! 120: if (((flags == NULL) || ((*flags & GSS_C_MUTUAL_FLAG) &&
! 121: (*flags & GSS_C_INTEG_FLAG))) && (ctx->major == GSS_S_COMPLETE)) {
! 122: if (ssh_gssapi_getclient(ctx, &gssapi_client))
! 123: fatal("Couldn't convert client name");
! 124: }
! 125:
! 126: return (status);
! 127: }
! 128:
! 129: /*
! 130: * This parses an exported name, extracting the mechanism specific portion
! 131: * to use for ACL checking. It verifies that the name belongs the mechanism
! 132: * originally selected.
! 133: */
! 134: static OM_uint32
! 135: ssh_gssapi_parse_ename(Gssctxt *ctx, gss_buffer_t ename, gss_buffer_t name)
! 136: {
! 137: char *tok;
! 138: OM_uint32 offset;
! 139: OM_uint32 oidl;
! 140:
! 141: tok=ename->value;
! 142:
! 143: /*
! 144: * Check that ename is long enough for all of the fixed length
! 145: * header, and that the initial ID bytes are correct
! 146: */
! 147:
! 148: if (ename->length<6 || memcmp(tok,"\x04\x01", 2)!=0)
! 149: return GSS_S_FAILURE;
! 150:
! 151: /*
! 152: * Extract the OID, and check it. Here GSSAPI breaks with tradition
! 153: * and does use the OID type and length bytes. To confuse things
! 154: * there are two lengths - the first including these, and the
! 155: * second without.
! 156: */
! 157:
! 158: oidl = GET_16BIT(tok+2); /* length including next two bytes */
! 159: oidl = oidl-2; /* turn it into the _real_ length of the variable OID */
! 160:
! 161: /*
! 162: * Check the BER encoding for correct type and length, that the
! 163: * string is long enough and that the OID matches that in our context
! 164: */
! 165: if (tok[4] != 0x06 || tok[5] != oidl ||
! 166: ename->length < oidl+6 ||
! 167: !ssh_gssapi_check_oid(ctx,tok+6,oidl))
! 168: return GSS_S_FAILURE;
! 169:
! 170: offset = oidl+6;
! 171:
! 172: if (ename->length < offset+4)
! 173: return GSS_S_FAILURE;
! 174:
! 175: name->length = GET_32BIT(tok+offset);
! 176: offset += 4;
! 177:
! 178: if (ename->length < offset+name->length)
! 179: return GSS_S_FAILURE;
! 180:
! 181: name->value = xmalloc(name->length);
! 182: memcpy(name->value,tok+offset,name->length);
! 183:
! 184: return GSS_S_COMPLETE;
! 185: }
! 186:
! 187: /* Extract the client details from a given context. This can only reliably
! 188: * be called once for a context */
! 189:
! 190: /* Priviledged (called from accept_secure_ctx) */
! 191: OM_uint32
! 192: ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
! 193: {
! 194: int i = 0;
! 195:
! 196: gss_buffer_desc ename;
! 197:
! 198: client->mech = NULL;
! 199:
! 200: while (supported_mechs[i]->name != NULL) {
! 201: if (supported_mechs[i]->oid.length == ctx->oid->length &&
! 202: (memcmp(supported_mechs[i]->oid.elements,
! 203: ctx->oid->elements, ctx->oid->length) == 0))
! 204: client->mech = supported_mechs[i];
! 205: i++;
! 206: }
! 207:
! 208: if (client->mech == NULL)
! 209: return GSS_S_FAILURE;
! 210:
! 211: if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
! 212: &client->displayname, NULL))) {
! 213: ssh_gssapi_error(ctx);
! 214: return (ctx->major);
! 215: }
! 216:
! 217: if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
! 218: &ename))) {
! 219: ssh_gssapi_error(ctx);
! 220: return (ctx->major);
! 221: }
! 222:
! 223: if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
! 224: &client->exportedname))) {
! 225: return (ctx->major);
! 226: }
! 227:
! 228: /* We can't copy this structure, so we just move the pointer to it */
! 229: client->creds = ctx->client_creds;
! 230: ctx->client_creds = GSS_C_NO_CREDENTIAL;
! 231: return (ctx->major);
! 232: }
! 233:
! 234: /* As user - called through fatal cleanup hook */
! 235: void
! 236: ssh_gssapi_cleanup_creds(void *ignored)
! 237: {
! 238: if (gssapi_client.store.filename != NULL) {
! 239: /* Unlink probably isn't sufficient */
! 240: debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename);
! 241: unlink(gssapi_client.store.filename);
! 242: }
! 243: }
! 244:
! 245: /* As user */
! 246: void
! 247: ssh_gssapi_storecreds(void)
! 248: {
! 249: if (gssapi_client.mech && gssapi_client.mech->storecreds) {
! 250: (*gssapi_client.mech->storecreds)(&gssapi_client);
! 251: if (options.gss_cleanup_creds)
! 252: fatal_add_cleanup(ssh_gssapi_cleanup_creds, NULL);
! 253: } else
! 254: debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
! 255: }
! 256:
! 257: /* This allows GSSAPI methods to do things to the childs environment based
! 258: * on the passed authentication process and credentials.
! 259: */
! 260: /* As user */
! 261: void
! 262: ssh_gssapi_do_child(char ***envp, u_int *envsizep)
! 263: {
! 264:
! 265: if (gssapi_client.store.envvar != NULL &&
! 266: gssapi_client.store.envval != NULL) {
! 267:
! 268: debug("Setting %s to %s", gssapi_client.store.envvar,
! 269: gssapi_client.store.envval);
! 270: child_set_env(envp, envsizep, gssapi_client.store.envvar,
! 271: gssapi_client.store.envval);
! 272: }
! 273: }
! 274:
! 275: /* Priviledged */
! 276: int
! 277: ssh_gssapi_userok(char *user)
! 278: {
! 279: if (gssapi_client.exportedname.length == 0 ||
! 280: gssapi_client.exportedname.value == NULL) {
! 281: debug("No suitable client data");
! 282: return 0;
! 283: }
! 284: if (gssapi_client.mech && gssapi_client.mech->userok)
! 285: return ((*gssapi_client.mech->userok)(&gssapi_client, user));
! 286: else
! 287: debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
! 288: return (0);
! 289: }
! 290:
! 291: #endif