static krb5_error_code libnet_keytab_add_entry(krb5_context context, krb5_keytab keytab, krb5_kvno kvno, const char *princ_s, krb5_enctype enctype, krb5_data password) { krb5_keyblock *keyp; krb5_keytab_entry kt_entry; krb5_error_code ret; /* remove duplicates first ... */ ret = libnet_keytab_remove_entries(context, keytab, princ_s, kvno, enctype, false); if (ret) { DEBUG(1, ("libnet_keytab_remove_entries failed: %s\n", error_message(ret))); } ZERO_STRUCT(kt_entry); kt_entry.vno = kvno; ret = smb_krb5_parse_name(context, princ_s, &kt_entry.principal); if (ret) { DEBUG(1, ("smb_krb5_parse_name(%s) failed (%s)\n", princ_s, error_message(ret))); return ret; } keyp = KRB5_KT_KEY(&kt_entry); if (create_kerberos_key_from_string(context, kt_entry.principal, &password, keyp, enctype, true)) { ret = KRB5KRB_ERR_GENERIC; goto done; } ret = krb5_kt_add_entry(context, keytab, &kt_entry); if (ret) { DEBUG(1, ("adding entry to keytab failed (%s)\n", error_message(ret))); } done: krb5_free_keyblock_contents(context, keyp); krb5_free_principal(context, kt_entry.principal); ZERO_STRUCT(kt_entry); smb_krb5_kt_free_entry(context, &kt_entry); return ret; }
static krb5_error_code ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, krb5_principal host_princ, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) { krb5_error_code ret = 0; bool auth_ok = False; char *password_s = NULL; krb5_data password; krb5_enctype enctypes[] = { #if defined(ENCTYPE_ARCFOUR_HMAC) ENCTYPE_ARCFOUR_HMAC, #endif ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL }; krb5_data packet; int i; *pp_tkt = NULL; *keyblock = NULL; *perr = 0; if (!secrets_init()) { DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); *perr = KRB5_CONFIG_CANTOPEN; return False; } password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!password_s) { DEBUG(1,("ads_secrets_verify_ticket: failed to fetch machine password\n")); *perr = KRB5_LIBOS_CANTREADPWD; return False; } password.data = password_s; password.length = strlen(password_s); /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ packet.length = ticket->length; packet.data = (char *)ticket->data; /* We need to setup a auth context with each possible encoding type in turn. */ for (i=0;enctypes[i];i++) { krb5_keyblock *key = NULL; if (!(key = SMB_MALLOC_P(krb5_keyblock))) { ret = ENOMEM; goto out; } if (create_kerberos_key_from_string(context, host_princ, &password, key, enctypes[i], false)) { SAFE_FREE(key); continue; } krb5_auth_con_setuseruserkey(context, auth_context, key); if (!(ret = krb5_rd_req(context, &auth_context, &packet, NULL, NULL, NULL, pp_tkt))) { DEBUG(10,("ads_secrets_verify_ticket: enc type [%u] decrypted message !\n", (unsigned int)enctypes[i] )); auth_ok = True; krb5_copy_keyblock(context, key, keyblock); krb5_free_keyblock(context, key); break; } DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, ("ads_secrets_verify_ticket: enc type [%u] failed to decrypt with error %s\n", (unsigned int)enctypes[i], error_message(ret))); /* successfully decrypted but ticket is just not valid at the moment */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW) { krb5_free_keyblock(context, key); break; } krb5_free_keyblock(context, key); } out: SAFE_FREE(password_s); *perr = ret; return auth_ok; }
static krb5_error_code ads_secrets_verify_ticket(krb5_context context, krb5_auth_context auth_context, krb5_principal host_princ, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) { krb5_error_code ret = 0; bool auth_ok = False; bool cont = true; char *password_s = NULL; /* Let's make some room for 2 password (old and new)*/ krb5_data passwords[2]; krb5_enctype enctypes[] = { #ifdef HAVE_ENCTYPE_AES256_CTS_HMAC_SHA1_96 ENCTYPE_AES256_CTS_HMAC_SHA1_96, #endif #ifdef HAVE_ENCTYPE_AES128_CTS_HMAC_SHA1_96 ENCTYPE_AES128_CTS_HMAC_SHA1_96, #endif ENCTYPE_ARCFOUR_HMAC, ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_NULL }; krb5_data packet; int i, j; *pp_tkt = NULL; *keyblock = NULL; *perr = 0; ZERO_STRUCT(passwords); if (!secrets_init()) { DEBUG(1,("ads_secrets_verify_ticket: secrets_init failed\n")); *perr = KRB5_CONFIG_CANTOPEN; return False; } password_s = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!password_s) { DEBUG(1,(__location__ ": failed to fetch machine password\n")); *perr = KRB5_LIBOS_CANTREADPWD; return False; } passwords[0].data = password_s; passwords[0].length = strlen(password_s); password_s = secrets_fetch_prev_machine_password(lp_workgroup()); if (password_s) { DEBUG(10, (__location__ ": found previous password\n")); passwords[1].data = password_s; passwords[1].length = strlen(password_s); } /* CIFS doesn't use addresses in tickets. This would break NAT. JRA */ packet.length = ticket->length; packet.data = (char *)ticket->data; /* We need to setup a auth context with each possible encoding type * in turn. */ for (j=0; j<2 && passwords[j].length; j++) { for (i=0;enctypes[i];i++) { krb5_keyblock *key = NULL; if (!(key = SMB_MALLOC_P(krb5_keyblock))) { ret = ENOMEM; goto out; } if (create_kerberos_key_from_string(context, host_princ, &passwords[j], key, enctypes[i], false)) { SAFE_FREE(key); continue; } krb5_auth_con_setuseruserkey(context, auth_context, key); if (!(ret = krb5_rd_req(context, &auth_context, &packet, NULL, NULL, NULL, pp_tkt))) { DEBUG(10, (__location__ ": enc type [%u] " "decrypted message !\n", (unsigned int)enctypes[i])); auth_ok = True; cont = false; krb5_copy_keyblock(context, key, keyblock); krb5_free_keyblock(context, key); break; } DEBUG((ret != KRB5_BAD_ENCTYPE) ? 3 : 10, (__location__ ": enc type [%u] failed to " "decrypt with error %s\n", (unsigned int)enctypes[i], error_message(ret))); /* successfully decrypted but ticket is just not * valid at the moment */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW) { krb5_free_keyblock(context, key); cont = false; break; } krb5_free_keyblock(context, key); } if (!cont) { /* If we found a valid pass then no need to try * the next one or we have invalid ticket so no need * to try next password*/ break; } } out: SAFE_FREE(passwords[0].data); SAFE_FREE(passwords[1].data); *perr = ret; return auth_ok; }
static krb5_error_code keytab_add_keys(TALLOC_CTX *parent_ctx, const char *princ_string, krb5_principal princ, krb5_principal salt_princ, int kvno, const char *password_s, struct smb_krb5_context *smb_krb5_context, const char **enctype_strings, krb5_keytab keytab) { int i; krb5_error_code ret; krb5_data password; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } password.data = discard_const_p(char *, password_s); password.length = strlen(password_s); for (i=0; enctype_strings[i]; i++) { krb5_keytab_entry entry; krb5_enctype enctype; ret = krb5_string_to_enctype(smb_krb5_context->krb5_context, enctype_strings[i], &enctype); if (ret != 0) { DEBUG(1, ("Failed to interpret %s as a krb5 encryption type: %s\n", enctype_strings[i], smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } ret = create_kerberos_key_from_string(smb_krb5_context->krb5_context, salt_princ, &password, &entry.keyblock, enctype); if (ret != 0) { talloc_free(mem_ctx); return ret; } entry.principal = princ; entry.vno = kvno; ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry); if (ret != 0) { DEBUG(1, ("Failed to add %s entry for %s(kvno %d) to keytab: %s\n", enctype_strings[i], princ_string, kvno, smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); return ret; } DEBUG(5, ("Added %s(kvno %d) to keytab (%s)\n", princ_string, kvno, enctype_strings[i])); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); } talloc_free(mem_ctx); return 0; }