1 | /* |
---|
2 | * Kerberos v5 authentication and ticket-passing routines. |
---|
3 | * |
---|
4 | * $FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp $ |
---|
5 | */ |
---|
6 | /* |
---|
7 | * Copyright (c) 2002 Daniel Kouril. All rights reserved. |
---|
8 | * |
---|
9 | * Redistribution and use in source and binary forms, with or without |
---|
10 | * modification, are permitted provided that the following conditions |
---|
11 | * are met: |
---|
12 | * 1. Redistributions of source code must retain the above copyright |
---|
13 | * notice, this list of conditions and the following disclaimer. |
---|
14 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer in the |
---|
16 | * documentation and/or other materials provided with the distribution. |
---|
17 | * |
---|
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
---|
19 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
---|
20 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
---|
21 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
22 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
---|
23 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
---|
24 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
---|
25 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
---|
26 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
---|
27 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
---|
28 | */ |
---|
29 | |
---|
30 | #include "includes.h" |
---|
31 | RCSID("$OpenBSD: auth-krb5.c,v 1.9 2002/09/09 06:48:06 itojun Exp $"); |
---|
32 | |
---|
33 | #include "ssh.h" |
---|
34 | #include "ssh1.h" |
---|
35 | #include "packet.h" |
---|
36 | #include "xmalloc.h" |
---|
37 | #include "log.h" |
---|
38 | #include "servconf.h" |
---|
39 | #include "uidswap.h" |
---|
40 | #include "auth.h" |
---|
41 | |
---|
42 | #ifdef KRB5 |
---|
43 | #include <krb5.h> |
---|
44 | #ifndef HEIMDAL |
---|
45 | #define krb5_get_err_text(context,code) error_message(code) |
---|
46 | #endif /* !HEIMDAL */ |
---|
47 | |
---|
48 | extern ServerOptions options; |
---|
49 | |
---|
50 | static int |
---|
51 | krb5_init(void *context) |
---|
52 | { |
---|
53 | Authctxt *authctxt = (Authctxt *)context; |
---|
54 | krb5_error_code problem; |
---|
55 | static int cleanup_registered = 0; |
---|
56 | int fd; |
---|
57 | #ifndef HEIMDAL |
---|
58 | krb5_rcache rcache; |
---|
59 | krb5_data host_data; |
---|
60 | #endif |
---|
61 | |
---|
62 | if (authctxt->krb5_ctx == NULL) { |
---|
63 | problem = krb5_init_context(&authctxt->krb5_ctx); |
---|
64 | if (problem) |
---|
65 | return (problem); |
---|
66 | |
---|
67 | } |
---|
68 | if (authctxt->krb5_auth_ctx == NULL) { |
---|
69 | problem = krb5_auth_con_init(authctxt->krb5_ctx, |
---|
70 | &authctxt->krb5_auth_ctx); |
---|
71 | if (problem) |
---|
72 | return problem; |
---|
73 | |
---|
74 | host_data.data = "host"; |
---|
75 | host_data.length = strlen(host_data.data); |
---|
76 | krb5_get_server_rcache(authctxt->krb5_ctx, |
---|
77 | &host_data, &rcache); |
---|
78 | krb5_auth_con_setrcache(authctxt->krb5_ctx, |
---|
79 | authctxt->krb5_auth_ctx, |
---|
80 | rcache); |
---|
81 | |
---|
82 | fd = packet_get_connection_in(); |
---|
83 | #ifdef HEIMDAL |
---|
84 | problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, |
---|
85 | authctxt->krb5_auth_ctx, &fd); |
---|
86 | #else |
---|
87 | problem = krb5_auth_con_genaddrs(authctxt->krb5_ctx, |
---|
88 | authctxt->krb5_auth_ctx,fd, |
---|
89 | KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR | |
---|
90 | KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR); |
---|
91 | #endif |
---|
92 | if (problem) |
---|
93 | return problem; |
---|
94 | } |
---|
95 | |
---|
96 | if (!cleanup_registered) { |
---|
97 | fatal_add_cleanup(krb5_cleanup_proc, authctxt); |
---|
98 | cleanup_registered = 1; |
---|
99 | } |
---|
100 | return (0); |
---|
101 | } |
---|
102 | |
---|
103 | /* |
---|
104 | * Try krb5 authentication. server_user is passed for logging purposes |
---|
105 | * only, in auth is received ticket, in client is returned principal |
---|
106 | * from the ticket |
---|
107 | */ |
---|
108 | int |
---|
109 | auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *reply) |
---|
110 | { |
---|
111 | krb5_error_code problem; |
---|
112 | krb5_principal server; |
---|
113 | krb5_ticket *ticket; |
---|
114 | int fd, ret; |
---|
115 | |
---|
116 | ret = 0; |
---|
117 | server = NULL; |
---|
118 | ticket = NULL; |
---|
119 | reply->length = 0; |
---|
120 | |
---|
121 | problem = krb5_init(authctxt); |
---|
122 | if (problem) |
---|
123 | goto err; |
---|
124 | |
---|
125 | problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL , |
---|
126 | KRB5_NT_SRV_HST, &server); |
---|
127 | if (problem) |
---|
128 | goto err; |
---|
129 | |
---|
130 | problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, |
---|
131 | auth, server, NULL, NULL, &ticket); |
---|
132 | if (problem) |
---|
133 | goto err; |
---|
134 | |
---|
135 | #ifdef HEIMDAL |
---|
136 | problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, |
---|
137 | &authctxt->krb5_user); |
---|
138 | #else |
---|
139 | problem = krb5_copy_principal(authctxt->krb5_ctx, |
---|
140 | ticket->enc_part2->client, |
---|
141 | &authctxt->krb5_user); |
---|
142 | #endif |
---|
143 | if (problem) |
---|
144 | goto err; |
---|
145 | |
---|
146 | /* if client wants mutual auth */ |
---|
147 | problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, |
---|
148 | reply); |
---|
149 | if (problem) |
---|
150 | goto err; |
---|
151 | |
---|
152 | /* Check .k5login authorization now. */ |
---|
153 | if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, |
---|
154 | authctxt->pw->pw_name)) |
---|
155 | goto err; |
---|
156 | |
---|
157 | if (client) |
---|
158 | krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, |
---|
159 | client); |
---|
160 | |
---|
161 | ret = 1; |
---|
162 | err: |
---|
163 | if (server) |
---|
164 | krb5_free_principal(authctxt->krb5_ctx, server); |
---|
165 | if (ticket) |
---|
166 | krb5_free_ticket(authctxt->krb5_ctx, ticket); |
---|
167 | if (!ret && reply->length) { |
---|
168 | xfree(reply->data); |
---|
169 | memset(reply, 0, sizeof(*reply)); |
---|
170 | } |
---|
171 | |
---|
172 | if (problem) { |
---|
173 | if (authctxt->krb5_ctx != NULL) |
---|
174 | debug("Kerberos v5 authentication failed: %s", |
---|
175 | krb5_get_err_text(authctxt->krb5_ctx, problem)); |
---|
176 | else |
---|
177 | debug("Kerberos v5 authentication failed: %d", |
---|
178 | problem); |
---|
179 | } |
---|
180 | |
---|
181 | return (ret); |
---|
182 | } |
---|
183 | |
---|
184 | int |
---|
185 | auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) |
---|
186 | { |
---|
187 | krb5_error_code problem; |
---|
188 | krb5_ccache ccache = NULL; |
---|
189 | char *pname; |
---|
190 | krb5_creds **creds; |
---|
191 | |
---|
192 | problem = krb5_init(authctxt); |
---|
193 | if (problem) |
---|
194 | goto fail; |
---|
195 | |
---|
196 | if (authctxt->pw == NULL) |
---|
197 | return (0); |
---|
198 | |
---|
199 | temporarily_use_uid(authctxt->pw); |
---|
200 | |
---|
201 | problem = krb5_rd_cred(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, |
---|
202 | tgt, &creds, NULL); |
---|
203 | if (problem) |
---|
204 | goto fail; |
---|
205 | #ifdef HEIMDAL |
---|
206 | problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache); |
---|
207 | #else |
---|
208 | { |
---|
209 | char ccname[40]; |
---|
210 | |
---|
211 | snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_p%d",getpid()); |
---|
212 | setenv("KRB5CCNAME", ccname, 1); |
---|
213 | |
---|
214 | problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &ccache); |
---|
215 | } |
---|
216 | #endif |
---|
217 | if (problem) |
---|
218 | goto fail; |
---|
219 | |
---|
220 | problem = krb5_copy_principal(authctxt->krb5_ctx, (*creds)->client, |
---|
221 | &authctxt->krb5_user); |
---|
222 | if (problem) |
---|
223 | goto fail; |
---|
224 | |
---|
225 | problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, |
---|
226 | authctxt->krb5_user); |
---|
227 | if (problem) |
---|
228 | goto fail; |
---|
229 | |
---|
230 | #ifdef HEIMDAL |
---|
231 | problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, |
---|
232 | ccache, tgt); |
---|
233 | if (problem) |
---|
234 | goto fail; |
---|
235 | #else |
---|
236 | problem = krb5_cc_store_cred(authctxt->krb5_ctx, ccache, *creds); |
---|
237 | if (problem) |
---|
238 | goto fail; |
---|
239 | #endif |
---|
240 | |
---|
241 | authctxt->krb5_fwd_ccache = ccache; |
---|
242 | ccache = NULL; |
---|
243 | |
---|
244 | authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
---|
245 | |
---|
246 | problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, |
---|
247 | &pname); |
---|
248 | if (problem) |
---|
249 | goto fail; |
---|
250 | |
---|
251 | debug("Kerberos v5 TGT accepted (%s)", pname); |
---|
252 | |
---|
253 | restore_uid(); |
---|
254 | |
---|
255 | return (1); |
---|
256 | |
---|
257 | fail: |
---|
258 | if (problem) |
---|
259 | debug("Kerberos v5 TGT passing failed: %s", |
---|
260 | krb5_get_err_text(authctxt->krb5_ctx, problem)); |
---|
261 | if (ccache) |
---|
262 | krb5_cc_destroy(authctxt->krb5_ctx, ccache); |
---|
263 | |
---|
264 | restore_uid(); |
---|
265 | |
---|
266 | return (0); |
---|
267 | } |
---|
268 | |
---|
269 | int |
---|
270 | auth_krb5_password(Authctxt *authctxt, const char *password) |
---|
271 | { |
---|
272 | #ifndef HEIMDAL |
---|
273 | krb5_creds creds; |
---|
274 | krb5_principal server; |
---|
275 | char ccname[40]; |
---|
276 | #endif |
---|
277 | krb5_error_code problem; |
---|
278 | |
---|
279 | if (authctxt->pw == NULL) |
---|
280 | return (0); |
---|
281 | |
---|
282 | temporarily_use_uid(authctxt->pw); |
---|
283 | |
---|
284 | problem = krb5_init(authctxt); |
---|
285 | if (problem) |
---|
286 | goto out; |
---|
287 | |
---|
288 | problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, |
---|
289 | &authctxt->krb5_user); |
---|
290 | if (problem) |
---|
291 | goto out; |
---|
292 | |
---|
293 | #ifdef HEIMDAL |
---|
294 | problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, |
---|
295 | &authctxt->krb5_fwd_ccache); |
---|
296 | if (problem) |
---|
297 | goto out; |
---|
298 | |
---|
299 | problem = krb5_cc_initialize(authctxt->krb5_ctx, |
---|
300 | authctxt->krb5_fwd_ccache, authctxt->krb5_user); |
---|
301 | if (problem) |
---|
302 | goto out; |
---|
303 | |
---|
304 | restore_uid(); |
---|
305 | problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, |
---|
306 | authctxt->krb5_fwd_ccache, password, 1, NULL); |
---|
307 | temporarily_use_uid(authctxt->pw); |
---|
308 | |
---|
309 | if (problem) |
---|
310 | goto out; |
---|
311 | |
---|
312 | #else |
---|
313 | problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, |
---|
314 | authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); |
---|
315 | if (problem) |
---|
316 | goto out; |
---|
317 | |
---|
318 | problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, |
---|
319 | KRB5_NT_SRV_HST, &server); |
---|
320 | if (problem) |
---|
321 | goto out; |
---|
322 | |
---|
323 | restore_uid(); |
---|
324 | problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, |
---|
325 | NULL, NULL, NULL); |
---|
326 | krb5_free_principal(authctxt->krb5_ctx, server); |
---|
327 | temporarily_use_uid(authctxt->pw); |
---|
328 | if (problem) |
---|
329 | goto out; |
---|
330 | |
---|
331 | if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, |
---|
332 | authctxt->pw->pw_name)) { |
---|
333 | problem = -1; |
---|
334 | goto out; |
---|
335 | } |
---|
336 | |
---|
337 | snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_p%d",getpid()); |
---|
338 | setenv("KRB5CCNAME", ccname, 1); |
---|
339 | |
---|
340 | problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &authctxt->krb5_fwd_ccache); |
---|
341 | if (problem) |
---|
342 | goto out; |
---|
343 | |
---|
344 | problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, |
---|
345 | authctxt->krb5_user); |
---|
346 | if (problem) |
---|
347 | goto out; |
---|
348 | |
---|
349 | problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, |
---|
350 | &creds); |
---|
351 | if (problem) |
---|
352 | goto out; |
---|
353 | #endif |
---|
354 | |
---|
355 | authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
---|
356 | |
---|
357 | out: |
---|
358 | restore_uid(); |
---|
359 | |
---|
360 | if (problem) { |
---|
361 | if (authctxt->krb5_ctx != NULL && problem!=-1) |
---|
362 | debug("Kerberos password authentication failed: %s", |
---|
363 | krb5_get_err_text(authctxt->krb5_ctx, problem)); |
---|
364 | else |
---|
365 | debug("Kerberos password authentication failed: %d", |
---|
366 | problem); |
---|
367 | |
---|
368 | krb5_cleanup_proc(authctxt); |
---|
369 | |
---|
370 | if (options.kerberos_or_local_passwd) |
---|
371 | return (-1); |
---|
372 | else |
---|
373 | return (0); |
---|
374 | } |
---|
375 | return (1); |
---|
376 | } |
---|
377 | |
---|
378 | void |
---|
379 | krb5_cleanup_proc(void *context) |
---|
380 | { |
---|
381 | Authctxt *authctxt = (Authctxt *)context; |
---|
382 | |
---|
383 | debug("krb5_cleanup_proc called"); |
---|
384 | if (authctxt->krb5_fwd_ccache) { |
---|
385 | krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
---|
386 | authctxt->krb5_fwd_ccache = NULL; |
---|
387 | } |
---|
388 | if (authctxt->krb5_user) { |
---|
389 | krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); |
---|
390 | authctxt->krb5_user = NULL; |
---|
391 | } |
---|
392 | if (authctxt->krb5_auth_ctx) { |
---|
393 | krb5_auth_con_free(authctxt->krb5_ctx, |
---|
394 | authctxt->krb5_auth_ctx); |
---|
395 | authctxt->krb5_auth_ctx = NULL; |
---|
396 | } |
---|
397 | if (authctxt->krb5_ctx) { |
---|
398 | krb5_free_context(authctxt->krb5_ctx); |
---|
399 | authctxt->krb5_ctx = NULL; |
---|
400 | } |
---|
401 | } |
---|
402 | |
---|
403 | #endif /* KRB5 */ |
---|