~ubuntu-branches/ubuntu/edgy/openssh/edgy

« back to all changes in this revision

Viewing changes to gss-serv.c

  • Committer: Bazaar Package Importer
  • Author(s): Noah Meyerhans
  • Date: 2006-10-31 17:53:38 UTC
  • Revision ID: james.westby@ubuntu.com-20061031175338-kh299ada2qc2kzlb
Tags: upstream-3.8.1p1
ImportĀ upstreamĀ versionĀ 3.8.1p1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*      $OpenBSD: gss-serv.c,v 1.5 2003/11/17 11:06:07 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
#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+1);
 
182
        memcpy(name->value,tok+offset,name->length);
 
183
        ((char *)name->value)[name->length] = 0;
 
184
 
 
185
        return GSS_S_COMPLETE;
 
186
}
 
187
 
 
188
/* Extract the client details from a given context. This can only reliably
 
189
 * be called once for a context */
 
190
 
 
191
/* Priviledged (called from accept_secure_ctx) */
 
192
OM_uint32
 
193
ssh_gssapi_getclient(Gssctxt *ctx, ssh_gssapi_client *client)
 
194
{
 
195
        int i = 0;
 
196
 
 
197
        gss_buffer_desc ename;
 
198
 
 
199
        client->mech = NULL;
 
200
 
 
201
        while (supported_mechs[i]->name != NULL) {
 
202
                if (supported_mechs[i]->oid.length == ctx->oid->length &&
 
203
                    (memcmp(supported_mechs[i]->oid.elements,
 
204
                    ctx->oid->elements, ctx->oid->length) == 0))
 
205
                        client->mech = supported_mechs[i];
 
206
                i++;
 
207
        }
 
208
 
 
209
        if (client->mech == NULL)
 
210
                return GSS_S_FAILURE;
 
211
 
 
212
        if ((ctx->major = gss_display_name(&ctx->minor, ctx->client,
 
213
            &client->displayname, NULL))) {
 
214
                ssh_gssapi_error(ctx);
 
215
                return (ctx->major);
 
216
        }
 
217
 
 
218
        if ((ctx->major = gss_export_name(&ctx->minor, ctx->client,
 
219
            &ename))) {
 
220
                ssh_gssapi_error(ctx);
 
221
                return (ctx->major);
 
222
        }
 
223
 
 
224
        if ((ctx->major = ssh_gssapi_parse_ename(ctx,&ename,
 
225
            &client->exportedname))) {
 
226
                return (ctx->major);
 
227
        }
 
228
 
 
229
        /* We can't copy this structure, so we just move the pointer to it */
 
230
        client->creds = ctx->client_creds;
 
231
        ctx->client_creds = GSS_C_NO_CREDENTIAL;
 
232
        return (ctx->major);
 
233
}
 
234
 
 
235
/* As user - called on fatal/exit */
 
236
void
 
237
ssh_gssapi_cleanup_creds(void)
 
238
{
 
239
        if (gssapi_client.store.filename != NULL) {
 
240
                /* Unlink probably isn't sufficient */
 
241
                debug("removing gssapi cred file\"%s\"", gssapi_client.store.filename);
 
242
                unlink(gssapi_client.store.filename);
 
243
        }
 
244
}
 
245
 
 
246
/* As user */
 
247
void
 
248
ssh_gssapi_storecreds(void)
 
249
{
 
250
        if (gssapi_client.mech && gssapi_client.mech->storecreds) {
 
251
                (*gssapi_client.mech->storecreds)(&gssapi_client);
 
252
        } else
 
253
                debug("ssh_gssapi_storecreds: Not a GSSAPI mechanism");
 
254
}
 
255
 
 
256
/* This allows GSSAPI methods to do things to the childs environment based
 
257
 * on the passed authentication process and credentials.
 
258
 */
 
259
/* As user */
 
260
void
 
261
ssh_gssapi_do_child(char ***envp, u_int *envsizep)
 
262
{
 
263
 
 
264
        if (gssapi_client.store.envvar != NULL &&
 
265
            gssapi_client.store.envval != NULL) {
 
266
 
 
267
                debug("Setting %s to %s", gssapi_client.store.envvar,
 
268
                gssapi_client.store.envval);
 
269
                child_set_env(envp, envsizep, gssapi_client.store.envvar,
 
270
                     gssapi_client.store.envval);
 
271
        }
 
272
}
 
273
 
 
274
/* Priviledged */
 
275
int
 
276
ssh_gssapi_userok(char *user)
 
277
{
 
278
        if (gssapi_client.exportedname.length == 0 ||
 
279
            gssapi_client.exportedname.value == NULL) {
 
280
                debug("No suitable client data");
 
281
                return 0;
 
282
        }
 
283
        if (gssapi_client.mech && gssapi_client.mech->userok)
 
284
                return ((*gssapi_client.mech->userok)(&gssapi_client, user));
 
285
        else
 
286
                debug("ssh_gssapi_userok: Unknown GSSAPI mechanism");
 
287
        return (0);
 
288
}
 
289
 
 
290
/* Priviledged */
 
291
OM_uint32
 
292
ssh_gssapi_checkmic(Gssctxt *ctx, gss_buffer_t gssbuf, gss_buffer_t gssmic)
 
293
{
 
294
        ctx->major = gss_verify_mic(&ctx->minor, ctx->context,
 
295
            gssbuf, gssmic, NULL);
 
296
 
 
297
        return (ctx->major);
 
298
}
 
299
 
 
300
#endif