1 /* 2 * Kerberos v5 authentication and ticket-passing routines. 3 * 4 * $xFreeBSD: src/crypto/openssh/auth-krb5.c,v 1.6 2001/02/13 16:58:04 assar Exp$ 5 */ 6 /* 7 * Copyright (c) 2002 Daniel Kouril. All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "includes.h" 31 RCSID("$OpenBSD: auth-krb5.c,v 1.15 2003/11/21 11:57:02 djm Exp $"); 32 RCSID("$FreeBSD$"); 33 34 #include "ssh.h" 35 #include "ssh1.h" 36 #include "packet.h" 37 #include "xmalloc.h" 38 #include "log.h" 39 #include "servconf.h" 40 #include "uidswap.h" 41 #include "auth.h" 42 43 #ifdef KRB5 44 #include <krb5.h> 45 46 extern ServerOptions options; 47 48 static int 49 krb5_init(void *context) 50 { 51 Authctxt *authctxt = (Authctxt *)context; 52 krb5_error_code problem; 53 54 if (authctxt->krb5_ctx == NULL) { 55 problem = krb5_init_context(&authctxt->krb5_ctx); 56 if (problem) 57 return (problem); 58 } 59 return (0); 60 } 61 62 int 63 auth_krb5_password(Authctxt *authctxt, const char *password) 64 { 65 #ifndef HEIMDAL 66 krb5_creds creds; 67 krb5_principal server; 68 #endif 69 krb5_error_code problem; 70 krb5_ccache ccache = NULL; 71 int len; 72 73 if (!authctxt->valid) 74 return (0); 75 76 temporarily_use_uid(authctxt->pw); 77 78 problem = krb5_init(authctxt); 79 if (problem) 80 goto out; 81 82 problem = krb5_parse_name(authctxt->krb5_ctx, authctxt->pw->pw_name, 83 &authctxt->krb5_user); 84 if (problem) 85 goto out; 86 87 #ifdef HEIMDAL 88 problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_mcc_ops, &ccache); 89 if (problem) 90 goto out; 91 92 problem = krb5_cc_initialize(authctxt->krb5_ctx, ccache, 93 authctxt->krb5_user); 94 if (problem) 95 goto out; 96 97 restore_uid(); 98 99 problem = krb5_verify_user(authctxt->krb5_ctx, authctxt->krb5_user, 100 ccache, password, 1, NULL); 101 102 temporarily_use_uid(authctxt->pw); 103 104 if (problem) 105 goto out; 106 107 problem = krb5_cc_gen_new(authctxt->krb5_ctx, &krb5_fcc_ops, 108 &authctxt->krb5_fwd_ccache); 109 if (problem) 110 goto out; 111 112 problem = krb5_cc_copy_cache(authctxt->krb5_ctx, ccache, 113 authctxt->krb5_fwd_ccache); 114 krb5_cc_destroy(authctxt->krb5_ctx, ccache); 115 ccache = NULL; 116 if (problem) 117 goto out; 118 119 #else 120 problem = krb5_get_init_creds_password(authctxt->krb5_ctx, &creds, 121 authctxt->krb5_user, (char *)password, NULL, NULL, 0, NULL, NULL); 122 if (problem) 123 goto out; 124 125 problem = krb5_sname_to_principal(authctxt->krb5_ctx, NULL, NULL, 126 KRB5_NT_SRV_HST, &server); 127 if (problem) 128 goto out; 129 130 restore_uid(); 131 problem = krb5_verify_init_creds(authctxt->krb5_ctx, &creds, server, 132 NULL, NULL, NULL); 133 krb5_free_principal(authctxt->krb5_ctx, server); 134 temporarily_use_uid(authctxt->pw); 135 if (problem) 136 goto out; 137 138 if (!krb5_kuserok(authctxt->krb5_ctx, authctxt->krb5_user, 139 authctxt->pw->pw_name)) { 140 problem = -1; 141 goto out; 142 } 143 144 problem = ssh_krb5_cc_gen(authctxt->krb5_ctx, &authctxt->krb5_fwd_ccache); 145 if (problem) 146 goto out; 147 148 problem = krb5_cc_initialize(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, 149 authctxt->krb5_user); 150 if (problem) 151 goto out; 152 153 problem= krb5_cc_store_cred(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache, 154 &creds); 155 if (problem) 156 goto out; 157 #endif 158 159 authctxt->krb5_ticket_file = (char *)krb5_cc_get_name(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 160 161 len = strlen(authctxt->krb5_ticket_file) + 6; 162 authctxt->krb5_ccname = xmalloc(len); 163 snprintf(authctxt->krb5_ccname, len, "FILE:%s", 164 authctxt->krb5_ticket_file); 165 166 #ifdef USE_PAM 167 if (options.use_pam) 168 do_pam_putenv("KRB5CCNAME", authctxt->krb5_ccname); 169 #endif 170 171 out: 172 restore_uid(); 173 174 if (problem) { 175 if (ccache) 176 krb5_cc_destroy(authctxt->krb5_ctx, ccache); 177 178 if (authctxt->krb5_ctx != NULL && problem!=-1) 179 debug("Kerberos password authentication failed: %s", 180 krb5_get_err_text(authctxt->krb5_ctx, problem)); 181 else 182 debug("Kerberos password authentication failed: %d", 183 problem); 184 185 krb5_cleanup_proc(authctxt); 186 187 if (options.kerberos_or_local_passwd) 188 return (-1); 189 else 190 return (0); 191 } 192 return (1); 193 } 194 195 void 196 krb5_cleanup_proc(Authctxt *authctxt) 197 { 198 debug("krb5_cleanup_proc called"); 199 if (authctxt->krb5_fwd_ccache) { 200 krb5_cc_destroy(authctxt->krb5_ctx, authctxt->krb5_fwd_ccache); 201 authctxt->krb5_fwd_ccache = NULL; 202 } 203 if (authctxt->krb5_user) { 204 krb5_free_principal(authctxt->krb5_ctx, authctxt->krb5_user); 205 authctxt->krb5_user = NULL; 206 } 207 if (authctxt->krb5_ctx) { 208 krb5_free_context(authctxt->krb5_ctx); 209 authctxt->krb5_ctx = NULL; 210 } 211 } 212 213 #ifndef HEIMDAL 214 krb5_error_code 215 ssh_krb5_cc_gen(krb5_context ctx, krb5_ccache *ccache) { 216 int tmpfd, ret; 217 char ccname[40]; 218 mode_t old_umask; 219 220 ret = snprintf(ccname, sizeof(ccname), 221 "FILE:/tmp/krb5cc_%d_XXXXXXXXXX", geteuid()); 222 if (ret == -1 || ret >= sizeof(ccname)) 223 return ENOMEM; 224 225 old_umask = umask(0177); 226 tmpfd = mkstemp(ccname + strlen("FILE:")); 227 umask(old_umask); 228 if (tmpfd == -1) { 229 logit("mkstemp(): %.100s", strerror(errno)); 230 return errno; 231 } 232 233 if (fchmod(tmpfd,S_IRUSR | S_IWUSR) == -1) { 234 logit("fchmod(): %.100s", strerror(errno)); 235 close(tmpfd); 236 return errno; 237 } 238 close(tmpfd); 239 240 return (krb5_cc_resolve(ctx, ccname, ccache)); 241 } 242 #endif /* !HEIMDAL */ 243 #endif /* KRB5 */ 244