]>
Commit | Line | Data |
---|---|---|
3c0ef626 | 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 $ | |
3c0ef626 | 5 | */ |
6 | ||
7 | #include "includes.h" | |
e9702f7d | 8 | RCSID("$OpenBSD: auth-krb5.c,v 1.6 2002/03/04 17:27:39 stevesk Exp $"); |
9 | ||
3c0ef626 | 10 | #include "ssh.h" |
11 | #include "ssh1.h" | |
12 | #include "packet.h" | |
13 | #include "xmalloc.h" | |
14 | #include "log.h" | |
15 | #include "servconf.h" | |
16 | #include "uidswap.h" | |
17 | #include "auth.h" | |
18 | ||
19 | #ifdef KRB5 | |
20 | #include <krb5.h> | |
63119dd9 | 21 | #ifndef HEIMDAL |
22 | #define krb5_get_err_text(context,code) error_message(code) | |
23 | #endif /* !HEIMDAL */ | |
3c0ef626 | 24 | |
25 | extern ServerOptions options; | |
26 | ||
27 | static int | |
28 | krb5_init(void *context) | |
29 | { | |
30 | Authctxt *authctxt = (Authctxt *)context; | |
31 | krb5_error_code problem; | |
32 | static int cleanup_registered = 0; | |
e9702f7d | 33 | |
3c0ef626 | 34 | if (authctxt->krb5_ctx == NULL) { |
35 | problem = krb5_init_context(&authctxt->krb5_ctx); | |
36 | if (problem) | |
37 | return (problem); | |
38 | krb5_init_ets(authctxt->krb5_ctx); | |
39 | } | |
40 | if (!cleanup_registered) { | |
41 | fatal_add_cleanup(krb5_cleanup_proc, authctxt); | |
42 | cleanup_registered = 1; | |
43 | } | |
44 | return (0); | |
45 | } | |
46 | ||
47 | /* | |
48 | * Try krb5 authentication. server_user is passed for logging purposes | |
49 | * only, in auth is received ticket, in client is returned principal | |
50 | * from the ticket | |
51 | */ | |
e9702f7d | 52 | int |
3c0ef626 | 53 | auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client) |
54 | { | |
55 | krb5_error_code problem; | |
56 | krb5_principal server; | |
57 | krb5_data reply; | |
58 | krb5_ticket *ticket; | |
59 | int fd, ret; | |
60 | ||
61 | ret = 0; | |
62 | server = NULL; | |
63 | ticket = NULL; | |
64 | reply.length = 0; | |
e9702f7d | 65 | |
3c0ef626 | 66 | problem = krb5_init(authctxt); |
e9702f7d | 67 | if (problem) |
3c0ef626 | 68 | goto err; |
e9702f7d | 69 | |
3c0ef626 | 70 | problem = krb5_auth_con_init(authctxt->krb5_ctx, |
71 | &authctxt->krb5_auth_ctx); | |
72 | if (problem) | |
73 | goto err; | |
e9702f7d | 74 | |
3c0ef626 | 75 | fd = packet_get_connection_in(); |
63119dd9 | 76 | #ifdef HEIMDAL |
3c0ef626 | 77 | problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, |
78 | authctxt->krb5_auth_ctx, &fd); | |
63119dd9 | 79 | #else |
80 | problem = krb5_auth_con_genaddrs(authctxt->krb5_ctx, | |
81 | authctxt->krb5_auth_ctx,fd, | |
82 | KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR | | |
83 | KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR); | |
84 | #endif | |
3c0ef626 | 85 | if (problem) |
86 | goto err; | |
e9702f7d | 87 | |
3c0ef626 | 88 | problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL , |
89 | KRB5_NT_SRV_HST, &server); | |
90 | if (problem) | |
91 | goto err; | |
e9702f7d | 92 | |
3c0ef626 | 93 | problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, |
94 | auth, server, NULL, NULL, &ticket); | |
95 | if (problem) | |
96 | goto err; | |
97 | ||
63119dd9 | 98 | #ifdef HEIMDAL |
3c0ef626 | 99 | problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, |
100 | &authctxt->krb5_user); | |
63119dd9 | 101 | #else |
102 | problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->enc_part2->client, | |
103 | &authctxt->krb5_user); | |
104 | #endif | |
3c0ef626 | 105 | if (problem) |
106 | goto err; | |
e9702f7d | 107 | |
3c0ef626 | 108 | /* if client wants mutual auth */ |
109 | problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, | |
110 | &reply); | |
111 | if (problem) | |
112 | goto err; | |
e9702f7d | 113 | |
3c0ef626 | 114 | /* Check .k5login authorization now. */ |
115 | if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, | |
116 | authctxt->pw->pw_name)) | |
117 | goto err; | |
e9702f7d | 118 | |
3c0ef626 | 119 | if (client) |
120 | krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, | |
121 | client); | |
e9702f7d | 122 | |
3c0ef626 | 123 | packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); |
124 | packet_put_string((char *) reply.data, reply.length); | |
125 | packet_send(); | |
126 | packet_write_wait(); | |
127 | ||
128 | ret = 1; | |
129 | err: | |
130 | if (server) | |
131 | krb5_free_principal(authctxt->krb5_ctx, server); | |
132 | if (ticket) | |
133 | krb5_free_ticket(authctxt->krb5_ctx, ticket); | |
134 | if (reply.length) | |
135 | xfree(reply.data); | |
e9702f7d | 136 | |
137 | if (problem) { | |
138 | if (authctxt->krb5_ctx != NULL) | |
139 | debug("Kerberos v5 authentication failed: %s", | |
140 | krb5_get_err_text(authctxt->krb5_ctx, problem)); | |
141 | else | |
142 | debug("Kerberos v5 authentication failed: %d", | |
143 | problem); | |
144 | } | |
3c0ef626 | 145 | |
146 | return (ret); | |
147 | } | |
148 | ||
149 | int | |
150 | auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) | |
151 | { | |
152 | krb5_error_code problem; | |
153 | krb5_ccache ccache = NULL; | |
154 | char *pname; | |
63119dd9 | 155 | krb5_creds **creds; |
3c0ef626 | 156 | |
157 | if (authctxt->pw == NULL || authctxt->krb5_user == NULL) | |
158 | return (0); | |
e9702f7d | 159 | |
3c0ef626 | 160 | temporarily_use_uid(authctxt->pw); |
161 | ||
63119dd9 | 162 | #ifdef HEIMDAL |
3c0ef626 | 163 | problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache); |
63119dd9 | 164 | #else |
165 | { | |
166 | char ccname[35]; | |
167 | ||
168 | snprintf(ccname, sizeof(ccname), "FILE:/tmp/krb5cc_%d", authctxt->pw->pw_uid); | |
169 | problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &ccache); | |
170 | } | |
171 | #endif | |
3c0ef626 | 172 | if (problem) |
173 | goto fail; | |
e9702f7d | 174 | |
3c0ef626 | 175 | problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, |
176 | authctxt->krb5_user); | |
177 | if (problem) | |
178 | goto fail; | |
179 | ||
63119dd9 | 180 | #ifdef HEIMDAL |
3c0ef626 | 181 | problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, |
182 | ccache, tgt); | |
183 | if (problem) | |
184 | goto fail; | |
63119dd9 | 185 | #else |
186 | problem = krb5_rd_cred(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, | |
187 | tgt, &creds, NULL); | |
188 | if (problem) | |
189 | goto fail; | |
190 | problem = krb5_cc_store_cred(authctxt->krb5_ctx, ccache, *creds); | |
191 | if (problem) | |
192 | goto fail; | |
193 | #endif | |
3c0ef626 | 194 | |
195 | authctxt->krb5_fwd_ccache = ccache; | |
196 | ccache = NULL; | |
e9702f7d | 197 | |
3c0ef626 | 198 | authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
e9702f7d | 199 | |
3c0ef626 | 200 | problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, |
201 | &pname); | |
202 | if (problem) | |
203 | goto fail; | |
e9702f7d | 204 | |
3c0ef626 | 205 | debug("Kerberos v5 TGT accepted (%s)", pname); |
e9702f7d | 206 | |
3c0ef626 | 207 | restore_uid(); |
e9702f7d | 208 | |
3c0ef626 | 209 | return (1); |
e9702f7d | 210 | |
3c0ef626 | 211 | fail: |
212 | if (problem) | |
213 | debug("Kerberos v5 TGT passing failed: %s", | |
214 | krb5_get_err_text(authctxt->krb5_ctx, problem)); | |
215 | if (ccache) | |
216 | krb5_cc_destroy(authctxt->krb5_ctx, ccache); | |
e9702f7d | 217 | |
3c0ef626 | 218 | restore_uid(); |
e9702f7d | 219 | |
3c0ef626 | 220 | return (0); |
221 | } | |
222 | ||
223 | int | |
224 | auth_krb5_password(Authctxt *authctxt, const char *password) | |
225 | { | |
63119dd9 | 226 | #ifndef HEIMDAL |
227 | krb5_creds creds; | |
228 | krb5_principal server; | |
229 | #endif | |
3c0ef626 | 230 | krb5_error_code problem; |
e9702f7d | 231 | |
3c0ef626 | 232 | if (authctxt->pw == NULL) |
233 | return (0); | |
e9702f7d | 234 | |
3c0ef626 | 235 | temporarily_use_uid(authctxt->pw); |
e9702f7d | 236 | |
3c0ef626 | 237 | problem = krb5_init(authctxt); |
238 | if (problem) | |
239 | goto out; | |
e9702f7d | 240 | |
3c0ef626 | 241 | problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, |
242 | &authctxt->krb5_user); | |
243 | if (problem) | |
244 | goto out; | |
245 | ||
63119dd9 | 246 | #ifdef HEIMDAL |
3c0ef626 | 247 | problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, |
248 | &authctxt->krb5_fwd_ccache); | |
63119dd9 | 249 | #else |
250 | problem = krb5_cc_resolve(authctxt->krb5_ctx, "MEMORY:", | |
251 | &authctxt->krb5_fwd_ccache); | |
252 | #endif | |
3c0ef626 | 253 | if (problem) |
254 | goto out; | |
e9702f7d | 255 | |
3c0ef626 | 256 | problem = krb5_cc_initialize(authctxt->krb5_ctx, |
257 | authctxt->krb5_fwd_ccache, authctxt->krb5_user); | |
258 | if (problem) | |
259 | goto out; | |
260 | ||
63119dd9 | 261 | #ifdef HEIMDAL |
e9702f7d | 262 | restore_uid(); |
3c0ef626 | 263 | problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, |
264 | authctxt->krb5_fwd_ccache, password, 1, NULL); | |
e9702f7d | 265 | temporarily_use_uid(authctxt->pw); |
266 | ||
3c0ef626 | 267 | if (problem) |
268 | goto out; | |
269 | ||
63119dd9 | 270 | #else |
271 | problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, | |
272 | authctxt->krb5_user, password, NULL, NULL, 0, NULL, NULL); | |
273 | if (problem) | |
274 | goto out; | |
275 | ||
276 | problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, | |
277 | KRB5_NT_SRV_HST, &server); | |
278 | if (problem) | |
279 | goto out; | |
280 | ||
281 | restore_uid(); | |
282 | problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, NULL, NULL, | |
283 | NULL); | |
284 | temporarily_use_uid(authctxt->pw); | |
285 | ||
286 | krb5_free_principal(authctxt->krb5_ctx, server); | |
287 | if (problem) | |
288 | goto out; | |
289 | ||
290 | problem = krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, &creds); | |
63119dd9 | 291 | |
292 | #endif /* HEIMDAL */ | |
293 | ||
3c0ef626 | 294 | authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
e9702f7d | 295 | |
3c0ef626 | 296 | out: |
297 | restore_uid(); | |
e9702f7d | 298 | |
3c0ef626 | 299 | if (problem) { |
e9702f7d | 300 | if (authctxt->krb5_ctx != NULL) |
301 | debug("Kerberos password authentication failed: %s", | |
302 | krb5_get_err_text(authctxt->krb5_ctx, problem)); | |
303 | else | |
304 | debug("Kerberos password authentication failed: %d", | |
305 | problem); | |
306 | ||
3c0ef626 | 307 | krb5_cleanup_proc(authctxt); |
e9702f7d | 308 | |
3c0ef626 | 309 | if (options.kerberos_or_local_passwd) |
310 | return (-1); | |
311 | else | |
312 | return (0); | |
313 | } | |
314 | return (1); | |
315 | } | |
316 | ||
317 | void | |
318 | krb5_cleanup_proc(void *context) | |
319 | { | |
320 | Authctxt *authctxt = (Authctxt *)context; | |
e9702f7d | 321 | |
3c0ef626 | 322 | debug("krb5_cleanup_proc called"); |
323 | if (authctxt->krb5_fwd_ccache) { | |
324 | krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); | |
325 | authctxt->krb5_fwd_ccache = NULL; | |
326 | } | |
327 | if (authctxt->krb5_user) { | |
328 | krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); | |
329 | authctxt->krb5_user = NULL; | |
330 | } | |
331 | if (authctxt->krb5_auth_ctx) { | |
332 | krb5_auth_con_free(authctxt->krb5_ctx, | |
333 | authctxt->krb5_auth_ctx); | |
334 | authctxt->krb5_auth_ctx = NULL; | |
335 | } | |
336 | if (authctxt->krb5_ctx) { | |
337 | krb5_free_context(authctxt->krb5_ctx); | |
338 | authctxt->krb5_ctx = NULL; | |
339 | } | |
340 | } | |
341 | ||
342 | #endif /* KRB5 */ |