ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal) { char *password; char *new_password; ADS_STATUS ret; enum netr_SchannelType sec_channel_type; if ((password = secrets_fetch_machine_password(lp_workgroup(), NULL, &sec_channel_type)) == NULL) { DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal)); return ADS_ERROR_SYSTEM(ENOENT); } new_password = generate_random_password(talloc_tos(), DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH, DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); ret = kerberos_set_password(ads->auth.kdc_server, host_principal, password, host_principal, new_password, ads->auth.time_offset); if (!ADS_ERR_OK(ret)) { goto failed; } if (!secrets_store_machine_password(new_password, lp_workgroup(), sec_channel_type)) { DEBUG(1,("Failed to save machine password\n")); ret = ADS_ERROR_SYSTEM(EACCES); goto failed; } failed: SAFE_FREE(password); return ret; }
bool set_cmdline_auth_info_machine_account_creds(struct user_auth_info *auth_info) { char *pass = NULL; char *account = NULL; if (!get_cmdline_auth_info_use_machine_account(auth_info)) { return false; } if (!secrets_init()) { d_printf("ERROR: Unable to open secrets database\n"); return false; } if (asprintf(&account, "%s$@%s", lp_netbios_name(), lp_realm()) < 0) { return false; } pass = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!pass) { d_printf("ERROR: Unable to fetch machine password for " "%s in domain %s\n", account, lp_workgroup()); SAFE_FREE(account); return false; } set_cmdline_auth_info_username(auth_info, account); set_cmdline_auth_info_password(auth_info, pass); SAFE_FREE(account); SAFE_FREE(pass); return true; }
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; }
int net_use_machine_account(void) { char *user_name = NULL; if (!secrets_init()) { d_fprintf(stderr, "ERROR: Unable to open secrets database\n"); exit(1); } opt_password = secrets_fetch_machine_password(opt_target_workgroup, NULL, NULL); if (asprintf(&user_name, "%s$", global_myname()) == -1) { return -1; } opt_user_name = user_name; return 0; }
int net_use_krb_machine_account(struct net_context *c) { char *user_name = NULL; if (!secrets_init()) { d_fprintf(stderr,_("ERROR: Unable to open secrets database\n")); exit(1); } c->opt_password = secrets_fetch_machine_password( c->opt_target_workgroup, NULL, NULL); if (asprintf(&user_name, "%s$@%s", global_myname(), lp_realm()) == -1) { return -1; } c->opt_user_name = user_name; return 0; }
bool secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], time_t *pass_last_set_time, enum netr_SchannelType *channel) { char *plaintext; plaintext = secrets_fetch_machine_password(domain, pass_last_set_time, channel); if (plaintext) { DEBUG(4,("Using cleartext machine password\n")); E_md4hash(plaintext, ret_pwd); SAFE_FREE(plaintext); return True; } return secrets_fetch_trust_account_password_legacy(domain, ret_pwd, pass_last_set_time, channel); }
BOOL secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16], time_t *pass_last_set_time, uint32 *channel) { struct machine_acct_pass *pass; char *plaintext; size_t size; plaintext = secrets_fetch_machine_password(domain, pass_last_set_time, channel); if (plaintext) { DEBUG(4,("Using cleartext machine password\n")); E_md4hash(plaintext, ret_pwd); SAFE_FREE(plaintext); return True; } if (!(pass = secrets_fetch(trust_keystr(domain), &size))) { DEBUG(5, ("secrets_fetch failed!\n")); return False; } if (size != sizeof(*pass)) { DEBUG(0, ("secrets were of incorrect size!\n")); return False; } if (pass_last_set_time) *pass_last_set_time = pass->mod_time; memcpy(ret_pwd, pass->hash, 16); SAFE_FREE(pass); if (channel) *channel = get_default_sec_channel(); return True; }
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; }
/* return our ads connections structure for a domain. We keep the connection open to make things faster */ static ADS_STRUCT *ads_cached_connection(struct winbindd_domain *domain) { ADS_STRUCT *ads; ADS_STATUS status; fstring dc_name; struct sockaddr_storage dc_ss; DEBUG(10,("ads_cached_connection\n")); if (domain->private_data) { time_t expire; time_t now = time(NULL); /* check for a valid structure */ ads = (ADS_STRUCT *)domain->private_data; expire = MIN(ads->auth.tgt_expire, ads->auth.tgs_expire); DEBUG(7, ("Current tickets expire in %d seconds (at %d, time is now %d)\n", (uint32)expire-(uint32)now, (uint32) expire, (uint32) now)); if ( ads->config.realm && (expire > now)) { return ads; } else { /* we own this ADS_STRUCT so make sure it goes away */ DEBUG(7,("Deleting expired krb5 credential cache\n")); ads->is_mine = True; ads_destroy( &ads ); ads_kdestroy("MEMORY:winbind_ccache"); domain->private_data = NULL; } } /* we don't want this to affect the users ccache */ setenv("KRB5CCNAME", "MEMORY:winbind_ccache", 1); ads = ads_init(domain->alt_name, domain->name, NULL); if (!ads) { DEBUG(1,("ads_init for domain %s failed\n", domain->name)); return NULL; } /* the machine acct password might have change - fetch it every time */ SAFE_FREE(ads->auth.password); SAFE_FREE(ads->auth.realm); if ( IS_DC ) { if ( !pdb_get_trusteddom_pw( domain->name, &ads->auth.password, NULL, NULL ) ) { ads_destroy( &ads ); return NULL; } ads->auth.realm = SMB_STRDUP( ads->server.realm ); strupper_m( ads->auth.realm ); } else { struct winbindd_domain *our_domain = domain; ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); /* always give preference to the alt_name in our primary domain if possible */ if ( !domain->primary ) our_domain = find_our_domain(); if ( our_domain->alt_name[0] != '\0' ) { ads->auth.realm = SMB_STRDUP( our_domain->alt_name ); strupper_m( ads->auth.realm ); } else ads->auth.realm = SMB_STRDUP( lp_realm() ); } ads->auth.renewable = WINBINDD_PAM_AUTH_KRB5_RENEW_TIME; /* Setup the server affinity cache. We don't reaally care about the name. Just setup affinity and the KRB5_CONFIG file. */ get_dc_name( ads->server.workgroup, ads->server.realm, dc_name, &dc_ss ); status = ads_connect(ads); if (!ADS_ERR_OK(status) || !ads->config.realm) { DEBUG(1,("ads_connect for domain %s failed: %s\n", domain->name, ads_errstr(status))); ads_destroy(&ads); /* if we get ECONNREFUSED then it might be a NT4 server, fall back to MSRPC */ if (status.error_type == ENUM_ADS_ERROR_SYSTEM && status.err.rc == ECONNREFUSED) { /* 'reconnect_methods' is the MS-RPC backend. */ DEBUG(1,("Trying MSRPC methods\n")); domain->backend = &reconnect_methods; } return NULL; } /* set the flag that says we don't own the memory even though we do so that ads_destroy() won't destroy the structure we pass back by reference */ ads->is_mine = False; domain->private_data = (void *)ads; return ads; }
NTSTATUS cell_connect(struct likewise_cell *c) { ADS_STRUCT *ads = NULL; ADS_STATUS ads_status; fstring dc_name; struct sockaddr_storage dcip; NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; /* have to at least have the AD domain name */ if (!c->dns_domain) { nt_status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; BAIL_ON_NTSTATUS_ERROR(nt_status); } /* clear out any old information */ if (c->conn) { ads_destroy(&c->conn); c->conn = NULL; } /* now setup the new connection */ ads = ads_init(c->dns_domain, NULL, NULL); BAIL_ON_PTR_ERROR(ads, nt_status); ads->auth.password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); ads->auth.realm = SMB_STRDUP(lp_realm()); /* Make the connection. We should already have an initial TGT using the machine creds */ if (cell_flags(c) & LWCELL_FLAG_GC_CELL) { ads_status = ads_connect_gc(ads); } else { /* Set up server affinity for normal cells and the client site name cache */ if (!get_dc_name("", c->dns_domain, dc_name, &dcip)) { nt_status = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND; BAIL_ON_NTSTATUS_ERROR(nt_status); } ads_status = ads_connect(ads); } c->conn = ads; nt_status = ads_ntstatus(ads_status); done: if (!NT_STATUS_IS_OK(nt_status)) { ads_destroy(&ads); c->conn = NULL; } return nt_status; }
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; }
WERROR check_published_printers(struct messaging_context *msg_ctx) { ADS_STATUS ads_rc; ADS_STRUCT *ads = NULL; int snum; int n_services = lp_numservices(); TALLOC_CTX *tmp_ctx = NULL; struct auth_serversupplied_info *session_info = NULL; struct spoolss_PrinterInfo2 *pinfo2; NTSTATUS status; WERROR result; tmp_ctx = talloc_new(NULL); if (!tmp_ctx) return WERR_NOMEM; ads = ads_init(lp_realm(), lp_workgroup(), NULL); if (!ads) { DEBUG(3, ("ads_init() failed\n")); return WERR_SERVER_UNAVAILABLE; } 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_connect() will find the DC for us */ ads_rc = ads_connect(ads); if (!ADS_ERR_OK(ads_rc)) { DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc))); result = WERR_ACCESS_DENIED; goto done; } status = make_session_info_system(tmp_ctx, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("check_published_printers: " "Could not create system session_info\n")); result = WERR_ACCESS_DENIED; goto done; } for (snum = 0; snum < n_services; snum++) { if (!lp_snum_ok(snum) || !lp_print_ok(snum)) { continue; } result = winreg_get_printer(tmp_ctx, session_info, msg_ctx, lp_servicename(snum), &pinfo2); if (!W_ERROR_IS_OK(result)) { continue; } if (pinfo2->attributes & PRINTER_ATTRIBUTE_PUBLISHED) { nt_printer_publish_ads(msg_ctx, ads, pinfo2); } TALLOC_FREE(pinfo2); } result = WERR_OK; done: ads_destroy(&ads); ads_kdestroy("MEMORY:prtpub_cache"); talloc_free(tmp_ctx); return result; }
WERROR nt_printer_publish(TALLOC_CTX *mem_ctx, const struct auth_serversupplied_info *session_info, struct messaging_context *msg_ctx, struct spoolss_PrinterInfo2 *pinfo2, int action) { uint32_t info2_mask = SPOOLSS_PRINTER_INFO_ATTRIBUTES; struct spoolss_SetPrinterInfo2 *sinfo2; ADS_STATUS ads_rc; ADS_STRUCT *ads = NULL; WERROR win_rc; sinfo2 = talloc_zero(mem_ctx, struct spoolss_SetPrinterInfo2); if (!sinfo2) { return WERR_NOMEM; } switch (action) { case DSPRINT_PUBLISH: case DSPRINT_UPDATE: pinfo2->attributes |= PRINTER_ATTRIBUTE_PUBLISHED; break; case DSPRINT_UNPUBLISH: pinfo2->attributes ^= PRINTER_ATTRIBUTE_PUBLISHED; break; default: win_rc = WERR_NOT_SUPPORTED; goto done; } sinfo2->attributes = pinfo2->attributes; win_rc = winreg_update_printer(mem_ctx, session_info, msg_ctx, pinfo2->sharename, info2_mask, sinfo2, NULL, NULL); if (!W_ERROR_IS_OK(win_rc)) { DEBUG(3, ("err %d saving data\n", W_ERROR_V(win_rc))); goto done; } TALLOC_FREE(sinfo2); ads = ads_init(lp_realm(), lp_workgroup(), NULL); if (!ads) { DEBUG(3, ("ads_init() failed\n")); win_rc = WERR_SERVER_UNAVAILABLE; goto done; } 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_connect() will find the DC for us */ ads_rc = ads_connect(ads); if (!ADS_ERR_OK(ads_rc)) { DEBUG(3, ("ads_connect failed: %s\n", ads_errstr(ads_rc))); win_rc = WERR_ACCESS_DENIED; goto done; } switch (action) { case DSPRINT_PUBLISH: case DSPRINT_UPDATE: win_rc = nt_printer_publish_ads(msg_ctx, ads, pinfo2); break; case DSPRINT_UNPUBLISH: win_rc = nt_printer_unpublish_ads(ads, pinfo2->sharename); break; } done: ads_destroy(&ads); return win_rc; }
static void popt_common_credentials_callback(poptContext con, enum poptCallbackReason reason, const struct poptOption *opt, const char *arg, const void *data) { char *p; if (reason == POPT_CALLBACK_REASON_PRE) { cmdline_auth_info.use_kerberos = False; cmdline_auth_info.got_pass = False; cmdline_auth_info.signing_state = Undefined; pstrcpy(cmdline_auth_info.username, "GUEST"); if (getenv("LOGNAME"))pstrcpy(cmdline_auth_info.username,getenv("LOGNAME")); if (getenv("USER")) { pstrcpy(cmdline_auth_info.username,getenv("USER")); if ((p = strchr_m(cmdline_auth_info.username,'%'))) { *p = 0; pstrcpy(cmdline_auth_info.password,p+1); cmdline_auth_info.got_pass = True; memset(strchr_m(getenv("USER"),'%')+1,'X',strlen(cmdline_auth_info.password)); } } if (getenv("PASSWD")) { pstrcpy(cmdline_auth_info.password,getenv("PASSWD")); cmdline_auth_info.got_pass = True; } if (getenv("PASSWD_FD") || getenv("PASSWD_FILE")) { get_password_file(&cmdline_auth_info); cmdline_auth_info.got_pass = True; } return; } switch(opt->val) { case 'U': { char *lp; pstrcpy(cmdline_auth_info.username,arg); if ((lp=strchr_m(cmdline_auth_info.username,'%'))) { *lp = 0; pstrcpy(cmdline_auth_info.password,lp+1); cmdline_auth_info.got_pass = True; memset(strchr_m(arg,'%')+1,'X',strlen(cmdline_auth_info.password)); } } break; case 'A': get_credentials_file(arg, &cmdline_auth_info); break; case 'k': #ifndef HAVE_KRB5 d_printf("No kerberos support compiled in\n"); exit(1); #else cmdline_auth_info.use_kerberos = True; cmdline_auth_info.got_pass = True; #endif break; case 'S': { cmdline_auth_info.signing_state = -1; if (strequal(arg, "off") || strequal(arg, "no") || strequal(arg, "false")) cmdline_auth_info.signing_state = False; else if (strequal(arg, "on") || strequal(arg, "yes") || strequal(arg, "true") || strequal(arg, "auto") ) cmdline_auth_info.signing_state = True; else if (strequal(arg, "force") || strequal(arg, "required") || strequal(arg, "forced")) cmdline_auth_info.signing_state = Required; else { fprintf(stderr, "Unknown signing option %s\n", arg ); exit(1); } } break; case 'P': { char *opt_password = NULL; /* it is very useful to be able to make ads queries as the machine account for testing purposes and for domain leave */ if (!secrets_init()) { d_printf("ERROR: Unable to open secrets database\n"); exit(1); } opt_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (!opt_password) { d_printf("ERROR: Unable to fetch machine password\n"); exit(1); } pstr_sprintf(cmdline_auth_info.username, "%s$", global_myname()); pstrcpy(cmdline_auth_info.password,opt_password); SAFE_FREE(opt_password); /* machine accounts only work with kerberos */ cmdline_auth_info.use_kerberos = True; cmdline_auth_info.got_pass = True; } break; } }
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 NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, const int sockfd, const int pipe_index, const char *controller, struct cli_state **cli, BOOL *retry) { char *machine_password, *machine_krb5_principal; char *ipc_username, *ipc_domain, *ipc_password; BOOL got_mutex; BOOL add_failed_connection = True; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; struct sockaddr peeraddr; socklen_t peeraddr_len; struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr; machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL); if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(), lp_realm()) == -1) { SAFE_FREE(machine_password); return NT_STATUS_NO_MEMORY; } cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password); *retry = True; got_mutex = secrets_named_mutex(controller, WINBIND_SERVER_MUTEX_WAIT_TIME); if (!got_mutex) { DEBUG(0,("cm_open_connection: mutex grab failed for %s\n", controller)); result = NT_STATUS_POSSIBLE_DEADLOCK; goto done; } if ((*cli = cli_initialise(NULL)) == NULL) { DEBUG(1, ("Could not cli_initialize\n")); result = NT_STATUS_NO_MEMORY; goto done; } (*cli)->timeout = 10000; /* 10 seconds */ (*cli)->fd = sockfd; fstrcpy((*cli)->desthost, controller); (*cli)->use_kerberos = True; peeraddr_len = sizeof(peeraddr); if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) || (peeraddr_len != sizeof(struct sockaddr_in)) || (peeraddr_in->sin_family != PF_INET)) { DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno))); goto done; } if (ntohs(peeraddr_in->sin_port) == 139) { struct nmb_name calling; struct nmb_name called; make_nmb_name(&calling, global_myname(), 0x0); make_nmb_name(&called, "*SMBSERVER", 0x20); if (!cli_session_request(*cli, &calling, &called)) { DEBUG(8, ("cli_session_request failed for %s\n", controller)); goto done; } } cli_setup_signing_state(*cli, Undefined); if (!cli_negprot(*cli)) { DEBUG(1, ("cli_negprot failed\n")); cli_shutdown(*cli); goto done; } /* Krb5 session */ if ((lp_security() == SEC_ADS) && ((*cli)->protocol >= PROTOCOL_NT1 && (*cli)->capabilities & CAP_EXTENDED_SECURITY)) { ADS_STATUS ads_status; (*cli)->use_kerberos = True; DEBUG(5, ("connecting to %s from %s with kerberos principal " "[%s]\n", controller, global_myname(), machine_krb5_principal)); ads_status = cli_session_setup_spnego(*cli, machine_krb5_principal, machine_password, lp_workgroup()); if (!ADS_ERR_OK(ads_status)) DEBUG(4,("failed kerberos session setup with %s\n", ads_errstr(ads_status))); result = ads_ntstatus(ads_status); } if (NT_STATUS_IS_OK(result)) goto session_setup_done; /* Fall back to non-kerberos session setup */ (*cli)->use_kerberos = False; if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) && (strlen(ipc_username) > 0)) { /* Only try authenticated if we have a username */ DEBUG(5, ("connecting to %s from %s with username " "[%s]\\[%s]\n", controller, global_myname(), ipc_domain, ipc_username)); if (cli_session_setup(*cli, ipc_username, ipc_password, strlen(ipc_password)+1, ipc_password, strlen(ipc_password)+1, ipc_domain)) { DEBUG(5, ("authenticated session setup failed\n")); goto session_setup_done; } } /* Fall back to anonymous connection, this might fail later */ if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) { DEBUG(5, ("Connected anonymously\n")); goto session_setup_done; } result = cli_nt_error(*cli); if (NT_STATUS_IS_OK(result)) result = NT_STATUS_UNSUCCESSFUL; /* We can't session setup */ goto done; session_setup_done: if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) { result = cli_nt_error(*cli); DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result))); if (NT_STATUS_IS_OK(result)) result = NT_STATUS_UNSUCCESSFUL; cli_shutdown(*cli); goto done; } secrets_named_mutex_release(controller); got_mutex = False; *retry = False; /* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel. Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call. So just drop it on the lsarpc pipe */ if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) { NTSTATUS status = setup_schannel( *cli, domain->name ); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("schannel refused - continuing without " "schannel (%s)\n", nt_errstr(status))); } } /* set the domain if empty; needed for schannel connections */ if ( !*(*cli)->domain ) fstrcpy( (*cli)->domain, domain->name ); if ( !cli_nt_session_open (*cli, pipe_index) ) { result = NT_STATUS_PIPE_NOT_AVAILABLE; /* This might be a NT4 DC */ if ( is_win2k_pipe(pipe_index) ) add_failed_connection = False; cli_shutdown(*cli); goto done; } result = NT_STATUS_OK; add_failed_connection = False; done: if (got_mutex) secrets_named_mutex_release(controller); SAFE_FREE(machine_password); SAFE_FREE(machine_krb5_principal); SAFE_FREE(ipc_username); SAFE_FREE(ipc_domain); SAFE_FREE(ipc_password); if (add_failed_connection) add_failed_connection_entry(domain->name, controller, result); return result; }