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