source: trunk/third/ssh/auth-kerberos.c @ 12648

Revision 12648, 10.2 KB checked in by danw, 26 years ago (diff)
merge changes
Line 
1/*
2
3   auth-kerberos.c
4
5   Initally written by Dug Song <dugsong@umich.edu> for Kerberos V4.
6   Mapped over to user Kerberos V5 by Glenn Machin - Sandia Natl Labs
7
8   Kerberos authentication and ticket-passing routines.
9
10*/
11/*
12 * $Id: auth-kerberos.c,v 1.11 1999-03-08 18:20:00 danw Exp $
13 * $Log: not supported by cvs2svn $
14 * Revision 1.10  1998/11/09 16:25:21  ghudson
15 * Close some possible buffer overflows.
16 *
17 * Revision 1.9  1998/08/01 18:38:49  danw
18 * from amu: malloc enough space to store the full ticket file name
19 *
20 * Revision 1.8  1998/07/28 03:15:50  ghudson
21 * Dan didn't actually just leave out a right paren; he put in a
22 * semicolon instead.  Nuke the semicolon.
23 *
24 * Revision 1.7  1998/07/15 22:48:53  ghudson
25 * Dan left out a right paren.
26 *
27 * Revision 1.6  1998/07/14 17:34:49  danw
28 * use krb5_build_principal_ext instead of krb5_build_principal in case
29 * the realm data isn't NUL-terminated
30 *
31 * Revision 1.5  1998/01/24 01:47:20  danw
32 * merge in changes for 1.2.22
33 *
34 * Revision 1.4  1997/11/19 20:44:42  danw
35 * do chown later
36 *
37 * Revision 1.3  1997/11/15 00:04:12  danw
38 * Use atexit() functions to destroy tickets and call al_acct_revert.
39 * Work around Solaris lossage with libucb and grantpt.
40 *
41 * Revision 1.2  1997/11/12 21:16:08  danw
42 * Athena-login changes (including some krb4 stuff)
43 *
44 * Revision 1.1.1.1  1997/10/17 22:26:14  danw
45 * Import of ssh 1.2.21
46 *
47 * Revision 1.1.1.2  1998/01/24 01:25:35  danw
48 * Import of ssh 1.2.22
49 *
50 * Revision 1.1.1.3  1999/03/08 17:43:32  danw
51 * Import of ssh 1.2.26
52 *
53 * Revision 1.3  1998/01/02 06:13:56  kivinen
54 *      Fixed kerberos ticket allocation.
55 *
56 * Revision 1.2  1997/04/17 03:56:51  kivinen
57 *      Kept FILE: prefix in kerberos ticket filename as DCE cache
58 *      code requires it (patch from Doug Engert <DEEngert@anl.gov>).
59 *
60 * Revision 1.1  1997/03/27 03:09:29  kivinen
61 * *** empty log message ***
62 *
63 *
64 * $Endlog$
65 */
66
67#include "includes.h"
68#include "packet.h"
69#include "xmalloc.h"
70#include "ssh.h"
71
72#ifdef KERBEROS
73#if defined (KRB5)
74#include <krb5.h>
75/* kludge to allow us to #include krb.h without namespace conflicts */
76#define des_cbc_encrypt krb_des_cbc_encrypt
77#include <krb.h>
78
79extern  krb5_context ssh_context;
80extern  krb5_auth_context auth_context;
81extern  int havecred;
82void    krb_cleanup(void);
83
84int auth_kerberos(char *server_user, krb5_data *auth, krb5_principal *client)
85{
86  krb5_error_code problem;
87  krb5_ticket *ticket;
88  krb5_data reply;
89  krb5_principal tkt_client;
90  char *server = 0;
91 
92  memset(&reply, 0, sizeof(reply));
93 
94  if (auth_context)
95    krb5_auth_con_free(ssh_context, auth_context);
96
97  auth_context = 0;
98  krb5_auth_con_init(ssh_context, &auth_context);
99  problem =
100    krb5_auth_con_genaddrs(ssh_context, auth_context,
101                           packet_get_connection_in(),
102                           KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
103  if (problem)
104    {
105      if (auth_context)
106        {
107          krb5_auth_con_free(ssh_context, auth_context);
108          auth_context = 0;
109        }
110      log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
111              server_user, error_message(problem));
112     
113      debug("Kerberos krb5_auth_con_genaddrs (%.100s).", error_message(problem));
114      packet_send_debug("Kerberos krb5_auth_con_genaddrs: %.100s",
115                        error_message(problem));
116      return 0;
117    }
118  problem = krb5_rd_req(ssh_context, &auth_context, auth,
119                        NULL, NULL, NULL, &ticket);
120  if (problem)
121    {
122      if (auth_context)
123        {
124          krb5_auth_con_free(ssh_context, auth_context);
125          auth_context = 0; 
126        }
127      log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
128              server_user, error_message(problem));
129     
130      debug("Kerberos V5 rd_req failed (%.100s).", error_message(problem));
131      packet_send_debug("Kerberos V5 krb5_rd_req: %.100s", error_message(problem));
132      return 0;
133    }
134 
135  /* Verify from ticket that the server used was of the form host/system */
136  problem = krb5_unparse_name(ssh_context, ticket->server, &server);
137  if (problem)
138    {
139      krb5_free_ticket(ssh_context, ticket);
140      log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
141              server_user, error_message(problem));
142     
143      debug("Kerberos krb5_unparse_name failed (%.100s).", error_message(problem));
144      packet_send_debug("Kerberos krb5_unparse_name: %.100s",
145                        error_message(problem));
146      return 0;
147    }
148  if (strncmp(server, "host/", strlen("host/")))
149    {
150      krb5_free_ticket(ssh_context, ticket);
151      log_msg("Kerberos ticket authentication of user %.100s failed: invalid service name (%.100s)",
152              server_user, server);
153     
154      debug("Kerberos invalid service name (%.100s).", server);
155      packet_send_debug("Kerberos invalid service name (%.100s).", server);
156      krb5_xfree(server);
157      return 0;
158    }
159  krb5_xfree(server);
160 
161  /* Extract the users name from the ticket client principal */
162  problem = krb5_copy_principal(ssh_context, ticket->enc_part2->client,
163                                &tkt_client);
164 
165  krb5_free_ticket(ssh_context, ticket);
166 
167  if (problem)
168    {
169      log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
170              server_user, error_message(problem));
171      debug("Kerberos krb5_copy_principal failed (%.100s).",
172            error_message(problem));
173      packet_send_debug("Kerberos krb5_copy_principal: %.100s",
174                        error_message(problem));
175      return 0;
176    }
177  *client = tkt_client;
178 
179  /* Make the reply - so that mutual authentication can be done */
180  if ((problem = krb5_mk_rep(ssh_context, auth_context, &reply)))
181    {
182      log_msg("Kerberos ticket authentication of user %.100s failed: %.100s",
183              server_user, error_message(problem));
184      debug("Kerberos krb5_mk_rep failed (%.100s).",
185            error_message(problem));
186      packet_send_debug("Kerberos krb5_mk_rep failed: %.100s",
187                        error_message(problem));
188      return 0;
189    }
190 
191  packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
192  packet_put_string((char *) reply.data, reply.length);
193  packet_send();
194  packet_write_wait();
195  krb5_xfree(reply.data);
196  return 1;
197}
198#endif /* KRB5 */
199#endif /* KERBEROS */
200
201#ifdef KERBEROS_TGT_PASSING
202#if defined (KRB5)
203int auth_kerberos_tgt( char *server_user, krb5_data *krb5data)
204{
205  krb5_creds **creds;
206  krb5_error_code retval;
207  static char ccname[512], tktname[512];
208  krb5_ccache ccache = NULL;
209  struct passwd *pwd;
210  extern char *ticket;
211  static krb5_principal rcache_server = 0;
212  static krb5_rcache rcache;
213  struct sockaddr_in local, foreign;
214  krb5_address *local_addr, *remote_addr;
215  int s;
216  krb5_data *realm;
217  krb5_creds increds, *v5creds;
218  CREDENTIALS v4creds;
219 
220  if (!(pwd = (struct passwd *) getpwnam(server_user)))
221    {
222      log_msg("Kerberos V5 tgt rejected for user %.100s", server_user);
223      packet_send_debug("Kerberos V5 tgt rejected for %.100s", server_user);
224      packet_start(SSH_SMSG_FAILURE);
225      packet_send();
226      packet_write_wait();
227      return 0;
228    }
229 
230  if (!auth_context)
231    {
232      if (!rcache_server)
233        krb5_parse_name(ssh_context,"sshd", &rcache_server);
234      krb5_auth_con_init(ssh_context, &auth_context);
235     
236      /* Set the addresses for local and remote systems, and replay
237         cache */
238     
239      /* GDM : We need to establish the local addresses and remote addresses
240         within auth_context, in order to to TGT forwarding. Normally
241         when the authentication credentials are passed, these are
242         established then, however in SSH the forwarded TGT is
243         passed prior to authentication. (Needed by AFS) */
244     
245      s = packet_get_connection_in();
246      krb5_auth_con_genaddrs(ssh_context, auth_context, s,
247                             KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR |
248                             KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR);
249      krb5_get_server_rcache(ssh_context,
250                             krb5_princ_component(context, rcache_server, 0),
251                             &rcache);
252      krb5_auth_con_setrcache( ssh_context, auth_context, rcache);
253     
254    }
255 
256  if (retval = krb5_rd_cred(ssh_context, auth_context, krb5data, &creds, NULL))
257    {
258      log_msg("Kerberos V5 tgt rejected for user %.100s : %.100s", server_user,
259              error_message(retval));
260      packet_send_debug("Kerberos V5 tgt rejected for %.100s : %.100s",
261                        server_user,
262                        error_message(retval));
263      packet_start(SSH_SMSG_FAILURE);
264      packet_send();
265      packet_write_wait();
266      return 0;
267    }
268 
269  sprintf(ccname, "FILE:/tmp/krb5cc_p%d", getpid());
270 
271  if (retval = krb5_cc_resolve(ssh_context, ccname, &ccache))
272    goto errout;
273 
274  if (retval = krb5_cc_initialize(ssh_context, ccache, (*creds)->client))
275    goto errout;
276 
277  if (retval = krb5_cc_store_cred(ssh_context, ccache, *creds))
278    goto errout;
279 
280  ticket = xmalloc(strlen(ccname) + 1);
281  (void) sprintf(ticket, "%.100s", ccname);
282 
283  /* Now try to get krb4 tickets */
284  krb524_init_ets(ssh_context);
285  realm = krb5_princ_realm(ssh_context, (*creds)->client);
286  memset(&increds, 0, sizeof(increds));
287  if (retval = krb5_build_principal_ext(ssh_context, &(increds.server),
288                                        realm->length, realm->data, 6,
289                                        "krbtgt", realm->length, realm->data,
290                                        NULL))
291    goto errout2;
292
293  increds.client = (*creds)->client;
294  increds.times.endtime = 0;
295  increds.keyblock.enctype = ENCTYPE_DES_CBC_CRC;
296  if (retval = krb5_get_credentials(ssh_context, 0, ccache, &increds,
297                                    &v5creds))
298    goto errout2;
299 
300  if (retval = krb524_convert_creds_kdc(ssh_context, v5creds, &v4creds))
301    goto errout2;
302
303  sprintf(tktname, "KRBTKFILE=/tmp/tkt_p%d", getpid());
304  putenv(xstrdup(tktname));
305  if (retval = in_tkt(v4creds.pname, v4creds.pinst))
306    goto errout2;
307
308  if (retval = krb_save_credentials(v4creds.service, v4creds.instance,
309                                    v4creds.realm, v4creds.session,
310                                    v4creds.lifetime, v4creds.kvno,
311                                    &(v4creds.ticket_st), v4creds.issue_date))
312    goto errout2;
313
314  /* Successful */
315  packet_start(SSH_SMSG_SUCCESS);
316  packet_send();
317  packet_write_wait();
318  havecred = 1;
319  atexit(krb_cleanup);
320  return 1;
321 
322errout3:
323  dest_tkt();
324errout2:
325  krb5_cc_destroy(ssh_context, ccache);
326errout:
327  krb5_free_tgt_creds(ssh_context, creds);
328  log_msg("Kerberos V5 tgt rejected for user %.100s :%.100s", server_user,
329          error_message(retval));
330  packet_send_debug("Kerberos V5 tgt rejected for %.100s : %.100s", server_user,
331                    error_message(retval));
332  packet_start(SSH_SMSG_FAILURE);
333  packet_send();
334  packet_write_wait();
335  return 0;
336 
337}
338#endif /* KRB5 */
339#endif /* KERBEROS_TGT_PASSING */
340
Note: See TracBrowser for help on using the repository browser.