/* fill in the cldap netlogon union for a given version */ NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, const char *domain, const char *netbios_domain, struct dom_sid *domain_sid, const char *domain_guid, const char *user, uint32_t acct_control, const char *src_address, uint32_t version, struct loadparm_context *lp_ctx, struct netlogon_samlogon_response *netlogon, bool fill_on_blank_request) { const char *dom_attrs[] = {"objectGUID", NULL}; const char *none_attrs[] = {NULL}; struct ldb_result *dom_res = NULL, *user_res = NULL; int ret; const char **services = lpcfg_server_services(lp_ctx); uint32_t server_type; const char *pdc_name; struct GUID domain_uuid; const char *dns_domain; const char *forest_domain; const char *pdc_dns_name; const char *flatname; const char *server_site; const char *client_site; const char *pdc_ip; struct ldb_dn *domain_dn = NULL; struct interface *ifaces; bool user_known, am_rodc; NTSTATUS status; /* the domain parameter could have an optional trailing "." */ if (domain && domain[strlen(domain)-1] == '.') { domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); NT_STATUS_HAVE_NO_MEMORY(domain); } /* Lookup using long or short domainname */ if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) { domain_dn = ldb_get_default_basedn(sam_ctx); } if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) { domain_dn = ldb_get_default_basedn(sam_ctx); } if (domain_dn) { const char *domain_identifier = domain != NULL ? domain : netbios_domain; ret = ldb_search(sam_ctx, mem_ctx, &dom_res, domain_dn, LDB_SCOPE_BASE, dom_attrs, "objectClass=domain"); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain_identifier, ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } if (dom_res->count != 1) { DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain_identifier, ldb_dn_get_linearized(domain_dn))); return NT_STATUS_NO_SUCH_DOMAIN; } } /* Lookup using GUID or SID */ if ((dom_res == NULL) && (domain_guid || domain_sid)) { if (domain_guid) { struct GUID binary_guid; struct ldb_val guid_val; /* By this means, we ensure we don't have funny stuff in the GUID */ status = GUID_from_string(domain_guid, &binary_guid); if (!NT_STATUS_IS_OK(status)) { return status; } /* And this gets the result into the binary format we want anyway */ status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val); if (!NT_STATUS_IS_OK(status)) { return status; } ret = ldb_search(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, "(&(objectCategory=DomainDNS)(objectGUID=%s))", ldb_binary_encode(mem_ctx, guid_val)); } else { /* domain_sid case */ ret = ldb_search(sam_ctx, mem_ctx, &dom_res, NULL, LDB_SCOPE_SUBTREE, dom_attrs, "(&(objectCategory=DomainDNS)(objectSid=%s))", dom_sid_string(mem_ctx, domain_sid)); } if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n", domain_guid, dom_sid_string(mem_ctx, domain_sid), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } else if (dom_res->count == 1) { /* Ok, now just check it is our domain */ if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx), dom_res->msgs[0]->dn) != 0) { DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n", domain_guid, dom_sid_string(mem_ctx, domain_sid))); return NT_STATUS_NO_SUCH_DOMAIN; } } else { DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n", domain_guid, dom_sid_string(mem_ctx, domain_sid))); return NT_STATUS_NO_SUCH_DOMAIN; } } if (dom_res == NULL && fill_on_blank_request) { /* blank inputs gives our domain - tested against w2k8r2. Without this ADUC on Win7 won't start */ domain_dn = ldb_get_default_basedn(sam_ctx); ret = ldb_search(sam_ctx, mem_ctx, &dom_res, domain_dn, LDB_SCOPE_BASE, dom_attrs, "objectClass=domain"); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", lpcfg_dnsdomain(lp_ctx), ldb_dn_get_linearized(domain_dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_DOMAIN; } } if (dom_res == NULL) { DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n")); return NT_STATUS_NO_SUCH_DOMAIN; } /* work around different inputs for not-specified users */ if (!user) { user = ""; } /* Enquire about any valid username with just a CLDAP packet - * if kerberos didn't also do this, the security folks would * scream... */ if (user[0]) { \ /* Only allow some bits to be enquired: [MS-ATDS] 7.3.3.2 */ if (acct_control == (uint32_t)-1) { acct_control = 0; } acct_control = acct_control & (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST); /* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */ ret = ldb_search(sam_ctx, mem_ctx, &user_res, dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, none_attrs, "(&(objectClass=user)(samAccountName=%s)" "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))" "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", ldb_binary_encode_string(mem_ctx, user), UF_ACCOUNTDISABLE, ds_acb2uf(acct_control)); if (ret != LDB_SUCCESS) { DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n", user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn), ldb_errstring(sam_ctx))); return NT_STATUS_NO_SUCH_USER; } else if (user_res->count == 1) { user_known = true; } else { user_known = false; } } else { user_known = true; } server_type = DS_SERVER_DS | DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV; if (samdb_is_pdc(sam_ctx)) { server_type |= DS_SERVER_PDC; } if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) { server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6; } if (samdb_is_gc(sam_ctx)) { server_type |= DS_SERVER_GC; } if (str_list_check(services, "ldap")) { server_type |= DS_SERVER_LDAP; } if (str_list_check(services, "kdc")) { server_type |= DS_SERVER_KDC; } if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) { server_type |= DS_SERVER_WRITABLE; } pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lpcfg_netbios_name(lp_ctx)); NT_STATUS_HAVE_NO_MEMORY(pdc_name); domain_uuid = samdb_result_guid(dom_res->msgs[0], "objectGUID"); dns_domain = lpcfg_dnsdomain(lp_ctx); forest_domain = samdb_forest_name(sam_ctx, mem_ctx); NT_STATUS_HAVE_NO_MEMORY(forest_domain); pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", strlower_talloc(mem_ctx, lpcfg_netbios_name(lp_ctx)), dns_domain); NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name); flatname = lpcfg_workgroup(lp_ctx); server_site = samdb_server_site_name(sam_ctx, mem_ctx); NT_STATUS_HAVE_NO_MEMORY(server_site); client_site = samdb_client_site_name(sam_ctx, mem_ctx, src_address, NULL); NT_STATUS_HAVE_NO_MEMORY(client_site); if (strcasecmp(server_site, client_site) == 0) { server_type |= DS_SERVER_CLOSEST; } load_interface_list(mem_ctx, lp_ctx, &ifaces); if (src_address) { pdc_ip = iface_list_best_ip(ifaces, src_address); } else { pdc_ip = iface_list_first_v4(ifaces); } if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) { /* this matches windows behaviour */ pdc_ip = "127.0.0.1"; } ZERO_STRUCTP(netlogon); /* check if either of these bits is present */ if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) { uint32_t extra_flags = 0; netlogon->ntver = NETLOGON_NT_VERSION_5EX; /* could check if the user exists */ if (user_known) { netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_RESPONSE_EX; } else { netlogon->data.nt5_ex.command = LOGON_SAM_LOGON_USER_UNKNOWN_EX; } netlogon->data.nt5_ex.pdc_name = pdc_name; netlogon->data.nt5_ex.user_name = user; netlogon->data.nt5_ex.domain_name = flatname; netlogon->data.nt5_ex.domain_uuid = domain_uuid; netlogon->data.nt5_ex.forest = forest_domain; netlogon->data.nt5_ex.dns_domain = dns_domain; netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name; netlogon->data.nt5_ex.server_site = server_site; netlogon->data.nt5_ex.client_site = client_site; if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) { /* note that this is always a IPV4 address */ extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP; netlogon->data.nt5_ex.sockaddr.sockaddr_family = 2; netlogon->data.nt5_ex.sockaddr.pdc_ip = pdc_ip; netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8); } netlogon->data.nt5_ex.server_type = server_type; netlogon->data.nt5_ex.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags; netlogon->data.nt5_ex.lmnt_token = 0xFFFF; netlogon->data.nt5_ex.lm20_token = 0xFFFF; } else if (version & NETLOGON_NT_VERSION_5) { netlogon->ntver = NETLOGON_NT_VERSION_5; /* could check if the user exists */ if (user_known) { netlogon->data.nt5.command = LOGON_SAM_LOGON_RESPONSE; } else { netlogon->data.nt5.command = LOGON_SAM_LOGON_USER_UNKNOWN; } netlogon->data.nt5.pdc_name = pdc_name; netlogon->data.nt5.user_name = user; netlogon->data.nt5.domain_name = flatname; netlogon->data.nt5.domain_uuid = domain_uuid; netlogon->data.nt5.forest = forest_domain; netlogon->data.nt5.dns_domain = dns_domain; netlogon->data.nt5.pdc_dns_name = pdc_dns_name; netlogon->data.nt5.pdc_ip = pdc_ip; netlogon->data.nt5.server_type = server_type; netlogon->data.nt5.nt_version = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5; netlogon->data.nt5.lmnt_token = 0xFFFF; netlogon->data.nt5.lm20_token = 0xFFFF; } else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ { netlogon->ntver = NETLOGON_NT_VERSION_1; /* could check if the user exists */ if (user_known) { netlogon->data.nt4.command = LOGON_SAM_LOGON_RESPONSE; } else { netlogon->data.nt4.command = LOGON_SAM_LOGON_USER_UNKNOWN; } netlogon->data.nt4.pdc_name = pdc_name; netlogon->data.nt4.user_name = user; netlogon->data.nt4.domain_name = flatname; netlogon->data.nt4.nt_version = NETLOGON_NT_VERSION_1; netlogon->data.nt4.lmnt_token = 0xFFFF; netlogon->data.nt4.lm20_token = 0xFFFF; } return NT_STATUS_OK; }
/** * per-share logic tests */ static void do_per_share_checks(int s) { const char **deny_list = lp_hosts_deny(s); const char **allow_list = lp_hosts_allow(s); const char **vfs_objects = NULL; int i; static bool uses_fruit; static bool doesnt_use_fruit; static bool fruit_mix_warned; if(deny_list) { for (i=0; deny_list[i]; i++) { char *hasstar = strchr_m(deny_list[i], '*'); char *hasquery = strchr_m(deny_list[i], '?'); if(hasstar || hasquery) { fprintf(stderr, "Invalid character %c in hosts deny list " "(%s) for service %s.\n\n", hasstar ? *hasstar : *hasquery, deny_list[i], lp_servicename(talloc_tos(), s)); } } } if(allow_list) { for (i=0; allow_list[i]; i++) { char *hasstar = strchr_m(allow_list[i], '*'); char *hasquery = strchr_m(allow_list[i], '?'); if(hasstar || hasquery) { fprintf(stderr, "Invalid character %c in hosts allow " "list (%s) for service %s.\n\n", hasstar ? *hasstar : *hasquery, allow_list[i], lp_servicename(talloc_tos(), s)); } } } if(lp_level2_oplocks(s) && !lp_oplocks(s)) { fprintf(stderr, "Invalid combination of parameters for service " "%s. Level II oplocks can only be set if oplocks " "are also set.\n\n", lp_servicename(talloc_tos(), s)); } if (!lp_store_dos_attributes(s) && lp_map_hidden(s) && !(lp_create_mask(s) & S_IXOTH)) { fprintf(stderr, "Invalid combination of parameters for service %s. Map " "hidden can only work if create mask includes octal " "01 (S_IXOTH).\n\n", lp_servicename(talloc_tos(), s)); } if (!lp_store_dos_attributes(s) && lp_map_hidden(s) && (lp_force_create_mode(s) & S_IXOTH)) { fprintf(stderr, "Invalid combination of parameters for service " "%s. Map hidden can only work if force create mode " "excludes octal 01 (S_IXOTH).\n\n", lp_servicename(talloc_tos(), s)); } if (!lp_store_dos_attributes(s) && lp_map_system(s) && !(lp_create_mask(s) & S_IXGRP)) { fprintf(stderr, "Invalid combination of parameters for service " "%s. Map system can only work if create mask includes " "octal 010 (S_IXGRP).\n\n", lp_servicename(talloc_tos(), s)); } if (!lp_store_dos_attributes(s) && lp_map_system(s) && (lp_force_create_mode(s) & S_IXGRP)) { fprintf(stderr, "Invalid combination of parameters for service " "%s. Map system can only work if force create mode " "excludes octal 010 (S_IXGRP).\n\n", lp_servicename(talloc_tos(), s)); } if (lp_printing(s) == PRINT_CUPS && *(lp_print_command(talloc_tos(), s)) != '\0') { fprintf(stderr, "Warning: Service %s defines a print command, but " "parameter is ignored when using CUPS libraries.\n\n", lp_servicename(talloc_tos(), s)); } vfs_objects = lp_vfs_objects(s); if (vfs_objects && str_list_check(vfs_objects, "fruit")) { uses_fruit = true; if (!lp_ea_support(s) && !lp_ea_support(-1)) { fprintf(stderr, "ERROR: Service \"%s\" uses vfs_fruit, but " "that requires \"ea support = yes\".\n\n", lp_servicename(talloc_tos(), s)); } } else { doesnt_use_fruit = true; } if (uses_fruit && doesnt_use_fruit && !fruit_mix_warned) { fruit_mix_warned = true; fprintf(stderr, "WARNING: some services use vfs_fruit, others don't. Mounting them " "in conjunction on OS X clients results in undefined behaviour.\n\n"); } }
/* fill in the cldap netlogon union for a given version */ static NTSTATUS cldapd_netlogon_fill(struct cldapd_server *cldapd, TALLOC_CTX *mem_ctx, const char *domain, const char *domain_guid, const char *user, const char *src_address, uint32_t version, union nbt_cldap_netlogon *netlogon) { const char *ref_attrs[] = {"nETBIOSName", "dnsRoot", "ncName", NULL}; const char *dom_attrs[] = {"objectGUID", NULL}; struct ldb_message **ref_res, **dom_res; int ret, count = 0; const char **services = lp_server_services(); uint32_t server_type; const char *pdc_name; struct GUID domain_uuid; const char *realm; const char *dns_domain; const char *pdc_dns_name; const char *flatname; const char *server_site; const char *client_site; const char *pdc_ip; struct ldb_dn *partitions_basedn; partitions_basedn = samdb_partitions_dn(cldapd->samctx, mem_ctx); /* the domain has an optional trailing . */ if (domain && domain[strlen(domain)-1] == '.') { domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1); } if (domain) { struct ldb_result *dom_ldb_result; struct ldb_dn *dom_dn; /* try and find the domain */ count = gendb_search(cldapd->samctx, mem_ctx, partitions_basedn, &ref_res, ref_attrs, "(&(&(objectClass=crossRef)(dnsRoot=%s))(nETBIOSName=*))", domain); if (count == 1) { dom_dn = samdb_result_dn(cldapd->samctx, mem_ctx, ref_res[0], "ncName", NULL); if (!dom_dn) { return NT_STATUS_NO_SUCH_DOMAIN; } ret = ldb_search(cldapd->samctx, dom_dn, LDB_SCOPE_BASE, "objectClass=domain", dom_attrs, &dom_ldb_result); if (ret != LDB_SUCCESS) { DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n", domain, ldb_dn_get_linearized(dom_dn), ldb_errstring(cldapd->samctx))); return NT_STATUS_NO_SUCH_DOMAIN; } talloc_steal(mem_ctx, dom_ldb_result); if (dom_ldb_result->count != 1) { DEBUG(2,("Error finding domain '%s'/'%s' in sam\n", domain, ldb_dn_get_linearized(dom_dn))); return NT_STATUS_NO_SUCH_DOMAIN; } dom_res = dom_ldb_result->msgs; } } if (count == 0 && domain_guid) { /* OK, so no dice with the name, try and find the domain with the GUID */ count = gendb_search(cldapd->samctx, mem_ctx, NULL, &dom_res, dom_attrs, "(&(objectClass=domainDNS)(objectGUID=%s))", domain_guid); if (count == 1) { /* try and find the domain */ ret = gendb_search(cldapd->samctx, mem_ctx, partitions_basedn, &ref_res, ref_attrs, "(&(objectClass=crossRef)(ncName=%s))", ldb_dn_get_linearized(dom_res[0]->dn)); if (ret != 1) { DEBUG(2,("Unable to find referece to '%s' in sam\n", ldb_dn_get_linearized(dom_res[0]->dn))); return NT_STATUS_NO_SUCH_DOMAIN; } } } if (count == 0) { DEBUG(2,("Unable to find domain with name %s or GUID {%s}\n", domain, domain_guid)); return NT_STATUS_NO_SUCH_DOMAIN; } server_type = NBT_SERVER_PDC | NBT_SERVER_GC | NBT_SERVER_DS | NBT_SERVER_TIMESERV | NBT_SERVER_CLOSEST | NBT_SERVER_WRITABLE | NBT_SERVER_GOOD_TIMESERV; if (str_list_check(services, "ldap")) { server_type |= NBT_SERVER_LDAP; } if (str_list_check(services, "kdc")) { server_type |= NBT_SERVER_KDC; } pdc_name = talloc_asprintf(mem_ctx, "\\\\%s", lp_netbios_name()); domain_uuid = samdb_result_guid(dom_res[0], "objectGUID"); realm = samdb_result_string(ref_res[0], "dnsRoot", lp_realm()); dns_domain = samdb_result_string(ref_res[0], "dnsRoot", lp_realm()); pdc_dns_name = talloc_asprintf(mem_ctx, "%s.%s", strlower_talloc(mem_ctx, lp_netbios_name()), dns_domain); flatname = samdb_result_string(ref_res[0], "nETBIOSName", lp_workgroup()); server_site = "Default-First-Site-Name"; client_site = "Default-First-Site-Name"; pdc_ip = iface_best_ip(src_address); ZERO_STRUCTP(netlogon); switch (version & 0xF) { case 0: case 1: netlogon->logon1.type = (user?19+2:19); netlogon->logon1.pdc_name = pdc_name; netlogon->logon1.user_name = user; netlogon->logon1.domain_name = flatname; netlogon->logon1.nt_version = 1; netlogon->logon1.lmnt_token = 0xFFFF; netlogon->logon1.lm20_token = 0xFFFF; break; case 2: case 3: netlogon->logon3.type = (user?19+2:19); netlogon->logon3.pdc_name = pdc_name; netlogon->logon3.user_name = user; netlogon->logon3.domain_name = flatname; netlogon->logon3.domain_uuid = domain_uuid; netlogon->logon3.forest = realm; netlogon->logon3.dns_domain = dns_domain; netlogon->logon3.pdc_dns_name = pdc_dns_name; netlogon->logon3.pdc_ip = pdc_ip; netlogon->logon3.server_type = server_type; netlogon->logon3.lmnt_token = 0xFFFF; netlogon->logon3.lm20_token = 0xFFFF; break; case 4: case 5: case 6: case 7: netlogon->logon5.type = (user?23+2:23); netlogon->logon5.server_type = server_type; netlogon->logon5.domain_uuid = domain_uuid; netlogon->logon5.forest = realm; netlogon->logon5.dns_domain = dns_domain; netlogon->logon5.pdc_dns_name = pdc_dns_name; netlogon->logon5.domain = flatname; netlogon->logon5.pdc_name = lp_netbios_name(); netlogon->logon5.user_name = user; netlogon->logon5.server_site = server_site; netlogon->logon5.client_site = client_site; netlogon->logon5.lmnt_token = 0xFFFF; netlogon->logon5.lm20_token = 0xFFFF; break; default: netlogon->logon13.type = (user?23+2:23); netlogon->logon13.server_type = server_type; netlogon->logon13.domain_uuid = domain_uuid; netlogon->logon13.forest = realm; netlogon->logon13.dns_domain = dns_domain; netlogon->logon13.pdc_dns_name = pdc_dns_name; netlogon->logon13.domain = flatname; netlogon->logon13.pdc_name = lp_netbios_name(); netlogon->logon13.user_name = user; netlogon->logon13.server_site = server_site; netlogon->logon13.client_site = client_site; netlogon->logon13.unknown = 10; netlogon->logon13.unknown2 = 2; netlogon->logon13.pdc_ip = pdc_ip; netlogon->logon13.lmnt_token = 0xFFFF; netlogon->logon13.lm20_token = 0xFFFF; break; } return NT_STATUS_OK; }
static int create_keytab(TALLOC_CTX *parent_ctx, struct cli_credentials *machine_account, struct smb_krb5_context *smb_krb5_context, const char **enctype_strings, krb5_keytab keytab, BOOL add_old) { krb5_error_code ret; const char *password_s; const char *old_secret; int kvno; krb5_principal salt_princ; krb5_principal princ; const char *princ_string; TALLOC_CTX *mem_ctx = talloc_new(parent_ctx); if (!mem_ctx) { return ENOMEM; } princ_string = cli_credentials_get_principal(machine_account, mem_ctx); /* Get the principal we will store the new keytab entries under */ ret = principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &princ); if (ret) { DEBUG(1,("create_keytab: makeing krb5 principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* The salt used to generate these entries may be different however, fetch that */ ret = salt_principal_from_credentials(mem_ctx, machine_account, smb_krb5_context, &salt_princ); if (ret) { DEBUG(1,("create_keytab: makeing salt principal failed (%s)\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } /* Finally, do the dance to get the password to put in the entry */ password_s = cli_credentials_get_password(machine_account); if (!password_s) { krb5_keytab_entry entry; const struct samr_Password *mach_pwd; if (!str_list_check(enctype_strings, "arcfour-hmac-md5")) { DEBUG(1, ("Asked to create keytab, but with only an NT hash supplied, " "but not listing arcfour-hmac-md5 as an enc type to include in the keytab!\n")); talloc_free(mem_ctx); return EINVAL; } /* If we don't have the plaintext password, try for * the MD4 password hash */ mach_pwd = cli_credentials_get_nt_hash(machine_account, mem_ctx); if (!mach_pwd) { /* OK, nothing to do here */ talloc_free(mem_ctx); return 0; } ret = krb5_keyblock_init(smb_krb5_context->krb5_context, ETYPE_ARCFOUR_HMAC_MD5, mach_pwd->hash, sizeof(mach_pwd->hash), &entry.keyblock); if (ret) { DEBUG(1, ("create_keytab: krb5_keyblock_init failed: %s\n", smb_get_krb5_error_message(smb_krb5_context->krb5_context, ret, mem_ctx))); talloc_free(mem_ctx); return ret; } entry.principal = princ; entry.vno = cli_credentials_get_kvno(machine_account); ret = krb5_kt_add_entry(smb_krb5_context->krb5_context, keytab, &entry); if (ret) { DEBUG(1, ("Failed to add ARCFOUR_HMAC (only) entry for %s to keytab: %s", cli_credentials_get_principal(machine_account, mem_ctx), 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 (arcfour-hmac-md5)\n", cli_credentials_get_principal(machine_account, mem_ctx), cli_credentials_get_kvno(machine_account))); krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &entry.keyblock); /* Can't go any further, we only have this one key */ talloc_free(mem_ctx); return 0; } kvno = cli_credentials_get_kvno(machine_account); /* good, we actually have the real plaintext */ ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, kvno, password_s, smb_krb5_context, enctype_strings, keytab); if (!ret) { talloc_free(mem_ctx); return ret; } if (!add_old || kvno == 0) { talloc_free(mem_ctx); return 0; } old_secret = cli_credentials_get_old_password(machine_account); if (!old_secret) { talloc_free(mem_ctx); return 0; } ret = keytab_add_keys(mem_ctx, princ_string, princ, salt_princ, kvno - 1, old_secret, smb_krb5_context, enctype_strings, keytab); if (!ret) { talloc_free(mem_ctx); return ret; } talloc_free(mem_ctx); return 0; }