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