]>
Commit | Line | Data |
---|---|---|
aa9f6a6e | 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 $ | |
aa9f6a6e | 5 | */ |
6 | ||
7 | #include "includes.h" | |
93c3b6de | 8 | RCSID("$OpenBSD: auth-krb5.c,v 1.6 2002/03/04 17:27:39 stevesk Exp $"); |
9 | ||
aa9f6a6e | 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> | |
21 | ||
22 | extern ServerOptions options; | |
23 | ||
24 | static int | |
25 | krb5_init(void *context) | |
26 | { | |
27 | Authctxt *authctxt = (Authctxt *)context; | |
28 | krb5_error_code problem; | |
29 | static int cleanup_registered = 0; | |
a0105740 | 30 | |
aa9f6a6e | 31 | if (authctxt->krb5_ctx == NULL) { |
32 | problem = krb5_init_context(&authctxt->krb5_ctx); | |
33 | if (problem) | |
34 | return (problem); | |
35 | krb5_init_ets(authctxt->krb5_ctx); | |
36 | } | |
37 | if (!cleanup_registered) { | |
38 | fatal_add_cleanup(krb5_cleanup_proc, authctxt); | |
39 | cleanup_registered = 1; | |
40 | } | |
41 | return (0); | |
42 | } | |
43 | ||
44 | /* | |
45 | * Try krb5 authentication. server_user is passed for logging purposes | |
46 | * only, in auth is received ticket, in client is returned principal | |
47 | * from the ticket | |
48 | */ | |
a0105740 | 49 | int |
aa9f6a6e | 50 | auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client) |
51 | { | |
52 | krb5_error_code problem; | |
53 | krb5_principal server; | |
54 | krb5_data reply; | |
55 | krb5_ticket *ticket; | |
ede8cea6 | 56 | int fd, ret; |
57 | ||
58 | ret = 0; | |
aa9f6a6e | 59 | server = NULL; |
60 | ticket = NULL; | |
61 | reply.length = 0; | |
a0105740 | 62 | |
aa9f6a6e | 63 | problem = krb5_init(authctxt); |
a0105740 | 64 | if (problem) |
aa9f6a6e | 65 | goto err; |
a0105740 | 66 | |
aa9f6a6e | 67 | problem = krb5_auth_con_init(authctxt->krb5_ctx, |
68 | &authctxt->krb5_auth_ctx); | |
69 | if (problem) | |
70 | goto err; | |
a0105740 | 71 | |
aa9f6a6e | 72 | fd = packet_get_connection_in(); |
73 | problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, | |
74 | authctxt->krb5_auth_ctx, &fd); | |
75 | if (problem) | |
76 | goto err; | |
a0105740 | 77 | |
aa9f6a6e | 78 | problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL , |
79 | KRB5_NT_SRV_HST, &server); | |
80 | if (problem) | |
81 | goto err; | |
a0105740 | 82 | |
aa9f6a6e | 83 | problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, |
84 | auth, server, NULL, NULL, &ticket); | |
85 | if (problem) | |
86 | goto err; | |
a0105740 | 87 | |
aa9f6a6e | 88 | problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, |
89 | &authctxt->krb5_user); | |
90 | if (problem) | |
91 | goto err; | |
a0105740 | 92 | |
aa9f6a6e | 93 | /* if client wants mutual auth */ |
94 | problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, | |
95 | &reply); | |
96 | if (problem) | |
97 | goto err; | |
a0105740 | 98 | |
aa9f6a6e | 99 | /* Check .k5login authorization now. */ |
100 | if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, | |
101 | authctxt->pw->pw_name)) | |
102 | goto err; | |
a0105740 | 103 | |
aa9f6a6e | 104 | if (client) |
105 | krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, | |
106 | client); | |
a0105740 | 107 | |
aa9f6a6e | 108 | packet_start(SSH_SMSG_AUTH_KERBEROS_RESPONSE); |
109 | packet_put_string((char *) reply.data, reply.length); | |
110 | packet_send(); | |
111 | packet_write_wait(); | |
ede8cea6 | 112 | |
113 | ret = 1; | |
aa9f6a6e | 114 | err: |
115 | if (server) | |
116 | krb5_free_principal(authctxt->krb5_ctx, server); | |
117 | if (ticket) | |
118 | krb5_free_ticket(authctxt->krb5_ctx, ticket); | |
119 | if (reply.length) | |
120 | xfree(reply.data); | |
a0105740 | 121 | |
c12337d9 | 122 | if (problem) { |
123 | if (authctxt->krb5_ctx != NULL) | |
124 | debug("Kerberos v5 authentication failed: %s", | |
125 | krb5_get_err_text(authctxt->krb5_ctx, problem)); | |
126 | else | |
127 | debug("Kerberos v5 authentication failed: %d", | |
128 | problem); | |
129 | } | |
ede8cea6 | 130 | |
131 | return (ret); | |
aa9f6a6e | 132 | } |
133 | ||
134 | int | |
135 | auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) | |
136 | { | |
137 | krb5_error_code problem; | |
138 | krb5_ccache ccache = NULL; | |
139 | char *pname; | |
a0105740 | 140 | |
aa9f6a6e | 141 | if (authctxt->pw == NULL || authctxt->krb5_user == NULL) |
142 | return (0); | |
a0105740 | 143 | |
aa9f6a6e | 144 | temporarily_use_uid(authctxt->pw); |
a0105740 | 145 | |
aa9f6a6e | 146 | problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache); |
147 | if (problem) | |
148 | goto fail; | |
a0105740 | 149 | |
aa9f6a6e | 150 | problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, |
151 | authctxt->krb5_user); | |
152 | if (problem) | |
153 | goto fail; | |
a0105740 | 154 | |
aa9f6a6e | 155 | problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, |
156 | ccache, tgt); | |
157 | if (problem) | |
158 | goto fail; | |
a0105740 | 159 | |
aa9f6a6e | 160 | authctxt->krb5_fwd_ccache = ccache; |
161 | ccache = NULL; | |
a0105740 | 162 | |
aa9f6a6e | 163 | authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
a0105740 | 164 | |
aa9f6a6e | 165 | problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, |
166 | &pname); | |
167 | if (problem) | |
168 | goto fail; | |
a0105740 | 169 | |
aa9f6a6e | 170 | debug("Kerberos v5 TGT accepted (%s)", pname); |
a0105740 | 171 | |
aa9f6a6e | 172 | restore_uid(); |
a0105740 | 173 | |
aa9f6a6e | 174 | return (1); |
a0105740 | 175 | |
aa9f6a6e | 176 | fail: |
177 | if (problem) | |
178 | debug("Kerberos v5 TGT passing failed: %s", | |
179 | krb5_get_err_text(authctxt->krb5_ctx, problem)); | |
180 | if (ccache) | |
181 | krb5_cc_destroy(authctxt->krb5_ctx, ccache); | |
a0105740 | 182 | |
aa9f6a6e | 183 | restore_uid(); |
a0105740 | 184 | |
aa9f6a6e | 185 | return (0); |
186 | } | |
187 | ||
188 | int | |
189 | auth_krb5_password(Authctxt *authctxt, const char *password) | |
190 | { | |
191 | krb5_error_code problem; | |
a0105740 | 192 | |
aa9f6a6e | 193 | if (authctxt->pw == NULL) |
194 | return (0); | |
a0105740 | 195 | |
aa9f6a6e | 196 | temporarily_use_uid(authctxt->pw); |
a0105740 | 197 | |
aa9f6a6e | 198 | problem = krb5_init(authctxt); |
199 | if (problem) | |
200 | goto out; | |
a0105740 | 201 | |
aa9f6a6e | 202 | problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, |
203 | &authctxt->krb5_user); | |
204 | if (problem) | |
205 | goto out; | |
a0105740 | 206 | |
aa9f6a6e | 207 | problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, |
208 | &authctxt->krb5_fwd_ccache); | |
209 | if (problem) | |
210 | goto out; | |
a0105740 | 211 | |
aa9f6a6e | 212 | problem = krb5_cc_initialize(authctxt->krb5_ctx, |
213 | authctxt->krb5_fwd_ccache, authctxt->krb5_user); | |
214 | if (problem) | |
215 | goto out; | |
a0105740 | 216 | |
217 | restore_uid(); | |
aa9f6a6e | 218 | problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, |
219 | authctxt->krb5_fwd_ccache, password, 1, NULL); | |
a0105740 | 220 | temporarily_use_uid(authctxt->pw); |
221 | ||
aa9f6a6e | 222 | if (problem) |
223 | goto out; | |
a0105740 | 224 | |
aa9f6a6e | 225 | authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); |
a0105740 | 226 | |
aa9f6a6e | 227 | out: |
228 | restore_uid(); | |
a0105740 | 229 | |
aa9f6a6e | 230 | if (problem) { |
c12337d9 | 231 | if (authctxt->krb5_ctx != NULL) |
232 | debug("Kerberos password authentication failed: %s", | |
233 | krb5_get_err_text(authctxt->krb5_ctx, problem)); | |
234 | else | |
235 | debug("Kerberos password authentication failed: %d", | |
236 | problem); | |
a0105740 | 237 | |
aa9f6a6e | 238 | krb5_cleanup_proc(authctxt); |
a0105740 | 239 | |
aa9f6a6e | 240 | if (options.kerberos_or_local_passwd) |
241 | return (-1); | |
242 | else | |
243 | return (0); | |
244 | } | |
245 | return (1); | |
246 | } | |
247 | ||
248 | void | |
249 | krb5_cleanup_proc(void *context) | |
250 | { | |
251 | Authctxt *authctxt = (Authctxt *)context; | |
a0105740 | 252 | |
aa9f6a6e | 253 | debug("krb5_cleanup_proc called"); |
254 | if (authctxt->krb5_fwd_ccache) { | |
255 | krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); | |
256 | authctxt->krb5_fwd_ccache = NULL; | |
257 | } | |
258 | if (authctxt->krb5_user) { | |
259 | krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); | |
260 | authctxt->krb5_user = NULL; | |
261 | } | |
262 | if (authctxt->krb5_auth_ctx) { | |
263 | krb5_auth_con_free(authctxt->krb5_ctx, | |
264 | authctxt->krb5_auth_ctx); | |
265 | authctxt->krb5_auth_ctx = NULL; | |
266 | } | |
267 | if (authctxt->krb5_ctx) { | |
268 | krb5_free_context(authctxt->krb5_ctx); | |
269 | authctxt->krb5_ctx = NULL; | |
270 | } | |
271 | } | |
272 | ||
273 | #endif /* KRB5 */ |