static int net_ads_printer_remove(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; const char *servername; char *prt_dn; void *res = NULL; if (!(ads = ads_startup())) { return -1; } if (argc < 1) { return net_ads_printer_usage(argc, argv); } if (argc > 1) { servername = argv[1]; } else { servername = global_myname(); } rc = ads_find_printer_on_server(ads, &res, argv[0], servername); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc)); ads_msgfree(ads, res); ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("Printer '%s' not found\n", argv[1]); ads_msgfree(ads, res); ads_destroy(&ads); return -1; } prt_dn = ads_get_dn(ads, res); ads_msgfree(ads, res); rc = ads_del_dn(ads, prt_dn); ads_memfree(ads, prt_dn); if (!ADS_ERR_OK(rc)) { d_printf("ads_del_dn: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } ads_destroy(&ads); return 0; }
static ADS_STATUS ads_sasl_gssapi_bind(ADS_STRUCT *ads) { ADS_STATUS status; struct ads_service_principal p; status = ads_generate_service_principal(ads, &p); if (!ADS_ERR_OK(status)) { return status; } if (ads->auth.password == NULL || ads->auth.password[0] == '\0') { status = ads_sasl_gssapi_do_bind(ads, p.name); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); return status; } DEBUG(10,("ads_sasl_gssapi_do_bind failed with: %s, " "calling kinit\n", ads_errstr(status))); } status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_gssapi_do_bind(ads, p.name); } ads_free_service_principal(&p); return status; }
static int ads_group_delete(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; void *res; char *groupdn; if (argc < 1) { return net_ads_group_usage(argc, argv); } if (!(ads = ads_startup())) { return -1; } rc = ads_find_user_acct(ads, &res, argv[0]); if (!ADS_ERR_OK(rc)) { DEBUG(0, ("Group %s does not exist\n", argv[0])); ads_destroy(&ads); return -1; } groupdn = ads_get_dn(ads, res); ads_msgfree(ads, res); rc = ads_del_dn(ads, groupdn); ads_memfree(ads, groupdn); if (!ADS_ERR_OK(rc)) { d_printf("Group %s deleted\n", argv[0]); ads_destroy(&ads); return 0; } d_printf("Error deleting group %s: %s\n", argv[0], ads_errstr(rc)); ads_destroy(&ads); return -1; }
/* convert a sid to a user or group name */ NTSTATUS ads_sid_to_name(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const DOM_SID *sid, char **name, enum SID_NAME_USE *type) { const char *attrs[] = {"userPrincipalName", "sAMAccountName", "sAMAccountType", NULL}; ADS_STATUS rc; void *msg = NULL; char *ldap_exp = NULL; char *sidstr = NULL; uint32 atype; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; if (!(sidstr = sid_binstring(sid))) { DEBUG(1,("ads_sid_to_name: sid_binstring failed!\n")); status = NT_STATUS_NO_MEMORY; goto done; } if (asprintf(&ldap_exp, "(objectSid=%s)", sidstr) == -1) { DEBUG(1,("ads_sid_to_name: asprintf failed!\n")); status = NT_STATUS_NO_MEMORY; goto done; } rc = ads_search_retry(ads, &msg, ldap_exp, attrs); if (!ADS_ERR_OK(rc)) { status = ads_ntstatus(rc); DEBUG(1,("ads_sid_to_name ads_search: %s\n", ads_errstr(rc))); goto done; } if (!ads_pull_uint32(ads, msg, "sAMAccountType", &atype)) { goto done; } *name = ads_pull_username(ads, mem_ctx, msg); if (!*name) { DEBUG(1,("ads_sid_to_name: ads_pull_username retuned NULL!\n")); status = NT_STATUS_NO_MEMORY; goto done; } *type = ads_atype_map(atype); status = NT_STATUS_OK; DEBUG(3,("ads sid_to_name mapped %s\n", *name)); done: if (msg) ads_msgfree(ads, msg); SAFE_FREE(ldap_exp); SAFE_FREE(sidstr); return status; }
static ADS_STATUS gpo_process_gpo_list_by_ext(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const struct security_token *token, struct registry_key *root_key, struct GROUP_POLICY_OBJECT *gpo_list, const char *extensions_guid, uint32_t flags) { ADS_STATUS status; struct GROUP_POLICY_OBJECT *gpo; for (gpo = gpo_list; gpo; gpo = gpo->next) { if (gpo->link_type == GP_LINK_LOCAL) { continue; } /* FIXME: we need to pass down the *list* down to the * extension, otherwise we cannot store the e.g. the *list* of * logon-scripts correctly (for more then one GPO) */ status = gpo_process_a_gpo(ads, mem_ctx, token, root_key, gpo, extensions_guid, flags); if (!ADS_ERR_OK(status)) { DEBUG(0,("failed to process gpo by ext: %s\n", ads_errstr(status))); return status; } } return ADS_SUCCESS; }
void dump_gplink(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, struct GP_LINK *gp_link) { ADS_STATUS status; int i; int lvl = 10; if (gp_link == NULL) { return; } DEBUG(lvl,("---------------------\n\n")); DEBUGADD(lvl,("gplink: %s\n", gp_link->gp_link)); DEBUGADD(lvl,("gpopts: %d ", gp_link->gp_opts)); switch (gp_link->gp_opts) { case GPOPTIONS_INHERIT: DEBUGADD(lvl,("GPOPTIONS_INHERIT\n")); break; case GPOPTIONS_BLOCK_INHERITANCE: DEBUGADD(lvl,("GPOPTIONS_BLOCK_INHERITANCE\n")); break; default: break; } DEBUGADD(lvl,("num links: %d\n", gp_link->num_links)); for (i = 0; i < gp_link->num_links; i++) { DEBUGADD(lvl,("---------------------\n\n")); DEBUGADD(lvl,("link: #%d\n", i + 1)); DEBUGADD(lvl,("name: %s\n", gp_link->link_names[i])); DEBUGADD(lvl,("opt: %d ", gp_link->link_opts[i])); if (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) { DEBUGADD(lvl,("GPO_LINK_OPT_ENFORCED ")); } if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) { DEBUGADD(lvl,("GPO_LINK_OPT_DISABLED")); } DEBUGADD(lvl,("\n")); if (ads != NULL && mem_ctx != NULL) { struct GROUP_POLICY_OBJECT gpo; status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i], NULL, NULL, &gpo); if (!ADS_ERR_OK(status)) { DEBUG(lvl,("get gpo for %s failed: %s\n", gp_link->link_names[i], ads_errstr(status))); return; } dump_gpo(ads, mem_ctx, &gpo, lvl); } } }
static WERROR nt_printer_guid_retrieve_internal(ADS_STRUCT *ads, const char *printer_dn, struct GUID *pguid) { ADS_STATUS ads_status; LDAPMessage *res; const char *attrs[] = {"objectGUID", NULL}; struct GUID guid; bool ok; ads_status = ads_search_dn(ads, &res, printer_dn, attrs); if (!ADS_ERR_OK(ads_status)) { DEBUG(2, ("Failed to retrieve GUID from DC - %s\n", ads_errstr(ads_status))); return WERR_BADFILE; } ZERO_STRUCT(guid); ok = ads_pull_guid(ads, res, &guid); ads_msgfree(ads, res); if (!ok) { return WERR_NOMEM; } *pguid = guid; return WERR_OK; }
/* join a machine to a realm, creating the machine account and setting the machine password */ int ads_join_realm(ADS_STRUCT *ads, const char *hostname) { int rc; LDAPMessage *res; char *principal; rc = ads_find_machine_acct(ads, &res, hostname); if (rc == LDAP_SUCCESS && ads_count_replies(ads, res) == 1) { DEBUG(0, ("Host account for %s already exists\n", hostname)); goto set_password; } rc = ads_add_machine_acct(ads, hostname); if (rc != LDAP_SUCCESS) { DEBUG(0, ("ads_add_machine_acct: %s\n", ads_errstr(rc))); return rc; } rc = ads_find_machine_acct(ads, &res, hostname); if (rc != LDAP_SUCCESS || ads_count_replies(ads, res) != 1) { DEBUG(0, ("Host account test failed\n")); /* hmmm, we need NTSTATUS */ return -1; } set_password: asprintf(&principal, "HOST/%s@%s", hostname, ads->realm); krb5_set_principal_password(principal, ads->ldap_server, hostname, ads->realm); free(principal); return LDAP_SUCCESS; }
static int net_ads_status(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; void *res; if (!(ads = ads_startup())) { return -1; } rc = ads_find_machine_acct(ads, &res, global_myname()); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_machine_acct: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("No machine account for '%s' found\n", global_myname()); ads_destroy(&ads); return -1; } ads_dump(ads, res); ads_destroy(&ads); return 0; }
static int net_ads_printer_search(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; void *res = NULL; if (!(ads = ads_startup())) { return -1; } rc = ads_find_printers(ads, &res); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_printer: %s\n", ads_errstr(rc)); ads_msgfree(ads, res); ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("No results found\n"); ads_msgfree(ads, res); ads_destroy(&ads); return -1; } ads_dump(ads, res); ads_msgfree(ads, res); ads_destroy(&ads); return 0; }
static int ads_group_add(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; void *res=NULL; int rc = -1; if (argc < 1) { return net_ads_group_usage(argc, argv); } if (!(ads = ads_startup())) { return -1; } status = ads_find_user_acct(ads, &res, argv[0]); if (!ADS_ERR_OK(status)) { d_printf("ads_group_add: %s\n", ads_errstr(status)); goto done; } if (ads_count_replies(ads, res)) { d_printf("ads_group_add: Group %s already exists\n", argv[0]); ads_msgfree(ads, res); goto done; } status = ads_add_group_acct(ads, argv[0], opt_container, opt_comment); if (ADS_ERR_OK(status)) { d_printf("Group %s added\n", argv[0]); rc = 0; } else { d_printf("Could not add group %s: %s\n", argv[0], ads_errstr(status)); } done: if (res) ads_msgfree(ads, res); ads_destroy(&ads); return rc; }
static int ads_user_info(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; void *res; const char *attrs[] = {"memberOf", NULL}; char *searchstring=NULL; char **grouplist; char *escaped_user = escape_ldap_string_alloc(argv[0]); if (argc < 1) { return net_ads_user_usage(argc, argv); } if (!(ads = ads_startup())) { return -1; } if (!escaped_user) { d_printf("ads_user_info: failed to escape user %s\n", argv[0]); ads_destroy(&ads); return -1; } asprintf(&searchstring, "(sAMAccountName=%s)", escaped_user); rc = ads_search(ads, &res, searchstring, attrs); safe_free(searchstring); if (!ADS_ERR_OK(rc)) { d_printf("ads_search: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } grouplist = ldap_get_values(ads->ld, res, "memberOf"); if (grouplist) { int i; char **groupname; for (i=0;grouplist[i];i++) { groupname = ldap_explode_dn(grouplist[i], 1); d_printf("%s\n", groupname[0]); ldap_value_free(groupname); } ldap_value_free(grouplist); } ads_msgfree(ads, res); ads_destroy(&ads); return 0; }
WERROR nt_printer_guid_retrieve(TALLOC_CTX *mem_ctx, const char *printer, struct GUID *pguid) { ADS_STRUCT *ads = NULL; char *old_krb5ccname = NULL; char *printer_dn; WERROR result; ADS_STATUS ads_status; TALLOC_CTX *tmp_ctx; tmp_ctx = talloc_new(mem_ctx); if (tmp_ctx == NULL) { return WERR_NOMEM; } ads = ads_init(lp_realm(), lp_workgroup(), NULL); if (ads == NULL) { result = WERR_SERVER_UNAVAILABLE; goto out; } old_krb5ccname = getenv(KRB5_ENV_CCNAME); setenv(KRB5_ENV_CCNAME, "MEMORY:prtpub_cache", 1); SAFE_FREE(ads->auth.password); ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); ads_status = ads_connect(ads); if (!ADS_ERR_OK(ads_status)) { DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_status))); result = WERR_ACCESS_DENIED; goto out; } result = nt_printer_dn_lookup(tmp_ctx, ads, printer, &printer_dn); if (!W_ERROR_IS_OK(result)) { goto out; } result = nt_printer_guid_retrieve_internal(ads, printer_dn, pguid); out: TALLOC_FREE(tmp_ctx); ads_destroy(&ads); ads_kdestroy("MEMORY:prtpub_cache"); unsetenv(KRB5_ENV_CCNAME); if (old_krb5ccname != NULL) { setenv(KRB5_ENV_CCNAME, old_krb5ccname, 0); } return result; }
static int net_ads_printer_info(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; const char *servername, *printername; void *res = NULL; if (!(ads = ads_startup())) { return -1; } if (argc > 0) { printername = argv[0]; } else { printername = "*"; } if (argc > 1) { servername = argv[1]; } else { servername = global_myname(); } rc = ads_find_printer_on_server(ads, &res, printername, servername); if (!ADS_ERR_OK(rc)) { d_printf("ads_find_printer_on_server: %s\n", ads_errstr(rc)); ads_msgfree(ads, res); ads_destroy(&ads); return -1; } if (ads_count_replies(ads, res) == 0) { d_printf("Printer '%s' not found\n", printername); ads_msgfree(ads, res); ads_destroy(&ads); return -1; } ads_dump(ads, res); ads_msgfree(ads, res); ads_destroy(&ads); return 0; }
static int net_ads_gpo_get_gpo(struct net_context *c, int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; TALLOC_CTX *mem_ctx; struct GROUP_POLICY_OBJECT gpo; if (argc < 1 || c->display_usage) { d_printf("Usage:\n" "net ads gpo getgpo <gpo>\n" " List speciefied GPO\n" " gpo\t\tGPO to list\n"); return -1; } mem_ctx = talloc_init("ads_gpo_get_gpo"); if (mem_ctx == NULL) { return -1; } status = ads_startup(c, false, &ads); if (!ADS_ERR_OK(status)) { goto out; } if (strnequal(argv[0], "CN={", strlen("CN={"))) { status = ads_get_gpo(ads, mem_ctx, argv[0], NULL, NULL, &gpo); } else { status = ads_get_gpo(ads, mem_ctx, NULL, argv[0], NULL, &gpo); } if (!ADS_ERR_OK(status)) { d_printf("get gpo for [%s] failed: %s\n", argv[0], ads_errstr(status)); goto out; } dump_gpo(ads, mem_ctx, &gpo, 1); out: talloc_destroy(mem_ctx); ads_destroy(&ads); return 0; }
static int net_ads_gpo_link_add(struct net_context *c, int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; uint32 gpo_opt = 0; TALLOC_CTX *mem_ctx; if (argc < 2 || c->display_usage) { d_printf("Usage:\n" "net ads gpo linkadd <linkdn> <gpodn> [options]\n" " Link a container to a GPO\n" " linkdn\tContainer to link to a GPO\n" " gpodn\tGPO to link container to\n"); d_printf("note: DNs must be provided properly escaped.\n"); d_printf("See RFC 4514 for details\n"); return -1; } mem_ctx = talloc_init("add_gpo_link"); if (mem_ctx == NULL) { return -1; } if (argc == 3) { gpo_opt = atoi(argv[2]); } status = ads_startup(c, false, &ads); if (!ADS_ERR_OK(status)) { goto out; } status = ads_add_gpo_link(ads, mem_ctx, argv[0], argv[1], gpo_opt); if (!ADS_ERR_OK(status)) { d_printf("link add failed: %s\n", ads_errstr(status)); goto out; } out: talloc_destroy(mem_ctx); ads_destroy(&ads); return 0; }
static int net_ads_gpo_link_get(struct net_context *c, int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; TALLOC_CTX *mem_ctx; struct GP_LINK gp_link; if (argc < 1 || c->display_usage) { d_printf("Usage:\n" "net ads gpo linkget <container>\n" " Lists gPLink of a containter\n" " container\tContainer to get link for\n"); return -1; } mem_ctx = talloc_init("add_gpo_link"); if (mem_ctx == NULL) { return -1; } status = ads_startup(c, false, &ads); if (!ADS_ERR_OK(status)) { goto out; } status = ads_get_gpo_link(ads, mem_ctx, argv[0], &gp_link); if (!ADS_ERR_OK(status)) { d_printf("get link for %s failed: %s\n", argv[0], ads_errstr(status)); goto out; } dump_gplink(ads, mem_ctx, &gp_link); out: talloc_destroy(mem_ctx); ads_destroy(&ads); return 0; }
/* general ADS search function. Useful in diagnosing problems in ADS */ static int net_ads_dn(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; const char *dn; const char **attrs; void *res = NULL; if (argc < 1) { return net_ads_dn_usage(argc, argv); } if (!(ads = ads_startup())) { return -1; } dn = argv[0]; attrs = (argv + 1); rc = ads_do_search_all(ads, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, &res); if (!ADS_ERR_OK(rc)) { d_printf("search failed: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } d_printf("Got %d replies\n\n", ads_count_replies(ads, res)); /* dump the results */ ads_dump(ads, res); ads_msgfree(ads, res); ads_destroy(&ads); return 0; }
/* general ADS search function. Useful in diagnosing problems in ADS */ static int net_ads_search(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; const char *ldap_exp; const char **attrs; void *res = NULL; if (argc < 1) { return net_ads_search_usage(argc, argv); } if (!(ads = ads_startup())) { return -1; } ldap_exp = argv[0]; attrs = (argv + 1); rc = ads_do_search_all(ads, ads->config.bind_path, LDAP_SCOPE_SUBTREE, ldap_exp, attrs, &res); if (!ADS_ERR_OK(rc)) { d_printf("search failed: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } d_printf("Got %d replies\n\n", ads_count_replies(ads, res)); /* dump the results */ ads_dump(ads, res); ads_msgfree(ads, res); ads_destroy(&ads); return 0; }
static int net_ads_gpo_link_delete(struct net_context *c, int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; TALLOC_CTX *mem_ctx; if (argc < 2 || c->display_usage) { d_printf("Usage:\n" "net ads gpo linkdelete <linkdn> <gpodn>\n" " Delete a GPO link\n" " <linkdn>\tContainer to delete GPO from\n" " <gpodn>\tGPO to delete from container\n"); return -1; } mem_ctx = talloc_init("delete_gpo_link"); if (mem_ctx == NULL) { return -1; } status = ads_startup(c, false, &ads); if (!ADS_ERR_OK(status)) { goto out; } status = ads_delete_gpo_link(ads, mem_ctx, argv[0], argv[1]); if (!ADS_ERR_OK(status)) { d_printf("delete link failed: %s\n", ads_errstr(status)); goto out; } out: talloc_destroy(mem_ctx); ads_destroy(&ads); return 0; }
/* perform a LDAP/SASL/SPNEGO/{NTLMSSP,KRB5} bind (just how many layers can we fit on one socket??) */ static ADS_STATUS ads_sasl_spnego_gensec_bind(ADS_STRUCT *ads, const char *sasl, enum credentials_use_kerberos krb5_state, const char *target_service, const char *target_hostname, const DATA_BLOB server_blob) { DATA_BLOB blob_in = data_blob_null; DATA_BLOB blob_out = data_blob_null; int rc; NTSTATUS nt_status; ADS_STATUS status; struct auth_generic_state *auth_generic_state; bool use_spnego_principal = lp_client_use_spnego_principal(); const char *sasl_list[] = { sasl, NULL }; NTTIME end_nt_time; struct ads_saslwrap *wrap = &ads->ldap_wrap_data; nt_status = auth_generic_client_prepare(NULL, &auth_generic_state); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_username(auth_generic_state, ads->auth.user_name))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_domain(auth_generic_state, ads->auth.realm))) { return ADS_ERROR_NT(nt_status); } if (!NT_STATUS_IS_OK(nt_status = auth_generic_set_password(auth_generic_state, ads->auth.password))) { return ADS_ERROR_NT(nt_status); } if (server_blob.length == 0) { use_spnego_principal = false; } if (krb5_state == CRED_DONT_USE_KERBEROS) { use_spnego_principal = false; } cli_credentials_set_kerberos_state(auth_generic_state->credentials, krb5_state); if (target_service != NULL) { nt_status = gensec_set_target_service( auth_generic_state->gensec_security, target_service); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } } if (target_hostname != NULL) { nt_status = gensec_set_target_hostname( auth_generic_state->gensec_security, target_hostname); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } } if (target_service != NULL && target_hostname != NULL) { use_spnego_principal = false; } switch (wrap->wrap_type) { case ADS_SASLWRAP_TYPE_SEAL: gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); break; case ADS_SASLWRAP_TYPE_SIGN: if (ads->auth.flags & ADS_AUTH_SASL_FORCE) { gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); } else { /* * windows servers are broken with sign only, * so we let the NTLMSSP backend to seal here, * via GENSEC_FEATURE_LDAP_STYLE. */ gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); gensec_want_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_LDAP_STYLE); } break; case ADS_SASLWRAP_TYPE_PLAIN: break; } nt_status = auth_generic_client_start_by_sasl(auth_generic_state, sasl_list); if (!NT_STATUS_IS_OK(nt_status)) { return ADS_ERROR_NT(nt_status); } rc = LDAP_SASL_BIND_IN_PROGRESS; nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED; if (use_spnego_principal) { blob_in = data_blob_dup_talloc(talloc_tos(), server_blob); if (blob_in.length == 0) { TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } } else { blob_in = data_blob_null; } blob_out = data_blob_null; while (true) { struct berval cred, *scred = NULL; nt_status = gensec_update(auth_generic_state->gensec_security, talloc_tos(), blob_in, &blob_out); data_blob_free(&blob_in); if (!NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(nt_status)) { TALLOC_FREE(auth_generic_state); data_blob_free(&blob_out); return ADS_ERROR_NT(nt_status); } if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_out.length == 0) { break; } cred.bv_val = (char *)blob_out.data; cred.bv_len = blob_out.length; scred = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, sasl, &cred, NULL, NULL, &scred); data_blob_free(&blob_out); if ((rc != LDAP_SASL_BIND_IN_PROGRESS) && (rc != 0)) { if (scred) { ber_bvfree(scred); } TALLOC_FREE(auth_generic_state); return ADS_ERROR(rc); } if (scred) { blob_in = data_blob_talloc(talloc_tos(), scred->bv_val, scred->bv_len); if (blob_in.length != scred->bv_len) { ber_bvfree(scred); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } ber_bvfree(scred); } else { blob_in = data_blob_null; } if (NT_STATUS_IS_OK(nt_status) && rc == 0 && blob_in.length == 0) { break; } } data_blob_free(&blob_in); data_blob_free(&blob_out); if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SEAL) { bool ok; ok = gensec_have_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SEAL); if (!ok) { DEBUG(0,("The gensec feature sealing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } ok = gensec_have_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); if (!ok) { DEBUG(0,("The gensec feature signing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } } else if (wrap->wrap_type >= ADS_SASLWRAP_TYPE_SIGN) { bool ok; ok = gensec_have_feature(auth_generic_state->gensec_security, GENSEC_FEATURE_SIGN); if (!ok) { DEBUG(0,("The gensec feature signing request, but unavailable\n")); TALLOC_FREE(auth_generic_state); return ADS_ERROR_NT(NT_STATUS_INVALID_NETWORK_RESPONSE); } } ads->auth.tgs_expire = LONG_MAX; end_nt_time = gensec_expire_time(auth_generic_state->gensec_security); if (end_nt_time != GENSEC_EXPIRE_TIME_INFINITY) { struct timeval tv; nttime_to_timeval(&tv, end_nt_time); ads->auth.tgs_expire = tv.tv_sec; } if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { size_t max_wrapped = gensec_max_wrapped_size(auth_generic_state->gensec_security); wrap->out.max_unwrapped = gensec_max_input_size(auth_generic_state->gensec_security); wrap->out.sig_size = max_wrapped - wrap->out.max_unwrapped; /* * Note that we have to truncate this to 0x2C * (taken from a capture with LDAP unbind), as the * signature size is not constant for Kerberos with * arcfour-hmac-md5. */ wrap->in.min_wrapped = MIN(wrap->out.sig_size, 0x2C); wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; status = ads_setup_sasl_wrapping(wrap, ads->ldap.ld, &ads_sasl_gensec_ops, auth_generic_state->gensec_security); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); TALLOC_FREE(auth_generic_state); return status; } /* Only keep the gensec_security element around long-term */ talloc_steal(NULL, auth_generic_state->gensec_security); } TALLOC_FREE(auth_generic_state); return ADS_ERROR(rc); }
/* join a domain using ADS */ int net_ads_join(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; char *password; char *machine_account = NULL; char *tmp_password; const char *org_unit = "Computers"; char *dn; void *res; DOM_SID dom_sid; char *ou_str; uint32 sec_channel_type = SEC_CHAN_WKSTA; uint32 account_type = UF_WORKSTATION_TRUST_ACCOUNT; const char *short_domain_name = NULL; TALLOC_CTX *ctx = NULL; if (argc > 0) { org_unit = argv[0]; } if (!secrets_init()) { DEBUG(1,("Failed to initialise secrets database\n")); return -1; } tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); password = strdup(tmp_password); if (!(ads = ads_startup())) { return -1; } if (!*lp_realm()) { d_printf("realm must be set in in smb.conf for ADS join to succeed.\n"); ads_destroy(&ads); return -1; } if (strcmp(ads->config.realm, lp_realm()) != 0) { d_printf("realm of remote server (%s) and realm in smb.conf (%s) DO NOT match. Aborting join\n", ads->config.realm, lp_realm()); ads_destroy(&ads); return -1; } ou_str = ads_ou_string(org_unit); asprintf(&dn, "%s,%s", ou_str, ads->config.bind_path); free(ou_str); rc = ads_search_dn(ads, &res, dn, NULL); ads_msgfree(ads, res); if (rc.error_type == ENUM_ADS_ERROR_LDAP && rc.err.rc == LDAP_NO_SUCH_OBJECT) { d_printf("ads_join_realm: organizational unit %s does not exist (dn:%s)\n", org_unit, dn); ads_destroy(&ads); return -1; } free(dn); if (!ADS_ERR_OK(rc)) { d_printf("ads_join_realm: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } rc = ads_join_realm(ads, global_myname(), account_type, org_unit); if (!ADS_ERR_OK(rc)) { d_printf("ads_join_realm: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } rc = ads_domain_sid(ads, &dom_sid); if (!ADS_ERR_OK(rc)) { d_printf("ads_domain_sid: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } if (asprintf(&machine_account, "%s$", global_myname()) == -1) { d_printf("asprintf failed\n"); ads_destroy(&ads); return -1; } rc = ads_set_machine_password(ads, machine_account, password); if (!ADS_ERR_OK(rc)) { d_printf("ads_set_machine_password: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } /* make sure we get the right workgroup */ if ( !(ctx = talloc_init("net ads join")) ) { d_printf("talloc_init() failed!\n"); ads_destroy(&ads); return -1; } rc = ads_workgroup_name(ads, ctx, &short_domain_name); if ( ADS_ERR_OK(rc) ) { if ( !strequal(lp_workgroup(), short_domain_name) ) { d_printf("The workgroup in smb.conf does not match the short\n"); d_printf("domain name obtained from the server.\n"); d_printf("Using the name [%s] from the server.\n", short_domain_name); d_printf("You should set \"workgroup = %s\" in smb.conf.\n", short_domain_name); } } else { short_domain_name = lp_workgroup(); } d_printf("Using short domain name -- %s\n", short_domain_name); /* HACK ALRET! Store the sid and password under bother the lp_workgroup() value from smb.conf and the string returned from the server. The former is neede to bootstrap winbindd's first connection to the DC to get the real short domain name --jerry */ if (!secrets_store_domain_sid(lp_workgroup(), &dom_sid)) { DEBUG(1,("Failed to save domain sid\n")); ads_destroy(&ads); return -1; } if (!secrets_store_machine_password(password, lp_workgroup(), sec_channel_type)) { DEBUG(1,("Failed to save machine password\n")); ads_destroy(&ads); return -1; } if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) { DEBUG(1,("Failed to save domain sid\n")); ads_destroy(&ads); return -1; } if (!secrets_store_machine_password(password, short_domain_name, sec_channel_type)) { DEBUG(1,("Failed to save machine password\n")); ads_destroy(&ads); return -1; } /* Now build the keytab, using the same ADS connection */ if (lp_use_kerberos_keytab() && ads_keytab_create_default(ads)) { DEBUG(1,("Error creating host keytab!\n")); } d_printf("Joined '%s' to realm '%s'\n", global_myname(), ads->config.realm); SAFE_FREE(password); SAFE_FREE(machine_account); if ( ctx ) { talloc_destroy(ctx); } ads_destroy(&ads); return 0; }
/* this performs a SASL/SPNEGO bind */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { struct berval *scred=NULL; int rc, i; ADS_STATUS status; DATA_BLOB blob; char *given_principal = NULL; char *OIDs[ASN1_MAX_OIDS]; #ifdef HAVE_KRB5 bool got_kerberos_mechanism = False; #endif rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto failed; } blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(blob, OIDs, &given_principal)) { data_blob_free(&blob); status = ADS_ERROR(LDAP_OPERATIONS_ERROR); goto failed; } data_blob_free(&blob); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); #ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } #endif talloc_free(OIDs[i]); } DEBUG(3,("ads_sasl_spnego_bind: got server principal name = %s\n", given_principal)); #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && got_kerberos_mechanism) { struct ads_service_principal p; status = ads_generate_service_principal(ads, given_principal, &p); TALLOC_FREE(given_principal); if (!ADS_ERR_OK(status)) { return status; } status = ads_sasl_spnego_krb5_bind(ads, &p); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); return status; } DEBUG(10,("ads_sasl_spnego_krb5_bind failed with: %s, " "calling kinit\n", ads_errstr(status))); status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_spnego_krb5_bind(ads, &p); if (!ADS_ERR_OK(status)) { DEBUG(0,("kinit succeeded but " "ads_sasl_spnego_krb5_bind failed: %s\n", ads_errstr(status))); } } ads_free_service_principal(&p); /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { return status; } } else #endif { TALLOC_FREE(given_principal); } /* lets do NTLMSSP ... this has the big advantage that we don't need to sync clocks, and we don't rely on special versions of the krb5 library for HMAC_MD4 encryption */ return ads_sasl_spnego_ntlmssp_bind(ads); failed: return status; }
static NTSTATUS _idmap_adex_init(struct idmap_domain *dom) { ADS_STRUCT *ads = NULL; ADS_STATUS status; static NTSTATUS init_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; struct dom_sid domain_sid; fstring dcname; struct sockaddr_storage ip; struct likewise_cell *lwcell; if (NT_STATUS_IS_OK(init_status)) return NT_STATUS_OK; /* Silently fail if we are not a member server in security = ads */ if ((lp_server_role() != ROLE_DOMAIN_MEMBER) || (lp_security() != SEC_ADS)) { init_status = NT_STATUS_INVALID_SERVER_STATE; BAIL_ON_NTSTATUS_ERROR(init_status); } /* fetch our domain SID first */ if (!secrets_fetch_domain_sid(lp_workgroup(), &domain_sid)) { init_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; BAIL_ON_NTSTATUS_ERROR(init_status); } /* reuse the same ticket cache as winbindd */ setenv("KRB5CCNAME", WINBIND_CCACHE_NAME, 1); /* Establish a connection to a DC */ if ((ads = ads_init(lp_realm(), lp_workgroup(), NULL)) == NULL) { init_status = NT_STATUS_NO_MEMORY; BAIL_ON_NTSTATUS_ERROR(init_status); } ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); ads->auth.realm = SMB_STRDUP(lp_realm()); /* get the DC name here to setup the server affinity cache and local krb5.conf */ get_dc_name(lp_workgroup(), lp_realm(), dcname, &ip); status = ads_connect(ads); if (!ADS_ERR_OK(status)) { DEBUG(0, ("_idmap_adex_init: ads_connect() failed! (%s)\n", ads_errstr(status))); } init_status = ads_ntstatus(status); BAIL_ON_NTSTATUS_ERROR(init_status); /* Find out cell membership */ init_status = cell_locate_membership(ads); if (!NT_STATUS_IS_OK(init_status)) { DEBUG(0,("LWI: Fail to locate cell membership (%s).", nt_errstr(init_status))); goto done; } /* Fill in the cell information */ lwcell = cell_list_head(); init_status = cell_lookup_settings(lwcell); BAIL_ON_NTSTATUS_ERROR(init_status); /* Miscellaneous setup. E.g. set up the list of GC servers and domain list for our forest (does not actually connect). */ init_status = gc_init_list(); BAIL_ON_NTSTATUS_ERROR(init_status); init_status = domain_init_list(); BAIL_ON_NTSTATUS_ERROR(init_status); done: if (!NT_STATUS_IS_OK(init_status)) { DEBUG(1,("Likewise initialization failed (%s)\n", nt_errstr(init_status))); } /* cleanup */ if (!NT_STATUS_IS_OK(init_status)) { cell_list_destroy(); /* init_status stores the failure reason but we need to return success or else idmap_init() will drop us from the backend list */ return NT_STATUS_OK; } init_status = NT_STATUS_OK; return init_status; }
/* a wrapper around ldap_search_s that retries depending on the error code this is supposed to catch dropped connections and auto-reconnect */ ADS_STATUS ads_do_search_retry(ADS_STRUCT *ads, const char *bind_path, int scope, const char *expr, const char **attrs, void **res) { ADS_STATUS status; int count = 3; char *bp; *res = NULL; if (!ads->ld && time(NULL) - ads->last_attempt < ADS_RECONNECT_TIME) { return ADS_ERROR(LDAP_SERVER_DOWN); } bp = strdup(bind_path); if (!bp) { return ADS_ERROR_NT(NT_STATUS_NO_MEMORY); } while (count--) { *res = NULL; status = ads_do_search_all(ads, bp, scope, expr, attrs, res); if (ADS_ERR_OK(status)) { DEBUG(5,("Search for %s gave %d replies\n", expr, ads_count_replies(ads, *res))); SAFE_FREE(bp); return status; } if (*res) ads_msgfree(ads, *res); *res = NULL; DEBUG(3,("Reopening ads connection to realm '%s' after error %s\n", ads->config.realm, ads_errstr(status))); if (ads->ld) { ldap_unbind(ads->ld); } ads->ld = NULL; status = ads_connect(ads); if (!ADS_ERR_OK(status)) { DEBUG(1,("ads_search_retry: failed to reconnect (%s)\n", ads_errstr(status))); ads_destroy(&ads); SAFE_FREE(bp); return status; } } SAFE_FREE(bp); if (!ADS_ERR_OK(status)) DEBUG(1,("ads reopen failed after error %s\n", ads_errstr(status))); return status; }
static int ads_user_add(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS status; char *upn, *userdn; void *res=NULL; int rc = -1; if (argc < 1) return net_ads_user_usage(argc, argv); if (!(ads = ads_startup())) { return -1; } status = ads_find_user_acct(ads, &res, argv[0]); if (!ADS_ERR_OK(status)) { d_printf("ads_user_add: %s\n", ads_errstr(status)); goto done; } if (ads_count_replies(ads, res)) { d_printf("ads_user_add: User %s already exists\n", argv[0]); goto done; } status = ads_add_user_acct(ads, argv[0], opt_container, opt_comment); if (!ADS_ERR_OK(status)) { d_printf("Could not add user %s: %s\n", argv[0], ads_errstr(status)); goto done; } /* if no password is to be set, we're done */ if (argc == 1) { d_printf("User %s added\n", argv[0]); rc = 0; goto done; } /* try setting the password */ asprintf(&upn, "%s@%s", argv[0], ads->config.realm); status = ads_krb5_set_password(ads->auth.kdc_server, upn, argv[1], ads->auth.time_offset); safe_free(upn); if (ADS_ERR_OK(status)) { d_printf("User %s added\n", argv[0]); rc = 0; goto done; } /* password didn't set, delete account */ d_printf("Could not add user %s. Error setting password %s\n", argv[0], ads_errstr(status)); ads_msgfree(ads, res); status=ads_find_user_acct(ads, &res, argv[0]); if (ADS_ERR_OK(status)) { userdn = ads_get_dn(ads, res); ads_del_dn(ads, userdn); ads_memfree(ads, userdn); } done: if (res) ads_msgfree(ads, res); ads_destroy(&ads); return rc; }
static ADS_STRUCT *ads_startup(void) { ADS_STRUCT *ads; ADS_STATUS status; BOOL need_password = False; BOOL second_time = False; char *cp; /* lp_realm() should be handled by a command line param, However, the join requires that realm be set in smb.conf and compares our realm with the remote server's so this is ok until someone needs more flexibility */ ads = ads_init(lp_realm(), opt_target_workgroup, opt_host); if (!opt_user_name) { opt_user_name = "administrator"; } if (opt_user_specified) { need_password = True; } retry: if (!opt_password && need_password && !opt_machine_pass) { char *prompt; asprintf(&prompt,"%s's password: "******"name@realm", * extract the realm and convert to upper case. * This is only used to establish the connection. */ if ((cp = strchr(ads->auth.user_name, '@'))!=0) { *cp++ = '\0'; ads->auth.realm = smb_xstrdup(cp); strupper_m(ads->auth.realm); } status = ads_connect(ads); if (!ADS_ERR_OK(status)) { if (!need_password && !second_time) { need_password = True; second_time = True; goto retry; } else { DEBUG(0,("ads_connect: %s\n", ads_errstr(status))); return NULL; } } return ads; }
/* this performs a SASL/gssapi bind we avoid using cyrus-sasl to make Samba more robust. cyrus-sasl is very dependent on correctly configured DNS whereas this routine is much less fragile see RFC2078 and RFC2222 for details */ static ADS_STATUS ads_sasl_gssapi_do_bind(ADS_STRUCT *ads, const gss_name_t serv_name) { uint32_t minor_status; gss_cred_id_t gss_cred = GSS_C_NO_CREDENTIAL; gss_ctx_id_t context_handle = GSS_C_NO_CONTEXT; gss_OID mech_type = GSS_C_NULL_OID; gss_buffer_desc output_token, input_token; uint32_t req_flags, ret_flags; int conf_state; struct berval cred; struct berval *scred = NULL; int i=0; int gss_rc, rc; uint8_t *p; uint32_t max_msg_size = ADS_SASL_WRAPPING_OUT_MAX_WRAPPED; uint8_t wrap_type = ADS_SASLWRAP_TYPE_PLAIN; ADS_STATUS status; struct ads_saslwrap *wrap = &ads->ldap_wrap_data; input_token.value = NULL; input_token.length = 0; status = ads_init_gssapi_cred(ads, &gss_cred); if (!ADS_ERR_OK(status)) { goto failed; } /* * Note: here we always ask the gssapi for sign and seal * as this is negotiated later after the mutal * authentication */ req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG; for (i=0; i < MAX_GSS_PASSES; i++) { gss_rc = gss_init_sec_context(&minor_status, gss_cred, &context_handle, serv_name, mech_type, req_flags, 0, NULL, &input_token, NULL, &output_token, &ret_flags, NULL); if (scred) { ber_bvfree(scred); scred = NULL; } if (gss_rc && gss_rc != GSS_S_CONTINUE_NEEDED) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } cred.bv_val = (char *)output_token.value; cred.bv_len = output_token.length; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto failed; } if (output_token.value) { gss_release_buffer(&minor_status, &output_token); } if (scred) { input_token.value = scred->bv_val; input_token.length = scred->bv_len; } else { input_token.value = NULL; input_token.length = 0; } if (gss_rc == 0) break; } gss_rc = gss_unwrap(&minor_status,context_handle,&input_token,&output_token, &conf_state,NULL); if (scred) { ber_bvfree(scred); scred = NULL; } if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } p = (uint8_t *)output_token.value; #if 0 file_save("sasl_gssapi.dat", output_token.value, output_token.length); #endif if (p) { wrap_type = CVAL(p,0); SCVAL(p,0,0); max_msg_size = RIVAL(p,0); } gss_release_buffer(&minor_status, &output_token); if (!(wrap_type & wrap->wrap_type)) { /* * the server doesn't supports the wrap * type we want :-( */ DEBUG(0,("The ldap sasl wrap type doesn't match wanted[%d] server[%d]\n", wrap->wrap_type, wrap_type)); DEBUGADD(0,("You may want to set the 'client ldap sasl wrapping' option\n")); status = ADS_ERROR_NT(NT_STATUS_NOT_SUPPORTED); goto failed; } /* 0x58 is the minimum windows accepts */ if (max_msg_size < 0x58) { max_msg_size = 0x58; } output_token.length = 4; output_token.value = SMB_MALLOC(output_token.length); if (!output_token.value) { output_token.length = 0; status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY); goto failed; } p = (uint8_t *)output_token.value; RSIVAL(p,0,max_msg_size); SCVAL(p,0,wrap->wrap_type); /* * we used to add sprintf("dn:%s", ads->config.bind_path) here. * but using ads->config.bind_path is the wrong! It should be * the DN of the user object! * * w2k3 gives an error when we send an incorrect DN, but sending nothing * is ok and matches the information flow used in GSS-SPNEGO. */ gss_rc = gss_wrap(&minor_status, context_handle,0,GSS_C_QOP_DEFAULT, &output_token, /* used as *input* here. */ &conf_state, &input_token); /* Used as *output* here. */ if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); output_token.length = 0; SAFE_FREE(output_token.value); goto failed; } /* We've finished with output_token. */ SAFE_FREE(output_token.value); output_token.length = 0; cred.bv_val = (char *)input_token.value; cred.bv_len = input_token.length; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSSAPI", &cred, NULL, NULL, &scred); gss_release_buffer(&minor_status, &input_token); status = ADS_ERROR(rc); if (!ADS_ERR_OK(status)) { goto failed; } if (wrap->wrap_type > ADS_SASLWRAP_TYPE_PLAIN) { gss_rc = gss_wrap_size_limit(&minor_status, context_handle, (wrap->wrap_type == ADS_SASLWRAP_TYPE_SEAL), GSS_C_QOP_DEFAULT, max_msg_size, &wrap->out.max_unwrapped); if (gss_rc) { status = ADS_ERROR_GSS(gss_rc, minor_status); goto failed; } wrap->out.sig_size = max_msg_size - wrap->out.max_unwrapped; wrap->in.min_wrapped = 0x2C; /* taken from a capture with LDAP unbind */ wrap->in.max_wrapped = ADS_SASL_WRAPPING_IN_MAX_WRAPPED; status = ads_setup_sasl_wrapping(wrap->wrap_private_data, ads->ldap.ld, &ads_sasl_gssapi_ops, context_handle); if (!ADS_ERR_OK(status)) { DEBUG(0, ("ads_setup_sasl_wrapping() failed: %s\n", ads_errstr(status))); goto failed; } /* make sure we don't free context_handle */ context_handle = GSS_C_NO_CONTEXT; } failed: if (gss_cred != GSS_C_NO_CREDENTIAL) gss_release_cred(&minor_status, &gss_cred); if (context_handle != GSS_C_NO_CONTEXT) gss_delete_sec_context(&minor_status, &context_handle, GSS_C_NO_BUFFER); if(scred) ber_bvfree(scred); return status; }
static int net_ads_printer_publish(int argc, const char **argv) { ADS_STRUCT *ads; ADS_STATUS rc; const char *servername, *printername; struct cli_state *cli; struct in_addr server_ip; NTSTATUS nt_status; TALLOC_CTX *mem_ctx = talloc_init("net_ads_printer_publish"); ADS_MODLIST mods = ads_init_mods(mem_ctx); char *prt_dn, *srv_dn, **srv_cn; void *res = NULL; if (!(ads = ads_startup())) { return -1; } if (argc < 1) { return net_ads_printer_usage(argc, argv); } printername = argv[0]; if (argc == 2) { servername = argv[1]; } else { servername = global_myname(); } /* Get printer data from SPOOLSS */ resolve_name(servername, &server_ip, 0x20); nt_status = cli_full_connection(&cli, global_myname(), servername, &server_ip, 0, "IPC$", "IPC", opt_user_name, opt_workgroup, opt_password ? opt_password : "", CLI_FULL_CONNECTION_USE_KERBEROS, Undefined, NULL); if (NT_STATUS_IS_ERR(nt_status)) { d_printf("Unable to open a connnection to %s to obtain data " "for %s\n", servername, printername); ads_destroy(&ads); return -1; } /* Publish on AD server */ ads_find_machine_acct(ads, &res, servername); if (ads_count_replies(ads, res) == 0) { d_printf("Could not find machine account for server %s\n", servername); ads_destroy(&ads); return -1; } srv_dn = ldap_get_dn(ads->ld, res); srv_cn = ldap_explode_dn(srv_dn, 1); asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn[0], printername, srv_dn); cli_nt_session_open(cli, PI_SPOOLSS); get_remote_printer_publishing_data(cli, mem_ctx, &mods, printername); rc = ads_add_printer_entry(ads, prt_dn, mem_ctx, &mods); if (!ADS_ERR_OK(rc)) { d_printf("ads_publish_printer: %s\n", ads_errstr(rc)); ads_destroy(&ads); return -1; } d_printf("published printer\n"); ads_destroy(&ads); return 0; }
/* this performs a SASL/SPNEGO bind */ static ADS_STATUS ads_sasl_spnego_bind(ADS_STRUCT *ads) { TALLOC_CTX *frame = talloc_stackframe(); struct ads_service_principal p = {0}; struct berval *scred=NULL; int rc, i; ADS_STATUS status; DATA_BLOB blob = data_blob_null; char *given_principal = NULL; char *OIDs[ASN1_MAX_OIDS]; #ifdef HAVE_KRB5 bool got_kerberos_mechanism = False; #endif const char *mech = NULL; rc = ldap_sasl_bind_s(ads->ldap.ld, NULL, "GSS-SPNEGO", NULL, NULL, NULL, &scred); if (rc != LDAP_SASL_BIND_IN_PROGRESS) { status = ADS_ERROR(rc); goto done; } blob = data_blob(scred->bv_val, scred->bv_len); ber_bvfree(scred); #if 0 file_save("sasl_spnego.dat", blob.data, blob.length); #endif /* the server sent us the first part of the SPNEGO exchange in the negprot reply */ if (!spnego_parse_negTokenInit(talloc_tos(), blob, OIDs, &given_principal, NULL) || OIDs[0] == NULL) { status = ADS_ERROR(LDAP_OPERATIONS_ERROR); goto done; } TALLOC_FREE(given_principal); /* make sure the server understands kerberos */ for (i=0;OIDs[i];i++) { DEBUG(3,("ads_sasl_spnego_bind: got OID=%s\n", OIDs[i])); #ifdef HAVE_KRB5 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 || strcmp(OIDs[i], OID_KERBEROS5) == 0) { got_kerberos_mechanism = True; } #endif talloc_free(OIDs[i]); } status = ads_generate_service_principal(ads, &p); if (!ADS_ERR_OK(status)) { goto done; } #ifdef HAVE_KRB5 if (!(ads->auth.flags & ADS_AUTH_DISABLE_KERBEROS) && got_kerberos_mechanism) { mech = "KRB5"; if (ads->auth.password == NULL || ads->auth.password[0] == '\0') { status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_MUST_USE_KERBEROS, p.service, p.hostname, blob); if (ADS_ERR_OK(status)) { ads_free_service_principal(&p); goto done; } DEBUG(10,("ads_sasl_spnego_gensec_bind(KRB5) failed with: %s, " "calling kinit\n", ads_errstr(status))); } status = ADS_ERROR_KRB5(ads_kinit_password(ads)); if (ADS_ERR_OK(status)) { status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_MUST_USE_KERBEROS, p.service, p.hostname, blob); if (!ADS_ERR_OK(status)) { DEBUG(0,("kinit succeeded but " "ads_sasl_spnego_gensec_bind(KRB5) failed " "for %s/%s with user[%s] realm[%s]: %s\n", p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } } /* only fallback to NTLMSSP if allowed */ if (ADS_ERR_OK(status) || !(ads->auth.flags & ADS_AUTH_ALLOW_NTLMSSP)) { goto done; } DEBUG(1,("ads_sasl_spnego_gensec_bind(KRB5) failed " "for %s/%s with user[%s] realm[%s]: %s, " "fallback to NTLMSSP\n", p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } #endif /* lets do NTLMSSP ... this has the big advantage that we don't need to sync clocks, and we don't rely on special versions of the krb5 library for HMAC_MD4 encryption */ mech = "NTLMSSP"; status = ads_sasl_spnego_gensec_bind(ads, "GSS-SPNEGO", CRED_DONT_USE_KERBEROS, p.service, p.hostname, data_blob_null); done: if (!ADS_ERR_OK(status)) { DEBUG(1,("ads_sasl_spnego_gensec_bind(%s) failed " "for %s/%s with user[%s] realm=[%s]: %s\n", mech, p.service, p.hostname, ads->auth.user_name, ads->auth.realm, ads_errstr(status))); } ads_free_service_principal(&p); TALLOC_FREE(frame); if (blob.data != NULL) { data_blob_free(&blob); } return status; }