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