1 | /* |
---|
2 | * Copyright (c) 2001,2002 Simon Wilkinson. All rights reserved. * |
---|
3 | * Redistribution and use in source and binary forms, with or without |
---|
4 | * modification, are permitted provided that the following conditions |
---|
5 | * are met: |
---|
6 | * 1. Redistributions of source code must retain the above copyright |
---|
7 | * notice, this list of conditions and the following disclaimer. |
---|
8 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
9 | * notice, this list of conditions and the following disclaimer in the |
---|
10 | * documentation and/or other materials provided with the distribution. |
---|
11 | * |
---|
12 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR |
---|
13 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
14 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
15 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
16 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
17 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
18 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
19 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
20 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
21 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
22 | */ |
---|
23 | |
---|
24 | #include "includes.h" |
---|
25 | |
---|
26 | #ifdef GSSAPI |
---|
27 | |
---|
28 | #include "ssh.h" |
---|
29 | #include "ssh2.h" |
---|
30 | #include "xmalloc.h" |
---|
31 | #include "buffer.h" |
---|
32 | #include "bufaux.h" |
---|
33 | #include "packet.h" |
---|
34 | #include "compat.h" |
---|
35 | #include <openssl/evp.h> |
---|
36 | #include "cipher.h" |
---|
37 | #include "kex.h" |
---|
38 | #include "log.h" |
---|
39 | #include "compat.h" |
---|
40 | #include "monitor_wrap.h" |
---|
41 | |
---|
42 | #include <netdb.h> |
---|
43 | |
---|
44 | #include "ssh-gss.h" |
---|
45 | |
---|
46 | /* Assorted globals for tracking the clients identity once they've |
---|
47 | * authenticated */ |
---|
48 | |
---|
49 | gss_buffer_desc gssapi_client_name = {0,NULL}; /* Name of our client */ |
---|
50 | gss_cred_id_t gssapi_client_creds = GSS_C_NO_CREDENTIAL; /* Their credentials */ |
---|
51 | enum ssh_gss_id gssapi_client_type = GSS_LAST_ENTRY; |
---|
52 | |
---|
53 | /* The mechanism name used in the list below is defined in the internet |
---|
54 | * draft as the Base 64 encoding of the MD5 hash of the ASN.1 DER encoding |
---|
55 | * of the underlying GSSAPI mechanism's OID. |
---|
56 | * |
---|
57 | * Also from the draft, before considering adding SPNEGO, bear in mind that |
---|
58 | * "mechanisms ... MUST NOT use SPNEGO as the underlying GSSAPI mechanism" |
---|
59 | */ |
---|
60 | |
---|
61 | /* These must be in the same order as ssh_gss_id, in ssh-gss.h */ |
---|
62 | |
---|
63 | ssh_gssapi_mech supported_mechs[]= { |
---|
64 | #ifdef KRB5 |
---|
65 | /* Official OID - 1.2.850.113554.1.2.2 */ |
---|
66 | {"Se3H81ismmOC3OE+FwYCiQ==","Kerberos", |
---|
67 | {9, "\x2A\x86\x48\x86\xF7\x12\x01\x02\x02"}}, |
---|
68 | #endif |
---|
69 | #ifdef GSI |
---|
70 | /* gssapi_ssleay 1.3.6.1.4.1.3536.1.1 */ |
---|
71 | {"N3+k7/4wGxHyuP8Yxi4RhA==", |
---|
72 | "GSI", |
---|
73 | {9, "\x2B\x06\x01\x04\x01\x9B\x50\x01\x01"} |
---|
74 | }, |
---|
75 | #endif /* GSI */ |
---|
76 | {NULL,NULL,{0,0}} |
---|
77 | }; |
---|
78 | |
---|
79 | char gssprefix[]=KEX_GSS_SHA1; |
---|
80 | |
---|
81 | /* Return a list of the gss-group1-sha1-x mechanisms supported by this |
---|
82 | * program. |
---|
83 | * |
---|
84 | * We only support the mechanisms that we've indicated in the list above, |
---|
85 | * but we check that they're supported by the GSSAPI mechanism on the |
---|
86 | * machine. We also check, before including them in the list, that |
---|
87 | * we have the necesary information in order to carry out the key exchange |
---|
88 | * (that is, that the user has credentials, the server's creds are accessible, |
---|
89 | * etc) |
---|
90 | * |
---|
91 | * The way that this is done is fairly nasty, as we do a lot of work that |
---|
92 | * is then thrown away. This should possibly be implemented with a cache |
---|
93 | * that stores the results (in an expanded Gssctxt structure), which are |
---|
94 | * then used by the first calls if that key exchange mechanism is chosen. |
---|
95 | */ |
---|
96 | |
---|
97 | char * |
---|
98 | ssh_gssapi_mechanisms(int server,char *host) { |
---|
99 | gss_OID_set supported; |
---|
100 | OM_uint32 maj_status, min_status; |
---|
101 | Buffer buf; |
---|
102 | int i = 0; |
---|
103 | int present; |
---|
104 | char * mechs; |
---|
105 | Gssctxt * ctx = NULL; |
---|
106 | |
---|
107 | if (datafellows & SSH_OLD_GSSAPI) return NULL; |
---|
108 | |
---|
109 | gss_indicate_mechs(&min_status, &supported); |
---|
110 | |
---|
111 | buffer_init(&buf); |
---|
112 | |
---|
113 | do { |
---|
114 | if ((maj_status=gss_test_oid_set_member(&min_status, |
---|
115 | &supported_mechs[i].oid, |
---|
116 | supported, |
---|
117 | &present))) { |
---|
118 | present=0; |
---|
119 | } |
---|
120 | if (present) { |
---|
121 | if ((server && |
---|
122 | !GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctx, |
---|
123 | &supported_mechs[i].oid)))) |
---|
124 | || (!server && |
---|
125 | !GSS_ERROR(ssh_gssapi_client_ctx(&ctx, |
---|
126 | &supported_mechs[i].oid, |
---|
127 | host)))) { |
---|
128 | /* Append gss_group1_sha1_x to our list */ |
---|
129 | buffer_append(&buf, gssprefix, |
---|
130 | strlen(gssprefix)); |
---|
131 | buffer_append(&buf, |
---|
132 | supported_mechs[i].enc_name, |
---|
133 | strlen(supported_mechs[i].enc_name)); |
---|
134 | } |
---|
135 | } |
---|
136 | } while (supported_mechs[++i].name != NULL); |
---|
137 | |
---|
138 | buffer_put_char(&buf,'\0'); |
---|
139 | |
---|
140 | mechs=xmalloc(buffer_len(&buf)); |
---|
141 | buffer_get(&buf,mechs,buffer_len(&buf)); |
---|
142 | buffer_free(&buf); |
---|
143 | if (strlen(mechs)==0) |
---|
144 | return(NULL); |
---|
145 | else |
---|
146 | return(mechs); |
---|
147 | } |
---|
148 | |
---|
149 | void ssh_gssapi_supported_oids(gss_OID_set *oidset) { |
---|
150 | enum ssh_gss_id i =0; |
---|
151 | OM_uint32 maj_status,min_status; |
---|
152 | int present; |
---|
153 | gss_OID_set supported; |
---|
154 | |
---|
155 | gss_create_empty_oid_set(&min_status,oidset); |
---|
156 | gss_indicate_mechs(&min_status, &supported); |
---|
157 | |
---|
158 | while (supported_mechs[i].name!=NULL) { |
---|
159 | if ((maj_status=gss_test_oid_set_member(&min_status, |
---|
160 | &supported_mechs[i].oid, |
---|
161 | supported, |
---|
162 | &present))) { |
---|
163 | present=0; |
---|
164 | } |
---|
165 | if (present) { |
---|
166 | gss_add_oid_set_member(&min_status, |
---|
167 | &supported_mechs[i].oid, |
---|
168 | oidset); |
---|
169 | } |
---|
170 | i++; |
---|
171 | } |
---|
172 | } |
---|
173 | |
---|
174 | /* Set the contexts OID from a data stream */ |
---|
175 | void ssh_gssapi_set_oid_data(Gssctxt *ctx, void *data, size_t len) { |
---|
176 | if (ctx->oid != GSS_C_NO_OID) { |
---|
177 | xfree(ctx->oid->elements); |
---|
178 | xfree(ctx->oid); |
---|
179 | } |
---|
180 | ctx->oid=xmalloc(sizeof(gss_OID_desc)); |
---|
181 | ctx->oid->length=len; |
---|
182 | ctx->oid->elements=xmalloc(len); |
---|
183 | memcpy(ctx->oid->elements,data,len); |
---|
184 | } |
---|
185 | |
---|
186 | /* Set the contexts OID */ |
---|
187 | void ssh_gssapi_set_oid(Gssctxt *ctx, gss_OID oid) { |
---|
188 | ssh_gssapi_set_oid_data(ctx,oid->elements,oid->length); |
---|
189 | } |
---|
190 | |
---|
191 | /* Find out which GSS type (out of the list we define in ssh-gss.h) a |
---|
192 | * particular connection is using |
---|
193 | */ |
---|
194 | enum ssh_gss_id ssh_gssapi_get_ctype(Gssctxt *ctxt) { |
---|
195 | enum ssh_gss_id i=0; |
---|
196 | |
---|
197 | while(supported_mechs[i].name!=NULL && |
---|
198 | supported_mechs[i].oid.length != ctxt->oid->length && |
---|
199 | (memcmp(supported_mechs[i].oid.elements, |
---|
200 | ctxt->oid->elements,ctxt->oid->length) !=0)) { |
---|
201 | i++; |
---|
202 | } |
---|
203 | return(i); |
---|
204 | } |
---|
205 | |
---|
206 | /* Set the GSS context's OID to the oid indicated by the given key exchange |
---|
207 | * name. */ |
---|
208 | gss_OID ssh_gssapi_id_kex(Gssctxt *ctx, char *name) { |
---|
209 | enum ssh_gss_id i=0; |
---|
210 | |
---|
211 | if (strncmp(name, gssprefix, strlen(gssprefix)-1) !=0) { |
---|
212 | return(NULL); |
---|
213 | } |
---|
214 | |
---|
215 | name+=strlen(gssprefix); /* Move to the start of the MIME string */ |
---|
216 | |
---|
217 | while (supported_mechs[i].name!=NULL && |
---|
218 | strcmp(name,supported_mechs[i].enc_name)!=0) { |
---|
219 | i++; |
---|
220 | } |
---|
221 | |
---|
222 | if (supported_mechs[i].name==NULL) |
---|
223 | return (NULL); |
---|
224 | |
---|
225 | if (ctx) ssh_gssapi_set_oid(ctx,&supported_mechs[i].oid); |
---|
226 | |
---|
227 | return &supported_mechs[i].oid; |
---|
228 | } |
---|
229 | |
---|
230 | |
---|
231 | /* All this effort to report an error ... |
---|
232 | * ... and with privsep, how on earth do we get it back to the client? */ |
---|
233 | |
---|
234 | void |
---|
235 | ssh_gssapi_error(OM_uint32 major_status,OM_uint32 minor_status) { |
---|
236 | OM_uint32 lmaj, lmin; |
---|
237 | gss_buffer_desc msg; |
---|
238 | OM_uint32 ctx; |
---|
239 | |
---|
240 | ctx = 0; |
---|
241 | /* The GSSAPI error */ |
---|
242 | do { |
---|
243 | lmaj = gss_display_status(&lmin, major_status, |
---|
244 | GSS_C_GSS_CODE, |
---|
245 | GSS_C_NULL_OID, |
---|
246 | &ctx, &msg); |
---|
247 | if (lmaj == GSS_S_COMPLETE) { |
---|
248 | debug((char *)msg.value); |
---|
249 | (void) gss_release_buffer(&lmin, &msg); |
---|
250 | } |
---|
251 | } while (ctx!=0); |
---|
252 | |
---|
253 | /* The mechanism specific error */ |
---|
254 | do { |
---|
255 | lmaj = gss_display_status(&lmin, minor_status, |
---|
256 | GSS_C_MECH_CODE, |
---|
257 | GSS_C_NULL_OID, |
---|
258 | &ctx, &msg); |
---|
259 | if (lmaj == GSS_S_COMPLETE) { |
---|
260 | debug((char *)msg.value); |
---|
261 | (void) gss_release_buffer(&lmin, &msg); |
---|
262 | } |
---|
263 | } while (ctx!=0); |
---|
264 | } |
---|
265 | |
---|
266 | /* Initialise our GSSAPI context. We use this opaque structure to contain all |
---|
267 | * of the data which both the client and server need to persist across |
---|
268 | * {accept,init}_sec_context calls, so that when we do it from the userauth |
---|
269 | * stuff life is a little easier |
---|
270 | */ |
---|
271 | void |
---|
272 | ssh_gssapi_build_ctx(Gssctxt **ctx) |
---|
273 | { |
---|
274 | *ctx=xmalloc(sizeof (Gssctxt)); |
---|
275 | (*ctx)->context=GSS_C_NO_CONTEXT; |
---|
276 | (*ctx)->name=GSS_C_NO_NAME; |
---|
277 | (*ctx)->oid=GSS_C_NO_OID; |
---|
278 | (*ctx)->creds=GSS_C_NO_CREDENTIAL; |
---|
279 | (*ctx)->client=GSS_C_NO_NAME; |
---|
280 | (*ctx)->client_creds=GSS_C_NO_CREDENTIAL; |
---|
281 | } |
---|
282 | |
---|
283 | /* Delete our context, providing it has been built correctly */ |
---|
284 | void |
---|
285 | ssh_gssapi_delete_ctx(Gssctxt **ctx) |
---|
286 | { |
---|
287 | OM_uint32 ms; |
---|
288 | |
---|
289 | /* Return if there's no context */ |
---|
290 | if ((*ctx)==NULL) |
---|
291 | return; |
---|
292 | |
---|
293 | if ((*ctx)->context != GSS_C_NO_CONTEXT) |
---|
294 | gss_delete_sec_context(&ms,&(*ctx)->context,GSS_C_NO_BUFFER); |
---|
295 | if ((*ctx)->name != GSS_C_NO_NAME) |
---|
296 | gss_release_name(&ms,&(*ctx)->name); |
---|
297 | if ((*ctx)->oid != GSS_C_NO_OID) { |
---|
298 | xfree((*ctx)->oid->elements); |
---|
299 | xfree((*ctx)->oid); |
---|
300 | (*ctx)->oid = GSS_C_NO_OID; |
---|
301 | } |
---|
302 | if ((*ctx)->creds != GSS_C_NO_CREDENTIAL) |
---|
303 | gss_release_cred(&ms,&(*ctx)->creds); |
---|
304 | if ((*ctx)->client != GSS_C_NO_NAME) |
---|
305 | gss_release_name(&ms,&(*ctx)->client); |
---|
306 | if ((*ctx)->client_creds != GSS_C_NO_CREDENTIAL) |
---|
307 | gss_release_cred(&ms,&(*ctx)->client_creds); |
---|
308 | |
---|
309 | xfree(*ctx); |
---|
310 | *ctx=NULL; |
---|
311 | } |
---|
312 | |
---|
313 | /* Wrapper to init_sec_context |
---|
314 | * Requires that the context contains: |
---|
315 | * oid |
---|
316 | * server name (from ssh_gssapi_import_name) |
---|
317 | */ |
---|
318 | OM_uint32 |
---|
319 | ssh_gssapi_init_ctx(Gssctxt *ctx, int deleg_creds, gss_buffer_desc *recv_tok, |
---|
320 | gss_buffer_desc* send_tok, OM_uint32 *flags) |
---|
321 | { |
---|
322 | OM_uint32 maj_status, min_status; |
---|
323 | int deleg_flag = 0; |
---|
324 | |
---|
325 | if (deleg_creds) { |
---|
326 | deleg_flag=GSS_C_DELEG_FLAG; |
---|
327 | debug("Delegating credentials"); |
---|
328 | } |
---|
329 | |
---|
330 | maj_status=gss_init_sec_context(&min_status, |
---|
331 | GSS_C_NO_CREDENTIAL, /* def. cred */ |
---|
332 | &ctx->context, |
---|
333 | ctx->name, |
---|
334 | ctx->oid, |
---|
335 | GSS_C_MUTUAL_FLAG | |
---|
336 | GSS_C_INTEG_FLAG | |
---|
337 | deleg_flag, |
---|
338 | 0, /* default lifetime */ |
---|
339 | NULL, /* no channel bindings */ |
---|
340 | recv_tok, |
---|
341 | NULL, |
---|
342 | send_tok, |
---|
343 | flags, |
---|
344 | NULL); |
---|
345 | ctx->status=maj_status; |
---|
346 | if (GSS_ERROR(maj_status)) { |
---|
347 | ssh_gssapi_error(maj_status,min_status); |
---|
348 | } |
---|
349 | return(maj_status); |
---|
350 | } |
---|
351 | |
---|
352 | /* Wrapper arround accept_sec_context |
---|
353 | * Requires that the context contains: |
---|
354 | * oid |
---|
355 | * credentials (from ssh_gssapi_acquire_cred) |
---|
356 | */ |
---|
357 | OM_uint32 ssh_gssapi_accept_ctx(Gssctxt *ctx,gss_buffer_desc *recv_tok, |
---|
358 | gss_buffer_desc *send_tok, OM_uint32 *flags) |
---|
359 | { |
---|
360 | OM_uint32 maj_status, min_status; |
---|
361 | gss_OID mech; |
---|
362 | |
---|
363 | maj_status=gss_accept_sec_context(&min_status, |
---|
364 | &ctx->context, |
---|
365 | ctx->creds, |
---|
366 | recv_tok, |
---|
367 | GSS_C_NO_CHANNEL_BINDINGS, |
---|
368 | &ctx->client, |
---|
369 | &mech, |
---|
370 | send_tok, |
---|
371 | flags, |
---|
372 | NULL, |
---|
373 | &ctx->client_creds); |
---|
374 | if (GSS_ERROR(maj_status)) { |
---|
375 | ssh_gssapi_error(maj_status,min_status); |
---|
376 | } |
---|
377 | |
---|
378 | if (ctx->client_creds) { |
---|
379 | debug("Received some client credentials"); |
---|
380 | } else { |
---|
381 | debug("Got no client credentials"); |
---|
382 | } |
---|
383 | |
---|
384 | /* FIXME: We should check that the me |
---|
385 | * the one that we asked for (in ctx->oid) */ |
---|
386 | |
---|
387 | ctx->status=maj_status; |
---|
388 | |
---|
389 | /* Now, if we're complete and we have the right flags, then |
---|
390 | * we flag the user as also having been authenticated |
---|
391 | */ |
---|
392 | |
---|
393 | if (((flags==NULL) || ((*flags & GSS_C_MUTUAL_FLAG) && |
---|
394 | (*flags & GSS_C_INTEG_FLAG))) && |
---|
395 | (maj_status == GSS_S_COMPLETE)) { |
---|
396 | if (ssh_gssapi_getclient(ctx,&gssapi_client_type, |
---|
397 | &gssapi_client_name, |
---|
398 | &gssapi_client_creds)) |
---|
399 | fatal("Couldn't convert client name"); |
---|
400 | } |
---|
401 | |
---|
402 | return(maj_status); |
---|
403 | } |
---|
404 | |
---|
405 | /* Create a service name for the given host */ |
---|
406 | OM_uint32 |
---|
407 | ssh_gssapi_import_name(Gssctxt *ctx, const char *host) { |
---|
408 | gss_buffer_desc gssbuf; |
---|
409 | OM_uint32 maj_status, min_status; |
---|
410 | struct hostent *hostinfo = NULL; |
---|
411 | char *xhost; |
---|
412 | |
---|
413 | /* Make a copy of the host name, in case it was returned by a |
---|
414 | * previous call to gethostbyname(). */ |
---|
415 | xhost = xstrdup(host); |
---|
416 | |
---|
417 | /* Make sure we have the FQDN. Some GSSAPI implementations don't do |
---|
418 | * this for us themselves */ |
---|
419 | |
---|
420 | hostinfo = gethostbyname(xhost); |
---|
421 | |
---|
422 | if ((hostinfo == NULL) || (hostinfo->h_name == NULL)) { |
---|
423 | debug("Unable to get FQDN for \"%s\"", xhost); |
---|
424 | } else { |
---|
425 | xfree(xhost); |
---|
426 | xhost = xstrdup(hostinfo->h_name); |
---|
427 | } |
---|
428 | |
---|
429 | gssbuf.length = sizeof("host@")+strlen(xhost); |
---|
430 | |
---|
431 | gssbuf.value = xmalloc(gssbuf.length); |
---|
432 | if (gssbuf.value == NULL) { |
---|
433 | xfree(xhost); |
---|
434 | return(-1); |
---|
435 | } |
---|
436 | snprintf(gssbuf.value,gssbuf.length,"host@%s",xhost); |
---|
437 | if ((maj_status=gss_import_name(&min_status, |
---|
438 | &gssbuf, |
---|
439 | GSS_C_NT_HOSTBASED_SERVICE, |
---|
440 | &ctx->name))) { |
---|
441 | ssh_gssapi_error(maj_status,min_status); |
---|
442 | } |
---|
443 | |
---|
444 | xfree(xhost); |
---|
445 | xfree(gssbuf.value); |
---|
446 | return(maj_status); |
---|
447 | } |
---|
448 | |
---|
449 | /* Acquire credentials for a server running on the current host. |
---|
450 | * Requires that the context structure contains a valid OID |
---|
451 | */ |
---|
452 | |
---|
453 | /* Returns a GSSAPI error code */ |
---|
454 | OM_uint32 |
---|
455 | ssh_gssapi_acquire_cred(Gssctxt *ctx) { |
---|
456 | OM_uint32 maj_status, min_status; |
---|
457 | char lname[MAXHOSTNAMELEN]; |
---|
458 | gss_OID_set oidset; |
---|
459 | |
---|
460 | gss_create_empty_oid_set(&min_status,&oidset); |
---|
461 | gss_add_oid_set_member(&min_status,ctx->oid,&oidset); |
---|
462 | |
---|
463 | if (gethostname(lname, MAXHOSTNAMELEN)) { |
---|
464 | return(-1); |
---|
465 | } |
---|
466 | |
---|
467 | if ((maj_status=ssh_gssapi_import_name(ctx,lname))) { |
---|
468 | return(maj_status); |
---|
469 | } |
---|
470 | if ((maj_status=gss_acquire_cred(&min_status, |
---|
471 | ctx->name, |
---|
472 | 0, |
---|
473 | oidset, |
---|
474 | GSS_C_ACCEPT, |
---|
475 | &ctx->creds, |
---|
476 | NULL, |
---|
477 | NULL))) { |
---|
478 | ssh_gssapi_error(maj_status,min_status); |
---|
479 | } |
---|
480 | |
---|
481 | gss_release_oid_set(&min_status, &oidset); |
---|
482 | return(maj_status); |
---|
483 | } |
---|
484 | |
---|
485 | /* Extract the client details from a given context. This can only reliably |
---|
486 | * be called once for a context */ |
---|
487 | |
---|
488 | OM_uint32 |
---|
489 | ssh_gssapi_getclient(Gssctxt *ctx, enum ssh_gss_id *type, |
---|
490 | gss_buffer_desc *name, gss_cred_id_t *creds) { |
---|
491 | |
---|
492 | OM_uint32 maj_status,min_status; |
---|
493 | |
---|
494 | *type=ssh_gssapi_get_ctype(ctx); |
---|
495 | if ((maj_status=gss_display_name(&min_status,ctx->client,name,NULL))) { |
---|
496 | ssh_gssapi_error(maj_status,min_status); |
---|
497 | } |
---|
498 | |
---|
499 | /* This is icky. There appears to be no way to copy this structure, |
---|
500 | * rather than the pointer to it, so we simply copy the pointer and |
---|
501 | * mark the originator as empty so we don't destroy it. |
---|
502 | */ |
---|
503 | *creds=ctx->client_creds; |
---|
504 | ctx->client_creds=GSS_C_NO_CREDENTIAL; |
---|
505 | return(maj_status); |
---|
506 | } |
---|
507 | |
---|
508 | OM_uint32 |
---|
509 | ssh_gssapi_sign(Gssctxt *ctx, gss_buffer_desc *buffer, gss_buffer_desc *hash) { |
---|
510 | OM_uint32 maj_status,min_status; |
---|
511 | |
---|
512 | if ((maj_status=gss_get_mic(&min_status,ctx->context, |
---|
513 | GSS_C_QOP_DEFAULT, buffer, hash))) { |
---|
514 | ssh_gssapi_error(maj_status,min_status); |
---|
515 | } |
---|
516 | |
---|
517 | return(maj_status); |
---|
518 | } |
---|
519 | |
---|
520 | OM_uint32 |
---|
521 | ssh_gssapi_server_ctx(Gssctxt **ctx,gss_OID oid) { |
---|
522 | if (*ctx) ssh_gssapi_delete_ctx(ctx); |
---|
523 | ssh_gssapi_build_ctx(ctx); |
---|
524 | ssh_gssapi_set_oid(*ctx,oid); |
---|
525 | return(ssh_gssapi_acquire_cred(*ctx)); |
---|
526 | } |
---|
527 | |
---|
528 | OM_uint32 |
---|
529 | ssh_gssapi_client_ctx(Gssctxt **ctx,gss_OID oid, char *host) { |
---|
530 | gss_buffer_desc token; |
---|
531 | OM_uint32 major,minor; |
---|
532 | |
---|
533 | if (*ctx) ssh_gssapi_delete_ctx(ctx); |
---|
534 | ssh_gssapi_build_ctx(ctx); |
---|
535 | ssh_gssapi_set_oid(*ctx,oid); |
---|
536 | ssh_gssapi_import_name(*ctx,host); |
---|
537 | major=ssh_gssapi_init_ctx(*ctx, 0, GSS_C_NO_BUFFER, &token, NULL); |
---|
538 | gss_release_buffer(&minor,&token); |
---|
539 | return(major); |
---|
540 | } |
---|
541 | |
---|
542 | #endif /* GSSAPI */ |
---|