]> andersk Git - gssapi-openssh.git/blob - openssh/auth-krb5.c
o Remove two gsi_openssh* packages from bundle module.
[gssapi-openssh.git] / openssh / auth-krb5.c
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.10 2002/11/21 23:03:51 deraadt 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
57         if (authctxt->krb5_ctx == NULL) {
58                 problem = krb5_init_context(&authctxt->krb5_ctx);
59                 if (problem)
60                         return (problem);
61                 krb5_init_ets(authctxt->krb5_ctx);
62         }
63         if (!cleanup_registered) {
64                 fatal_add_cleanup(krb5_cleanup_proc, authctxt);
65                 cleanup_registered = 1;
66         }
67         return (0);
68 }
69
70 /*
71  * Try krb5 authentication. server_user is passed for logging purposes
72  * only, in auth is received ticket, in client is returned principal
73  * from the ticket
74  */
75 int
76 auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *reply)
77 {
78         krb5_error_code problem;
79         krb5_principal server;
80         krb5_ticket *ticket;
81         int fd, ret;
82
83         ret = 0;
84         server = NULL;
85         ticket = NULL;
86         reply->length = 0;
87
88         problem = krb5_init(authctxt);
89         if (problem)
90                 goto err;
91
92         problem = krb5_auth_con_init(authctxt->krb5_ctx,
93             &authctxt->krb5_auth_ctx);
94         if (problem)
95                 goto err;
96
97         fd = packet_get_connection_in();
98 #ifdef HEIMDAL
99         problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx,
100             authctxt->krb5_auth_ctx, &fd);
101 #else
102         problem = krb5_auth_con_genaddrs(authctxt->krb5_ctx, 
103             authctxt->krb5_auth_ctx,fd,
104             KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR |
105             KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
106 #endif
107         if (problem)
108                 goto err;
109
110         problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
111             KRB5_NT_SRV_HST, &server);
112         if (problem)
113                 goto err;
114
115         problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx,
116             auth, server, NULL, NULL, &ticket);
117         if (problem)
118                 goto err;
119
120 #ifdef HEIMDAL
121         problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client,
122             &authctxt->krb5_user);
123 #else
124         problem = krb5_copy_principal(authctxt->krb5_ctx, 
125                                       ticket->enc_part2->client,
126                                       &authctxt->krb5_user);
127 #endif
128         if (problem)
129                 goto err;
130
131         /* if client wants mutual auth */
132         problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
133             reply);
134         if (problem)
135                 goto err;
136
137         /* Check .k5login authorization now. */
138         if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user,
139             authctxt->pw->pw_name))
140                 goto err;
141
142         if (client)
143                 krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
144                     client);
145
146         ret = 1;
147  err:
148         if (server)
149                 krb5_free_principal(authctxt->krb5_ctx, server);
150         if (ticket)
151                 krb5_free_ticket(authctxt->krb5_ctx, ticket);
152         if (!ret && reply->length) {
153                 xfree(reply->data);
154                 memset(reply, 0, sizeof(*reply));
155         }
156
157         if (problem) {
158                 if (authctxt->krb5_ctx != NULL)
159                         debug("Kerberos v5 authentication failed: %s",
160                             krb5_get_err_text(authctxt->krb5_ctx, problem));
161                 else
162                         debug("Kerberos v5 authentication failed: %d",
163                             problem);
164         }
165
166         return (ret);
167 }
168
169 int
170 auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt)
171 {
172         krb5_error_code problem;
173         krb5_ccache ccache = NULL;
174         char *pname;
175         krb5_creds **creds;
176
177         if (authctxt->pw == NULL || authctxt->krb5_user == NULL)
178                 return (0);
179
180         temporarily_use_uid(authctxt->pw);
181
182 #ifdef HEIMDAL
183         problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache);
184 #else
185 {
186         char ccname[40];
187         int tmpfd;
188         
189         snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
190         
191         if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
192                 log("mkstemp(): %.100s", strerror(errno));
193                 problem = errno;
194                 goto fail;
195         }
196         if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
197                 log("fchmod(): %.100s", strerror(errno));
198                 close(tmpfd);
199                 problem = errno;
200                 goto fail;
201         }
202         close(tmpfd);
203         problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &ccache);
204 }
205 #endif
206         if (problem)
207                 goto fail;
208
209         problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache,
210             authctxt->krb5_user);
211         if (problem)
212                 goto fail;
213
214 #ifdef HEIMDAL
215         problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
216             ccache, tgt);
217         if (problem)
218                 goto fail;
219 #else
220         problem = krb5_rd_cred(authctxt->krb5_ctx, authctxt->krb5_auth_ctx,
221             tgt, &creds, NULL);
222         if (problem)
223                 goto fail;
224         problem = krb5_cc_store_cred(authctxt->krb5_ctx, ccache, *creds);
225         if (problem)
226                 goto fail;
227 #endif
228
229         authctxt->krb5_fwd_ccache = ccache;
230         ccache = NULL;
231
232         authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
233
234         problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user,
235             &pname);
236         if (problem)
237                 goto fail;
238
239         debug("Kerberos v5 TGT accepted (%s)", pname);
240
241         restore_uid();
242
243         return (1);
244
245  fail:
246         if (problem)
247                 debug("Kerberos v5 TGT passing failed: %s",
248                     krb5_get_err_text(authctxt->krb5_ctx, problem));
249         if (ccache)
250                 krb5_cc_destroy(authctxt->krb5_ctx, ccache);
251
252         restore_uid();
253
254         return (0);
255 }
256
257 int
258 auth_krb5_password(Authctxt *authctxt, const char *password)
259 {
260 #ifndef HEIMDAL
261         krb5_creds creds;
262         krb5_principal server;
263         char ccname[40];
264         int tmpfd;
265 #endif  
266         krb5_error_code problem;
267
268         if (authctxt->pw == NULL)
269                 return (0);
270
271         temporarily_use_uid(authctxt->pw);
272
273         problem = krb5_init(authctxt);
274         if (problem)
275                 goto out;
276
277         problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name,
278                     &authctxt->krb5_user);
279         if (problem)
280                 goto out;
281
282 #ifdef HEIMDAL
283         problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops,
284             &authctxt->krb5_fwd_ccache);
285         if (problem)
286                 goto out;
287
288         problem = krb5_cc_initialize(authctxt->krb5_ctx,
289             authctxt->krb5_fwd_ccache, authctxt->krb5_user);
290         if (problem)
291                 goto out;
292
293         restore_uid();
294         problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user,
295             authctxt->krb5_fwd_ccache, password, 1, NULL);
296         temporarily_use_uid(authctxt->pw);
297
298         if (problem)
299                 goto out;
300
301 #else
302         problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds,
303             authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL);
304         if (problem)
305                 goto out;
306
307         problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL,
308             KRB5_NT_SRV_HST, &server);
309         if (problem)
310                 goto out;
311
312         restore_uid();
313         problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server,
314             NULL, NULL, NULL);
315         krb5_free_principal(authctxt->krb5_ctx, server);
316         temporarily_use_uid(authctxt->pw);
317         if (problem)
318                 goto out;
319         
320         if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, 
321                           authctxt->pw->pw_name)) {
322                 problem = -1;
323                 goto out;
324         } 
325
326         snprintf(ccname,sizeof(ccname),"FILE:/tmp/krb5cc_%d_XXXXXX",geteuid());
327         
328         if ((tmpfd = mkstemp(ccname+strlen("FILE:")))==-1) {
329                 log("mkstemp(): %.100s", strerror(errno));
330                 problem = errno;
331                 goto out;
332         }
333         
334         if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) {
335                 log("fchmod(): %.100s", strerror(errno));
336                 close(tmpfd);
337                 problem = errno;
338                 goto out;
339         }
340         close(tmpfd);
341
342         problem = krb5_cc_resolve(authctxt->krb5_ctx, ccname, &authctxt->krb5_fwd_ccache);
343         if (problem)
344                 goto out;
345
346         problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
347                                      authctxt->krb5_user);
348         if (problem)
349                 goto out;
350                                 
351         problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache,
352                                  &creds);
353         if (problem)
354                 goto out;
355 #endif          
356
357         authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
358
359  out:
360         restore_uid();
361
362         if (problem) {
363                 if (authctxt->krb5_ctx != NULL && problem!=-1)
364                         debug("Kerberos password authentication failed: %s",
365                             krb5_get_err_text(authctxt->krb5_ctx, problem));
366                 else
367                         debug("Kerberos password authentication failed: %d",
368                             problem);
369
370                 krb5_cleanup_proc(authctxt);
371
372                 if (options.kerberos_or_local_passwd)
373                         return (-1);
374                 else
375                         return (0);
376         }
377         return (1);
378 }
379
380 void
381 krb5_cleanup_proc(void *context)
382 {
383         Authctxt *authctxt = (Authctxt *)context;
384
385         debug("krb5_cleanup_proc called");
386         if (authctxt->krb5_fwd_ccache) {
387                 krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache);
388                 authctxt->krb5_fwd_ccache = NULL;
389         }
390         if (authctxt->krb5_user) {
391                 krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user);
392                 authctxt->krb5_user = NULL;
393         }
394         if (authctxt->krb5_auth_ctx) {
395                 krb5_auth_con_free(authctxt->krb5_ctx,
396                     authctxt->krb5_auth_ctx);
397                 authctxt->krb5_auth_ctx = NULL;
398         }
399         if (authctxt->krb5_ctx) {
400                 krb5_free_context(authctxt->krb5_ctx);
401                 authctxt->krb5_ctx = NULL;
402         }
403 }
404
405 #endif /* KRB5 */
This page took 1.828159 seconds and 5 git commands to generate.