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