krb5_error_code libnet_keytab_init(TALLOC_CTX *mem_ctx, const char *keytab_name, struct libnet_keytab_context **ctx) { krb5_error_code ret = 0; krb5_context context = NULL; krb5_keytab keytab = NULL; const char *keytab_string = NULL; struct libnet_keytab_context *r; r = talloc_zero(mem_ctx, struct libnet_keytab_context); if (!r) { return ENOMEM; } talloc_set_destructor(r, keytab_close); initialize_krb5_error_table(); ret = krb5_init_context(&context); if (ret) { DEBUG(1,("keytab_init: could not krb5_init_context: %s\n", error_message(ret))); return ret; } ret = smb_krb5_open_keytab(context, keytab_name, true, &keytab); if (ret) { DEBUG(1,("keytab_init: smb_krb5_open_keytab failed (%s)\n", error_message(ret))); krb5_free_context(context); return ret; } ret = smb_krb5_keytab_name(mem_ctx, context, keytab, &keytab_string); if (ret) { krb5_kt_close(context, keytab); krb5_free_context(context); return ret; } r->context = context; r->keytab = keytab; r->keytab_name = keytab_string; r->clean_old_entries = false; *ctx = r; return 0; }
_PUBLIC_ int smb_krb5_create_memory_keytab(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, const char **enctype_strings, struct keytab_container **keytab_container) { krb5_error_code ret; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); const char *rand_string; const char *keytab_name; if (!mem_ctx) { return ENOMEM; } *keytab_container = talloc(mem_ctx, struct keytab_container); rand_string = generate_random_str(mem_ctx, 16); if (!rand_string) { talloc_free(mem_ctx); return ENOMEM; } keytab_name = talloc_asprintf(mem_ctx, "MEMORY:%s", rand_string); if (!keytab_name) { talloc_free(mem_ctx); return ENOMEM; } ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, keytab_name, keytab_container); if (ret) { return ret; } ret = smb_krb5_update_keytab(mem_ctx, machine_account, smb_krb5_context, enctype_strings, *keytab_container); if (ret == 0) { talloc_steal(parent_ctx, *keytab_container); } else { *keytab_container = NULL; } talloc_free(mem_ctx); return ret; }
int cli_credentials_set_keytab_name(struct cli_credentials *cred, const char *keytab_name, enum credentials_obtained obtained) { krb5_error_code ret; struct keytab_container *ktc; struct smb_krb5_context *smb_krb5_context; TALLOC_CTX *mem_ctx; if (cred->keytab_obtained >= obtained) { return 0; } ret = cli_credentials_get_krb5_context(cred, &smb_krb5_context); if (ret) { return ret; } mem_ctx = talloc_new(cred); if (!mem_ctx) { return ENOMEM; } ret = smb_krb5_open_keytab(mem_ctx, smb_krb5_context, keytab_name, &ktc); if (ret) { return ret; } cred->keytab_obtained = obtained; talloc_steal(cred, ktc); cred->keytab = ktc; talloc_free(mem_ctx); return ret; }
static bool ads_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) { krb5_error_code ret = 0; bool auth_ok = False; krb5_keytab keytab = NULL; krb5_kt_cursor kt_cursor; krb5_keytab_entry kt_entry; char *valid_princ_formats[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL }; char *entry_princ_s = NULL; fstring my_name, my_fqdn; int i; int number_matched_principals = 0; krb5_data packet; *pp_tkt = NULL; *keyblock = NULL; *perr = 0; /* Generate the list of principal names which we expect * clients might want to use for authenticating to the file * service. We allow name$,{host,cifs}/{name,fqdn,name.REALM}. */ fstrcpy(my_name, global_myname()); my_fqdn[0] = '\0'; name_to_fqdn(my_fqdn, global_myname()); if (asprintf(&valid_princ_formats[0], "%s$@%s", my_name, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[1], "host/%s@%s", my_name, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[2], "host/%s@%s", my_fqdn, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[3], "host/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[4], "cifs/%s@%s", my_name, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[5], "cifs/%s@%s", my_fqdn, lp_realm()) == -1) { goto out; } if (asprintf(&valid_princ_formats[6], "cifs/%s.%s@%s", my_name, lp_realm(), lp_realm()) == -1) { goto out; } ZERO_STRUCT(kt_entry); ZERO_STRUCT(kt_cursor); ret = smb_krb5_open_keytab(context, NULL, False, &keytab); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_open_keytab failed (%s)\n", error_message(ret))); goto out; } /* Iterate through the keytab. For each key, if the principal * name case-insensitively matches one of the allowed formats, * try verifying the ticket using that principal. */ ret = krb5_kt_start_seq_get(context, keytab, &kt_cursor); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret))); goto out; } while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) { ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto out; } for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { if (!strequal(entry_princ_s, valid_princ_formats[i])) { continue; } number_matched_principals++; packet.length = ticket->length; packet.data = (char *)ticket->data; *pp_tkt = NULL; ret = krb5_rd_req_return_keyblock_from_keytab(context, &auth_context, &packet, kt_entry.principal, keytab, NULL, pp_tkt, keyblock); if (ret) { DEBUG(10,("ads_keytab_verify_ticket: " "krb5_rd_req_return_keyblock_from_keytab(%s) failed: %s\n", entry_princ_s, error_message(ret))); /* workaround for MIT: * as krb5_ktfile_get_entry will explicitly * close the krb5_keytab as soon as krb5_rd_req * has successfully decrypted the ticket but the * ticket is not valid yet (due to clockskew) * there is no point in querying more keytab * entries - Guenther */ if (ret == KRB5KRB_AP_ERR_TKT_NYV || ret == KRB5KRB_AP_ERR_TKT_EXPIRED || ret == KRB5KRB_AP_ERR_SKEW) { break; } } else { DEBUG(3,("ads_keytab_verify_ticket: " "krb5_rd_req_return_keyblock_from_keytab succeeded for principal %s\n", entry_princ_s)); auth_ok = True; break; } } /* Free the name we parsed. */ SAFE_FREE(entry_princ_s); /* Free the entry we just read. */ smb_krb5_kt_free_entry(context, &kt_entry); ZERO_STRUCT(kt_entry); } krb5_kt_end_seq_get(context, keytab, &kt_cursor); ZERO_STRUCT(kt_cursor); out: for (i = 0; i < ARRAY_SIZE(valid_princ_formats); i++) { SAFE_FREE(valid_princ_formats[i]); } if (!auth_ok) { if (!number_matched_principals) { DEBUG(3, ("ads_keytab_verify_ticket: no keytab principals matched expected file service name.\n")); } else { DEBUG(3, ("ads_keytab_verify_ticket: krb5_rd_req failed for all %d matched keytab principals\n", number_matched_principals)); } } SAFE_FREE(entry_princ_s); { krb5_keytab_entry zero_kt_entry; ZERO_STRUCT(zero_kt_entry); if (memcmp(&zero_kt_entry, &kt_entry, sizeof(krb5_keytab_entry))) { smb_krb5_kt_free_entry(context, &kt_entry); } } { krb5_kt_cursor zero_csr; ZERO_STRUCT(zero_csr); if ((memcmp(&kt_cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) { krb5_kt_end_seq_get(context, keytab, &kt_cursor); } } if (keytab) { krb5_kt_close(context, keytab); } *perr = ret; return auth_ok; }
static bool ads_dedicated_keytab_verify_ticket(krb5_context context, krb5_auth_context auth_context, const DATA_BLOB *ticket, krb5_ticket **pp_tkt, krb5_keyblock **keyblock, krb5_error_code *perr) { krb5_error_code ret = 0; bool auth_ok = false; krb5_keytab keytab = NULL; krb5_keytab_entry kt_entry; krb5_ticket *dec_ticket = NULL; krb5_data packet; krb5_kvno kvno = 0; krb5_enctype enctype; *pp_tkt = NULL; *keyblock = NULL; *perr = 0; ZERO_STRUCT(kt_entry); ret = smb_krb5_open_keytab(context, lp_dedicated_keytab_file(), true, &keytab); if (ret) { DEBUG(1, ("smb_krb5_open_keytab failed (%s)\n", error_message(ret))); goto out; } packet.length = ticket->length; packet.data = (char *)ticket->data; ret = krb5_rd_req(context, &auth_context, &packet, NULL, keytab, NULL, &dec_ticket); if (ret) { DEBUG(0, ("krb5_rd_req failed (%s)\n", error_message(ret))); goto out; } #ifdef HAVE_ETYPE_IN_ENCRYPTEDDATA /* Heimdal */ enctype = dec_ticket->ticket.key.keytype; #else /* MIT */ enctype = dec_ticket->enc_part.enctype; kvno = dec_ticket->enc_part.kvno; #endif /* Get the key for checking the pac signature */ ret = krb5_kt_get_entry(context, keytab, dec_ticket->server, kvno, enctype, &kt_entry); if (ret) { DEBUG(0, ("krb5_kt_get_entry failed (%s)\n", error_message(ret))); goto out; } ret = krb5_copy_keyblock(context, KRB5_KT_KEY(&kt_entry), keyblock); smb_krb5_kt_free_entry(context, &kt_entry); if (ret) { DEBUG(0, ("failed to copy key: %s\n", error_message(ret))); goto out; } auth_ok = true; *pp_tkt = dec_ticket; dec_ticket = NULL; out: if (dec_ticket) krb5_free_ticket(context, dec_ticket); if (keytab) krb5_kt_close(context, keytab); *perr = ret; return auth_ok; }