1 /* $NetBSD: auth-krb5.c,v 1.2 2009/06/07 22:38:46 christos Exp $ */ 2 /* $OpenBSD: auth-krb5.c,v 1.19 2006/08/03 03:34:41 deraadt Exp $ */ 3 /* 4 * Kerberos v5 authentication and ticket-passing routines. 5 * 6 * $FreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp $ 7 */ 8 /* 9 * Copyright (c) 2002 Daniel Kouril. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include "includes.h" 33 __RCSID("$NetBSD: auth-krb5.c,v 1.2 2009/06/07 22:38:46 christos Exp $"); 34 #include <sys/types.h> 35 #include <pwd.h> 36 #include <stdarg.h> 37 #include <string.h> 38 39 #include "xmalloc.h" 40 #include "ssh.h" 41 #include "ssh1.h" 42 #include "packet.h" 43 #include "log.h" 44 #include "buffer.h" 45 #include "servconf.h" 46 #include "uidswap.h" 47 #include "key.h" 48 #include "hostfile.h" 49 #include "auth.h" 50 51 #ifdef KRB5 52 #include <krb5.h> 53 54 extern ServerOptions options; 55 56 static int 57 krb5_init(void *context) 58 { 59 Authctxt *authctxt = (Authctxt *)context; 60 krb5_error_code problem; 61 62 if (authctxt->krb5_ctx == NULL) { 63 problem = krb5_init_context(&authctxt->krb5_ctx); 64 if (problem) 65 return (problem); 66 krb5_init_ets(authctxt->krb5_ctx); 67 } 68 return (0); 69 } 70 71 /* 72 * Try krb5 authentication. server_user is passed for logging purposes 73 * only, in auth is received ticket, in client is returned principal 74 * from the ticket 75 */ 76 int 77 auth_krb5(Authctxt *authctxt, krb5_data *auth, char **client, krb5_data *reply) 78 { 79 krb5_error_code problem; 80 krb5_principal server; 81 krb5_ticket *ticket; 82 int fd, ret; 83 84 ret = 0; 85 server = NULL; 86 ticket = NULL; 87 reply->length = 0; 88 89 problem = krb5_init(authctxt); 90 if (problem) 91 goto err; 92 93 problem = krb5_auth_con_init(authctxt->krb5_ctx, 94 &authctxt->krb5_auth_ctx); 95 if (problem) 96 goto err; 97 98 fd = packet_get_connection_in(); 99 problem = krb5_auth_con_setaddrs_from_fd(authctxt->krb5_ctx, 100 authctxt->krb5_auth_ctx, &fd); 101 if (problem) 102 goto err; 103 104 problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, 105 KRB5_NT_SRV_HST, &server); 106 if (problem) 107 goto err; 108 109 problem = krb5_rd_req(authctxt->krb5_ctx, &authctxt->krb5_auth_ctx, 110 auth, server, NULL, NULL, &ticket); 111 if (problem) 112 goto err; 113 114 problem = krb5_copy_principal(authctxt->krb5_ctx, ticket->client, 115 &authctxt->krb5_user); 116 if (problem) 117 goto err; 118 119 /* if client wants mutual auth */ 120 problem = krb5_mk_rep(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, 121 reply); 122 if (problem) 123 goto err; 124 125 /* Check .k5login authorization now. */ 126 if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, 127 authctxt->pw->pw_name)) 128 goto err; 129 130 if (client) 131 krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, 132 client); 133 134 ret = 1; 135 err: 136 if (server) 137 krb5_free_principal(authctxt->krb5_ctx, server); 138 if (ticket) 139 krb5_free_ticket(authctxt->krb5_ctx, ticket); 140 if (!ret && reply->length) { 141 xfree(reply->data); 142 memset(reply, 0, sizeof(*reply)); 143 } 144 145 if (problem) { 146 if (authctxt->krb5_ctx != NULL) 147 debug("Kerberos v5 authentication failed: %s", 148 krb5_get_err_text(authctxt->krb5_ctx, problem)); 149 else 150 debug("Kerberos v5 authentication failed: %d", 151 problem); 152 } 153 154 return (ret); 155 } 156 157 int 158 auth_krb5_tgt(Authctxt *authctxt, krb5_data *tgt) 159 { 160 krb5_error_code problem; 161 krb5_ccache ccache = NULL; 162 char *pname; 163 164 if (authctxt->pw == NULL || authctxt->krb5_user == NULL) 165 return (0); 166 167 temporarily_use_uid(authctxt->pw); 168 169 problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, &ccache); 170 if (problem) 171 goto fail; 172 173 problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, 174 authctxt->krb5_user); 175 if (problem) 176 goto fail; 177 178 problem = krb5_rd_cred2(authctxt->krb5_ctx, authctxt->krb5_auth_ctx, 179 ccache, tgt); 180 if (problem) 181 goto fail; 182 183 authctxt->krb5_fwd_ccache = ccache; 184 ccache = NULL; 185 186 authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 187 188 problem = krb5_unparse_name(authctxt->krb5_ctx, authctxt->krb5_user, 189 &pname); 190 if (problem) 191 goto fail; 192 193 #ifdef USE_PAM 194 if (options.use_pam) 195 do_pam_putenv("KRB5CCNAME", authctxt->krb5_ticket_file); 196 #endif 197 debug("Kerberos v5 TGT accepted (%s)", pname); 198 199 restore_uid(); 200 201 return (1); 202 203 fail: 204 if (problem) 205 debug("Kerberos v5 TGT passing failed: %s", 206 krb5_get_err_text(authctxt->krb5_ctx, problem)); 207 if (ccache) 208 krb5_cc_destroy(authctxt->krb5_ctx, ccache); 209 210 restore_uid(); 211 212 return (0); 213 } 214 215 216 int 217 auth_krb5_password(Authctxt *authctxt, const char *password) 218 { 219 krb5_error_code problem; 220 krb5_ccache ccache = NULL; 221 222 temporarily_use_uid(authctxt->pw); 223 224 problem = krb5_init(authctxt); 225 if (problem) 226 goto out; 227 228 problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, 229 &authctxt->krb5_user); 230 if (problem) 231 goto out; 232 233 problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); 234 if (problem) 235 goto out; 236 237 problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, 238 authctxt->krb5_user); 239 if (problem) 240 goto out; 241 242 restore_uid(); 243 244 problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, 245 ccache, password, 1, NULL); 246 247 temporarily_use_uid(authctxt->pw); 248 249 if (problem) 250 goto out; 251 252 problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, 253 &authctxt->krb5_fwd_ccache); 254 if (problem) 255 goto out; 256 257 problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, 258 authctxt->krb5_fwd_ccache); 259 krb5_cc_destroy(authctxt->krb5_ctx, ccache); 260 ccache = NULL; 261 if (problem) 262 goto out; 263 264 authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, 265 authctxt->krb5_fwd_ccache); 266 267 out: 268 restore_uid(); 269 270 if (problem) { 271 if (ccache) 272 krb5_cc_destroy(authctxt->krb5_ctx, ccache); 273 274 if (authctxt->krb5_ctx != NULL) 275 debug("Kerberos password authentication failed: %s", 276 krb5_get_err_text(authctxt->krb5_ctx, problem)); 277 else 278 debug("Kerberos password authentication failed: %d", 279 problem); 280 281 krb5_cleanup_proc(authctxt); 282 283 if (options.kerberos_or_local_passwd) 284 return (-1); 285 else 286 return (0); 287 } 288 return (authctxt->valid ? 1 : 0); 289 } 290 291 void 292 krb5_cleanup_proc(Authctxt *authctxt) 293 { 294 debug("krb5_cleanup_proc called"); 295 if (authctxt->krb5_fwd_ccache) { 296 krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 297 authctxt->krb5_fwd_ccache = NULL; 298 } 299 if (authctxt->krb5_user) { 300 krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); 301 authctxt->krb5_user = NULL; 302 } 303 if (authctxt->krb5_auth_ctx) { 304 krb5_auth_con_free(authctxt->krb5_ctx, 305 authctxt->krb5_auth_ctx); 306 authctxt->krb5_auth_ctx = NULL; 307 } 308 if (authctxt->krb5_ctx) { 309 krb5_free_context(authctxt->krb5_ctx); 310 authctxt->krb5_ctx = NULL; 311 } 312 } 313 314 #endif /* KRB5 */ 315