10 static Ssh_gss_stat
ssh_gssapi_indicate_mech(struct ssh_gss_library
*lib
,
13 /* Copy constant into mech */
14 mech
->length
= GSS_MECH_KRB5
->length
;
15 mech
->value
= GSS_MECH_KRB5
->elements
;
19 static Ssh_gss_stat
ssh_gssapi_import_name(struct ssh_gss_library
*lib
,
21 Ssh_gss_name
*srv_name
)
23 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
24 OM_uint32 min_stat
,maj_stat
;
25 gss_buffer_desc host_buf
;
28 pStr
= dupcat("host@", host
);
30 host_buf
.value
= pStr
;
31 host_buf
.length
= strlen(pStr
);
33 maj_stat
= gss
->import_name(&min_stat
, &host_buf
,
34 GSS_C_NT_HOSTBASED_SERVICE
, srv_name
);
37 if (maj_stat
== GSS_S_COMPLETE
) return SSH_GSS_OK
;
38 return SSH_GSS_FAILURE
;
41 static Ssh_gss_stat
ssh_gssapi_acquire_cred(struct ssh_gss_library
*lib
,
45 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
46 gss_OID_set_desc k5only
= { 1, GSS_MECH_KRB5
};
50 gssapi_ssh_gss_ctx
*gssctx
= snew(gssapi_ssh_gss_ctx
);
52 gssctx
->ctx
= GSS_C_NO_CONTEXT
;
56 gss
->acquire_cred(&gssctx
->min_stat
, GSS_C_NO_NAME
, GSS_C_INDEFINITE
,
57 &k5only
, GSS_C_INITIATE
, &cred
,
58 (gss_OID_set
*)0, &time_rec
);
60 if (gssctx
->maj_stat
!= GSS_S_COMPLETE
) {
62 return SSH_GSS_FAILURE
;
66 * When the credential lifetime is not yet available due to deferred
67 * processing, gss_acquire_cred should return a 0 lifetime which is
68 * distinct from GSS_C_INDEFINITE which signals a crential that never
69 * expires. However, not all implementations get this right, and with
70 * Kerberos, initiator credentials always expire at some point. So when
71 * lifetime is 0 or GSS_C_INDEFINITE we call gss_inquire_cred_by_mech() to
72 * complete deferred processing.
74 if (time_rec
== GSS_C_INDEFINITE
|| time_rec
== 0) {
76 gss
->inquire_cred_by_mech(&gssctx
->min_stat
, cred
,
77 (gss_OID
) GSS_MECH_KRB5
,
83 (void) gss
->release_cred(&dummy
, &cred
);
85 if (gssctx
->maj_stat
!= GSS_S_COMPLETE
) {
87 return SSH_GSS_FAILURE
;
90 if (time_rec
!= GSS_C_INDEFINITE
)
91 gssctx
->expiry
= time(NULL
) + time_rec
;
93 gssctx
->expiry
= GSS_NO_EXPIRATION
;
96 *expiry
= gssctx
->expiry
;
99 *ctx
= (Ssh_gss_ctx
) gssctx
;
103 static Ssh_gss_stat
ssh_gssapi_init_sec_context(struct ssh_gss_library
*lib
,
105 Ssh_gss_name srv_name
,
107 Ssh_gss_buf
*recv_tok
,
108 Ssh_gss_buf
*send_tok
,
110 unsigned long *lifetime
)
112 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
113 gssapi_ssh_gss_ctx
*gssctx
= (gssapi_ssh_gss_ctx
*) *ctx
;
115 OM_uint32 lifetime_rec
;
117 if (to_deleg
) to_deleg
= GSS_C_DELEG_FLAG
;
118 gssctx
->maj_stat
= gss
->init_sec_context(&gssctx
->min_stat
,
122 (gss_OID
) GSS_MECH_KRB5
,
124 GSS_C_INTEG_FLAG
| to_deleg
,
126 GSS_C_NO_CHANNEL_BINDINGS
,
128 NULL
, /* ignore mech type */
134 if (lifetime_rec
== GSS_C_INDEFINITE
)
135 *lifetime
= ULONG_MAX
;
137 *lifetime
= lifetime_rec
;
140 if (lifetime_rec
== GSS_C_INDEFINITE
)
141 *expiry
= GSS_NO_EXPIRATION
;
143 *expiry
= time(NULL
) + lifetime_rec
;
146 if (gssctx
->maj_stat
== GSS_S_COMPLETE
) return SSH_GSS_S_COMPLETE
;
147 if (gssctx
->maj_stat
== GSS_S_CONTINUE_NEEDED
) return SSH_GSS_S_CONTINUE_NEEDED
;
148 return SSH_GSS_FAILURE
;
151 static Ssh_gss_stat
ssh_gssapi_display_status(struct ssh_gss_library
*lib
,
155 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
156 gssapi_ssh_gss_ctx
*gssctx
= (gssapi_ssh_gss_ctx
*) ctx
;
159 gss_buffer_desc msg_maj
=GSS_C_EMPTY_BUFFER
;
160 gss_buffer_desc msg_min
=GSS_C_EMPTY_BUFFER
;
162 /* Return empty buffer in case of failure */
163 SSH_GSS_CLEAR_BUF(buf
);
165 /* get first mesg from GSS */
167 lmax
=gss
->display_status(&lmin
,gssctx
->maj_stat
,GSS_C_GSS_CODE
,(gss_OID
) GSS_MECH_KRB5
,&ccc
,&msg_maj
);
169 if (lmax
!= GSS_S_COMPLETE
) return SSH_GSS_FAILURE
;
171 /* get first mesg from Kerberos */
173 lmax
=gss
->display_status(&lmin
,gssctx
->min_stat
,GSS_C_MECH_CODE
,(gss_OID
) GSS_MECH_KRB5
,&ccc
,&msg_min
);
175 if (lmax
!= GSS_S_COMPLETE
) {
176 gss
->release_buffer(&lmin
, &msg_maj
);
177 return SSH_GSS_FAILURE
;
180 /* copy data into buffer */
181 buf
->length
= msg_maj
.length
+ msg_min
.length
+ 1;
182 buf
->value
= snewn(buf
->length
+ 1, char);
185 memcpy((char *)buf
->value
, msg_maj
.value
, msg_maj
.length
);
186 ((char *)buf
->value
)[msg_maj
.length
] = ' ';
187 memcpy((char *)buf
->value
+ msg_maj
.length
+ 1, msg_min
.value
, msg_min
.length
);
188 ((char *)buf
->value
)[buf
->length
] = 0;
189 /* free mem & exit */
190 gss
->release_buffer(&lmin
, &msg_maj
);
191 gss
->release_buffer(&lmin
, &msg_min
);
195 static Ssh_gss_stat
ssh_gssapi_free_tok(struct ssh_gss_library
*lib
,
196 Ssh_gss_buf
*send_tok
)
198 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
199 OM_uint32 min_stat
,maj_stat
;
200 maj_stat
= gss
->release_buffer(&min_stat
, send_tok
);
202 if (maj_stat
== GSS_S_COMPLETE
) return SSH_GSS_OK
;
203 return SSH_GSS_FAILURE
;
206 static Ssh_gss_stat
ssh_gssapi_release_cred(struct ssh_gss_library
*lib
,
209 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
210 gssapi_ssh_gss_ctx
*gssctx
= (gssapi_ssh_gss_ctx
*) *ctx
;
212 OM_uint32 maj_stat
=GSS_S_COMPLETE
;
214 if (gssctx
== NULL
) return SSH_GSS_FAILURE
;
215 if (gssctx
->ctx
!= GSS_C_NO_CONTEXT
)
216 maj_stat
= gss
->delete_sec_context(&min_stat
,&gssctx
->ctx
,GSS_C_NO_BUFFER
);
220 if (maj_stat
== GSS_S_COMPLETE
) return SSH_GSS_OK
;
221 return SSH_GSS_FAILURE
;
225 static Ssh_gss_stat
ssh_gssapi_release_name(struct ssh_gss_library
*lib
,
226 Ssh_gss_name
*srv_name
)
228 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
229 OM_uint32 min_stat
,maj_stat
;
230 maj_stat
= gss
->release_name(&min_stat
, srv_name
);
232 if (maj_stat
== GSS_S_COMPLETE
) return SSH_GSS_OK
;
233 return SSH_GSS_FAILURE
;
236 static Ssh_gss_stat
ssh_gssapi_get_mic(struct ssh_gss_library
*lib
,
237 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
240 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
241 gssapi_ssh_gss_ctx
*gssctx
= (gssapi_ssh_gss_ctx
*) ctx
;
242 if (gssctx
== NULL
) return SSH_GSS_FAILURE
;
243 return gss
->get_mic(&(gssctx
->min_stat
), gssctx
->ctx
, 0, buf
, hash
);
246 static Ssh_gss_stat
ssh_gssapi_verify_mic(struct ssh_gss_library
*lib
,
247 Ssh_gss_ctx ctx
, Ssh_gss_buf
*buf
,
250 struct gssapi_functions
*gss
= &lib
->u
.gssapi
;
251 gssapi_ssh_gss_ctx
*gssctx
= (gssapi_ssh_gss_ctx
*) ctx
;
252 if (gssctx
== NULL
) return SSH_GSS_FAILURE
;
253 return gss
->verify_mic(&(gssctx
->min_stat
), gssctx
->ctx
, buf
, hash
, NULL
);
256 static Ssh_gss_stat
ssh_gssapi_free_mic(struct ssh_gss_library
*lib
,
259 /* On Unix this is the same freeing process as ssh_gssapi_free_tok. */
260 return ssh_gssapi_free_tok(lib
, hash
);
263 void ssh_gssapi_bind_fns(struct ssh_gss_library
*lib
)
265 lib
->indicate_mech
= ssh_gssapi_indicate_mech
;
266 lib
->import_name
= ssh_gssapi_import_name
;
267 lib
->release_name
= ssh_gssapi_release_name
;
268 lib
->init_sec_context
= ssh_gssapi_init_sec_context
;
269 lib
->free_tok
= ssh_gssapi_free_tok
;
270 lib
->acquire_cred
= ssh_gssapi_acquire_cred
;
271 lib
->release_cred
= ssh_gssapi_release_cred
;
272 lib
->get_mic
= ssh_gssapi_get_mic
;
273 lib
->verify_mic
= ssh_gssapi_verify_mic
;
274 lib
->free_mic
= ssh_gssapi_free_mic
;
275 lib
->display_status
= ssh_gssapi_display_status
;
280 /* Dummy function so this source file defines something if NO_GSSAPI
283 int ssh_gssapi_init(void)