xref: /freebsd/crypto/openssh/auth-krb5.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
1 /*
2  *    Kerberos v5 authentication and ticket-passing routines.
3  *
4  * $FreeBSD$
5  */
6 
7 #include "includes.h"
8 #include "ssh.h"
9 #include "ssh1.h"
10 #include "packet.h"
11 #include "xmalloc.h"
12 
13 #ifdef KRB5
14 
15 krb5_context ssh_context = NULL;
16 krb5_auth_context auth_context;
17 krb5_ccache mem_ccache = NULL; /* Credential cache for acquired ticket */
18 
19 /* Try krb5 authentication. server_user is passed for logging purposes only,
20    in auth is received ticket, in client is returned principal from the
21    ticket */
22 int
23 auth_krb5(const char* server_user, krb5_data *auth, krb5_principal *client)
24 {
25 	krb5_error_code problem;
26 	krb5_principal server = NULL;
27 	krb5_principal tkt_client = NULL;
28 	krb5_data reply;
29 	krb5_ticket *ticket = NULL;
30 	int fd;
31 	int ret;
32 
33 	reply.length = 0;
34 
35 	problem = krb5_init();
36 	if (problem)
37 	   return 0;
38 
39 	problem = krb5_auth_con_init(ssh_context, &auth_context);
40 	if (problem) {
41 	  log("Kerberos v5 authentication failed: %.100s",
42 	       krb5_get_err_text(ssh_context, problem));
43 
44 	  return 0;
45 	}
46 
47        fd = packet_get_connection_in();
48        problem = krb5_auth_con_setaddrs_from_fd(ssh_context, auth_context, &fd);
49        if (problem) {
50 	 ret = 0;
51 	 goto err;
52        }
53 
54 	problem = krb5_sname_to_principal(ssh_context,  NULL, NULL ,
55 	    KRB5_NT_SRV_HST, &server);
56 	if (problem) {
57 	    ret = 0;
58 	    goto err;
59 	}
60 
61 	problem = krb5_rd_req(ssh_context, &auth_context, auth, server, NULL,
62 	    NULL, &ticket);
63 	if (problem) {
64 	  ret = 0;
65 	  goto err;
66 	}
67 
68 	problem = krb5_copy_principal(ssh_context, ticket->client, &tkt_client);
69 	if (problem) {
70 	  ret = 0;
71 	  goto err;
72 	}
73 
74 	/* if client wants mutual auth */
75 	problem = krb5_mk_rep(ssh_context, auth_context, &reply);
76 	if (problem) {
77 	  ret = 0;
78 	  goto err;
79 	}
80 
81 	*client = tkt_client;
82 
83 	packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE);
84 	packet_put_string((char *) reply.data, reply.length);
85 	packet_send();
86 	packet_write_wait();
87 	ret = 1;
88 
89 err:
90 	if (server)
91 	  krb5_free_principal(ssh_context, server);
92 	if (ticket)
93 	  krb5_free_ticket(ssh_context, ticket);
94 	if (reply.length)
95 	  xfree(reply.data);
96 	return ret;
97 }
98 
99 int
100 auth_krb5_tgt(char *server_user, krb5_data *tgt, krb5_principal tkt_client)
101 {
102   krb5_error_code problem;
103   krb5_ccache ccache = NULL;
104 
105   if (ssh_context == NULL) {
106      goto fail;
107   }
108 
109   problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
110   if (problem) {
111      goto fail;
112   }
113 
114   problem = krb5_cc_initialize(ssh_context, ccache, tkt_client);
115   if (problem) {
116      goto fail;
117   }
118 
119   problem = krb5_rd_cred2(ssh_context, auth_context, ccache, tgt);
120   if (problem) {
121      goto fail;
122   }
123 
124   mem_ccache = ccache;
125   ccache = NULL;
126 
127   /*
128   problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
129   if (problem) {
130      mem_ccache = NULL;
131      goto fail;
132   }
133 
134 
135   problem = krb5_cc_destroy(ssh_context, ccache);
136   if (problem)
137      goto fail;
138      */
139 
140 #if 0
141   packet_start(SSH_SMSG_SUCCESS);
142   packet_send();
143   packet_write_wait();
144 #endif
145   return 1;
146 
147 fail:
148   if (ccache)
149      krb5_cc_destroy(ssh_context, ccache);
150 #if 0
151   packet_start(SSH_SMSG_FAILURE);
152   packet_send();
153   packet_write_wait();
154 #endif
155   return 0;
156 }
157 
158 int
159 auth_krb5_password(struct passwd *pw, const char *password)
160 {
161   krb5_error_code problem;
162   krb5_ccache ccache = NULL;
163   krb5_principal client = NULL;
164   int ret;
165 
166   problem = krb5_init();
167   if (problem)
168      return 0;
169 
170   problem = krb5_parse_name(ssh_context, pw->pw_name, &client);
171   if (problem) {
172      ret = 0;
173      goto out;
174   }
175 
176   problem = krb5_cc_gen_new(ssh_context, &krb5_mcc_ops, &ccache);
177   if (problem) {
178      ret = 0;
179      goto out;
180   }
181 
182   problem = krb5_cc_initialize(ssh_context, ccache, client);
183   if (problem) {
184      ret = 0;
185      goto out;
186   }
187 
188   problem = krb5_verify_user(ssh_context, client, ccache, password, 1, NULL);
189   if (problem) {
190      ret = 0;
191      goto out;
192   }
193 
194 /*
195   problem = krb5_cc_copy_cache(ssh_context, ccache, mem_ccache);
196   if (problem) {
197      ret = 0;
198      mem_ccache = NULL;
199      goto out;
200   }
201   */
202   mem_ccache = ccache;
203   ccache = NULL;
204 
205   ret = 1;
206 out:
207   if (client != NULL)
208      krb5_free_principal(ssh_context, client);
209   if (ccache != NULL)
210      krb5_cc_destroy(ssh_context, ccache);
211   return ret;
212 }
213 
214 void
215 krb5_cleanup_proc(void *ignore)
216 {
217    extern krb5_principal tkt_client;
218 
219    debug("krb5_cleanup_proc() called");
220    if (mem_ccache)
221       krb5_cc_destroy(ssh_context, mem_ccache);
222    if (tkt_client)
223       krb5_free_principal(ssh_context, tkt_client);
224    if (auth_context)
225       krb5_auth_con_free(ssh_context, auth_context);
226    if (ssh_context)
227       krb5_free_context(ssh_context);
228 }
229 
230 int
231 krb5_init(void)
232 {
233    krb5_error_code problem;
234    static cleanup_registered = 0;
235 
236    if (ssh_context == NULL) {
237       problem = krb5_init_context(&ssh_context);
238       if (problem)
239 	 return problem;
240       krb5_init_ets(ssh_context);
241    }
242 
243    if (!cleanup_registered) {
244       fatal_add_cleanup(krb5_cleanup_proc, NULL);
245      cleanup_registered = 1;
246    }
247    return 0;
248 }
249 
250 #endif /* KRB5 */
251