diff options
-rw-r--r-- | source4/auth/auth_sam.c | 363 | ||||
-rw-r--r-- | source4/libcli/auth/gensec_krb5.c | 80 | ||||
-rw-r--r-- | source4/libcli/auth/gensec_ntlmssp.c | 7 |
3 files changed, 302 insertions, 148 deletions
diff --git a/source4/auth/auth_sam.c b/source4/auth/auth_sam.c index 4e797acd36..bae13bd996 100644 --- a/source4/auth/auth_sam.c +++ b/source4/auth/auth_sam.c @@ -144,6 +144,7 @@ static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx, if(strequal(tok, user_info->wksta_name.str)) { invalid_ws = False; + break; } } @@ -171,38 +172,23 @@ static NTSTATUS sam_account_ok(TALLOC_CTX *mem_ctx, } /**************************************************************************** -check if a username/password is OK assuming the password is a 24 byte -SMB hash supplied in the user_info structure -return an NT_STATUS constant. + Look for the specified user in the sam, return ldb result structures ****************************************************************************/ -static NTSTATUS check_sam_security(const struct auth_context *auth_context, - void *my_private_data, - TALLOC_CTX *mem_ctx, - const struct auth_usersupplied_info *user_info, - struct auth_serversupplied_info **server_info) +static NTSTATUS sam_search_user(const char *username, const char *domain, + TALLOC_CTX *mem_ctx, void *sam_ctx, + struct ldb_message ***ret_msgs, + struct ldb_message ***ret_msgs_domain) { struct ldb_message **msgs; struct ldb_message **msgs_domain; - void *sam_ctx; - char *username = user_info->internal_username.str; - uint16_t acct_flags; - const char *workstation_list; - NTTIME acct_expiry; - NTTIME must_change_time; - NTTIME last_set_time; uint_t ret; uint_t ret_domain; - const char *domain_dn; + const char *domain_dn = NULL; const char *domain_sid; - NTSTATUS nt_status; - DATA_BLOB user_sess_key = data_blob(NULL, 0); - DATA_BLOB lm_sess_key = data_blob(NULL, 0); - struct samr_Password *lm_pwd, *nt_pwd; - const char *attrs[] = {"unicodePwd", "lmPwdHash", "ntPwdHash", "userAccountControl", "pwdLastSet", @@ -226,18 +212,31 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, NULL, }; - const char *domain_attrs[] = {"name"}; + const char *domain_attrs[] = {"name", "objectSid"}; + + if (domain) { + /* find the domain's DN */ + ret_domain = samdb_search(sam_ctx, mem_ctx, NULL, &msgs_domain, domain_attrs, + "(&(|(realm=%s)(name=%s))(objectclass=domain))", + domain, domain); + + if (ret_domain == 0) { + DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", + domain)); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret_domain > 1) { + DEBUG(0,("Found %d records matching domain [%s]\n", + ret_domain, domain)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + domain_dn = msgs_domain[0]->dn; - if (!user_info || !auth_context) { - return NT_STATUS_UNSUCCESSFUL; - } - - sam_ctx = samdb_connect(mem_ctx); - if (sam_ctx == NULL) { - return NT_STATUS_INVALID_SYSTEM_SERVICE; } /* pull the user attributes */ - ret = samdb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs, + ret = samdb_search(sam_ctx, mem_ctx, domain_dn, &msgs, attrs, "(&(sAMAccountName=%s)(objectclass=user))", username); @@ -252,30 +251,56 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, return NT_STATUS_INTERNAL_DB_CORRUPTION; } - domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid"); - if (!domain_sid) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } + if (!domain) { + domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid"); + if (!domain_sid) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } - /* find the domain's DN */ - ret_domain = samdb_search(sam_ctx, mem_ctx, NULL, &msgs_domain, domain_attrs, - "(&(objectSid=%s)(objectclass=domain))", - domain_sid); + /* find the domain's DN */ + ret_domain = samdb_search(sam_ctx, mem_ctx, NULL, &msgs_domain, domain_attrs, + "(&(objectSid=%s)(objectclass=domain))", + domain_sid); + + if (ret_domain == 0) { + DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", + domain_sid)); + return NT_STATUS_NO_SUCH_USER; + } + + if (ret_domain > 1) { + DEBUG(0,("Found %d records matching domain [%s]\n", + ret_domain, domain_sid)); + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } - if (ret_domain == 0) { - DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", - domain_sid)); - return NT_STATUS_NO_SUCH_USER; + domain_dn = msgs_domain[0]->dn; } + *ret_msgs = msgs; + *ret_msgs_domain = msgs_domain; + + return NT_STATUS_OK; +} + +NTSTATUS sam_check_password(const struct auth_context *auth_context, + const char *username, + TALLOC_CTX *mem_ctx, void *sam_ctx, + struct ldb_message **msgs, + const char *domain_dn, + const struct auth_usersupplied_info *user_info, + DATA_BLOB *user_sess_key, DATA_BLOB *lm_sess_key) +{ + + uint16_t acct_flags; + const char *workstation_list; + NTTIME acct_expiry; + NTTIME must_change_time; + NTTIME last_set_time; + struct samr_Password *lm_pwd, *nt_pwd; + + NTSTATUS nt_status; - if (ret_domain > 1) { - DEBUG(0,("Found %d records matching domain [%s]\n", - ret_domain, domain_sid)); - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - domain_dn = msgs_domain[0]->dn; - acct_flags = samdb_result_acct_flags(msgs[0], "sAMAcctFlags"); /* Quit if the account was locked out. */ @@ -293,7 +318,7 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, nt_status = sam_password_ok(auth_context, mem_ctx, username, acct_flags, lm_pwd, nt_pwd, - user_info, &user_sess_key, &lm_sess_key); + user_info, user_sess_key, lm_sess_key); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; @@ -314,68 +339,72 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, workstation_list, user_info); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } + return nt_status; +} + +NTSTATUS sam_make_server_info(TALLOC_CTX *mem_ctx, void *sam_ctx, + struct ldb_message **msgs, struct ldb_message **msgs_domain, + struct auth_serversupplied_info **server_info) +{ + + struct ldb_message **group_msgs; + int group_ret; + const char *group_attrs[3] = { "sAMAccountType", "objectSid", NULL }; + /* find list of sids */ + struct dom_sid **groupSIDs = NULL; + struct dom_sid *user_sid; + struct dom_sid *primary_group_sid; + const char *sidstr; + int i; + uint_t rid; + + NTSTATUS nt_status; - if (!NT_STATUS_IS_OK(nt_status = make_server_info(auth_context, server_info, username))) { + if (!NT_STATUS_IS_OK(nt_status = make_server_info(mem_ctx, server_info, + samdb_result_string(msgs[0], "sAMAccountName", "")))) { DEBUG(0,("check_sam_security: make_server_info_sam() failed with '%s'\n", nt_errstr(nt_status))); return nt_status; } - - { - struct ldb_message **group_msgs; - char *dn = msgs[0]->dn; - int group_ret; - const char *group_attrs[3] = { "sAMAccountType", "objectSid", NULL }; - /* find list of sids */ - struct dom_sid **groupSIDs = NULL; - struct dom_sid *user_sid; - struct dom_sid *primary_group_sid; - const char *sidstr; - int i; - uint_t rid; - - group_ret = samdb_search(sam_ctx, - mem_ctx, NULL, &group_msgs, group_attrs, - "(&(member=%s)(sAMAccountType=*))", - dn); - if (group_ret == -1) { - return NT_STATUS_INTERNAL_DB_CORRUPTION; - } - - if (group_ret > 0 && - !(groupSIDs = talloc_array_p(*server_info, struct dom_sid *, group_ret))) { - talloc_free(*server_info); - return NT_STATUS_NO_MEMORY; - } - - /* Need to unroll some nested groups, but not aliases */ - for (i = 0; i < group_ret; i++) { - sidstr = ldb_msg_find_string(group_msgs[i], "objectSid", NULL); - groupSIDs[i] = dom_sid_parse_talloc(*server_info, sidstr); - } - - sidstr = ldb_msg_find_string(msgs[0], "objectSid", NULL); - user_sid = dom_sid_parse_talloc(*server_info, sidstr); - primary_group_sid = dom_sid_parse_talloc(*server_info, sidstr); - rid = samdb_result_uint(msgs[0], "primaryGroupID", ~0); - if (rid == ~0) { - if (group_ret > 0) { - primary_group_sid = groupSIDs[0]; - } else { - primary_group_sid = NULL; - } + + group_ret = samdb_search(sam_ctx, + mem_ctx, NULL, &group_msgs, group_attrs, + "(&(member=%s)(sAMAccountType=*))", + msgs[0]->dn); + if (group_ret == -1) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + if (group_ret > 0 && + !(groupSIDs = talloc_array_p(*server_info, struct dom_sid *, group_ret))) { + talloc_free(*server_info); + return NT_STATUS_NO_MEMORY; + } + + /* Need to unroll some nested groups, but not aliases */ + for (i = 0; i < group_ret; i++) { + sidstr = ldb_msg_find_string(group_msgs[i], "objectSid", NULL); + groupSIDs[i] = dom_sid_parse_talloc(*server_info, sidstr); + } + + sidstr = ldb_msg_find_string(msgs[0], "objectSid", NULL); + user_sid = dom_sid_parse_talloc(*server_info, sidstr); + primary_group_sid = dom_sid_parse_talloc(*server_info, sidstr); + rid = samdb_result_uint(msgs[0], "primaryGroupID", ~0); + if (rid == ~0) { + if (group_ret > 0) { + primary_group_sid = groupSIDs[0]; } else { - primary_group_sid->sub_auths[primary_group_sid->num_auths-1] = rid; + primary_group_sid = NULL; } - - (*server_info)->user_sid = user_sid; - (*server_info)->primary_group_sid = primary_group_sid; - - (*server_info)->n_domain_groups = group_ret; - (*server_info)->domain_groups = groupSIDs; + } else { + primary_group_sid->sub_auths[primary_group_sid->num_auths-1] = rid; } + + (*server_info)->user_sid = user_sid; + (*server_info)->primary_group_sid = primary_group_sid; + + (*server_info)->n_domain_groups = group_ret; + (*server_info)->domain_groups = groupSIDs; (*server_info)->account_name = talloc_strdup(*server_info, @@ -409,10 +438,10 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, (*server_info)->last_password_change = samdb_result_nttime(msgs[0], "pwdLastSet", 0); (*server_info)->allow_password_change = samdb_result_allow_password_change(sam_ctx, mem_ctx, - domain_dn, msgs[0], "pwdLastSet"); + msgs_domain[0]->dn, msgs[0], "pwdLastSet"); (*server_info)->force_password_change = samdb_result_force_password_change(sam_ctx, mem_ctx, - domain_dn, msgs[0], "pwdLastSet"); + msgs_domain[0]->dn, msgs[0], "pwdLastSet"); (*server_info)->logon_count = samdb_result_uint(msgs[0], "logonCount", 0); (*server_info)->bad_password_count = samdb_result_uint(msgs[0], "badPwdCount", 0); @@ -421,9 +450,6 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, (*server_info)->guest = False; - (*server_info)->user_session_key = user_sess_key; - (*server_info)->lm_session_key = lm_sess_key; - if (!(*server_info)->account_name || !(*server_info)->full_name || !(*server_info)->logon_script @@ -437,6 +463,85 @@ static NTSTATUS check_sam_security(const struct auth_context *auth_context, return nt_status; } +NTSTATUS sam_get_server_info(const char *username, const char *domain, TALLOC_CTX *mem_ctx, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status; + + struct ldb_message **msgs; + struct ldb_message **domain_msgs; + void *sam_ctx; + + sam_ctx = samdb_connect(mem_ctx); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + nt_status = sam_search_user(username, domain, mem_ctx, sam_ctx, &msgs, &domain_msgs); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + nt_status = sam_make_server_info(mem_ctx, sam_ctx, msgs, domain_msgs, server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + return NT_STATUS_OK; +} + +static NTSTATUS check_sam_security_internals(const struct auth_context *auth_context, + const char *domain, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + NTSTATUS nt_status; + + const char *username = user_info->internal_username.str; + struct ldb_message **msgs; + struct ldb_message **domain_msgs; + void *sam_ctx; + DATA_BLOB user_sess_key, lm_sess_key; + + sam_ctx = samdb_connect(mem_ctx); + if (sam_ctx == NULL) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + nt_status = sam_search_user(username, domain, mem_ctx, sam_ctx, &msgs, &domain_msgs); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + nt_status = sam_check_password(auth_context, username, mem_ctx, sam_ctx, msgs, domain_msgs[0]->dn, user_info, + &user_sess_key, &lm_sess_key); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + nt_status = sam_make_server_info(mem_ctx, sam_ctx, msgs, domain_msgs, server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + talloc_reference(auth_context, *server_info); + + (*server_info)->user_session_key = user_sess_key; + (*server_info)->lm_session_key = lm_sess_key; + return NT_STATUS_OK; +} + +static NTSTATUS check_sam_security(const struct auth_context *auth_context, + void *my_private_data, + TALLOC_CTX *mem_ctx, + const struct auth_usersupplied_info *user_info, + struct auth_serversupplied_info **server_info) +{ + return check_sam_security_internals(auth_context, NULL, + mem_ctx, user_info, server_info); +} + /* module initialisation */ static NTSTATUS auth_init_sam_ignoredomain(struct auth_context *auth_context, const char *param, @@ -462,22 +567,44 @@ static NTSTATUS check_samstrict_security(const struct auth_context *auth_context const struct auth_usersupplied_info *user_info, struct auth_serversupplied_info **server_info) { + const char *domain; + BOOL is_local_name, is_my_domain; if (!user_info || !auth_context) { return NT_STATUS_LOGON_FAILURE; } - /* If we are a domain member, we must not - attempt to check the password locally, - unless it is one of our aliases. */ + is_local_name = is_myname(user_info->domain.str); + is_my_domain = strequal(user_info->domain.str, lp_workgroup()); + + /* check whether or not we service this domain/workgroup name */ - if (!is_myname(user_info->domain.str)) { - DEBUG(7,("The requested user domain is not the local server name. [%s]\\[%s]\n", - user_info->domain.str,user_info->internal_username.str)); - return NT_STATUS_NO_SUCH_USER; + switch ( lp_server_role() ) { + case ROLE_STANDALONE: + case ROLE_DOMAIN_MEMBER: + if ( !is_local_name ) { + DEBUG(6,("check_samstrict_security: %s is not one of my local names (%s)\n", + user_info->domain.str, (lp_server_role() == ROLE_DOMAIN_MEMBER + ? "ROLE_DOMAIN_MEMBER" : "ROLE_STANDALONE") )); + return NT_STATUS_NOT_IMPLEMENTED; + } + domain = lp_netbios_name(); + break; + case ROLE_DOMAIN_PDC: + case ROLE_DOMAIN_BDC: + if ( !is_local_name && !is_my_domain ) { + DEBUG(6,("check_samstrict_security: %s is not one of my local names or domain name (DC)\n", + user_info->domain.str)); + return NT_STATUS_NOT_IMPLEMENTED; + } + domain = lp_workgroup(); + break; + default: /* name is ok */ + domain = user_info->domain.str; + break; } - return check_sam_security(auth_context, my_private_data, mem_ctx, user_info, server_info); + return check_sam_security_internals(auth_context, domain, mem_ctx, user_info, server_info); } /* module initialisation */ diff --git a/source4/libcli/auth/gensec_krb5.c b/source4/libcli/auth/gensec_krb5.c index 14e2f586c3..1ce05b519e 100644 --- a/source4/libcli/auth/gensec_krb5.c +++ b/source4/libcli/auth/gensec_krb5.c @@ -611,39 +611,48 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security struct dom_sid *sid; char *p; char *principal; + const char *username; + const char *realm; *session_info_out = NULL; - nt_status = make_server_info(gensec_security, &server_info, gensec_krb5_state->peer_principal); - if (!NT_STATUS_IS_OK(nt_status)) { - return nt_status; - } - - server_info->guest = False; + /* IF we have the PAC - otherwise (TODO) we need to get this + * data from elsewere - local ldb, or lookup of some + * kind... */ - principal = talloc_strdup(server_info, gensec_krb5_state->peer_principal); + principal = talloc_strdup(gensec_krb5_state, gensec_krb5_state->peer_principal); p = strchr(principal, '@'); if (p) { *p = '\0'; } - server_info->account_name = principal; - server_info->domain = talloc_strdup(server_info, p++); - if (!server_info->domain) { - free_server_info(&server_info); - return NT_STATUS_NO_MEMORY; - } - - nt_status = make_session_info(server_info, &session_info); - if (!NT_STATUS_IS_OK(nt_status)) { - free_server_info(&server_info); - return nt_status; - } + p++; + username = principal; + realm = p; + + if (logon_info) { + nt_status = make_server_info(gensec_krb5_state, &server_info, gensec_krb5_state->peer_principal); + if (!NT_STATUS_IS_OK(nt_status)) { + return nt_status; + } + + server_info->guest = False; + + server_info->account_name = talloc_strdup(server_info, principal); + server_info->domain = talloc_strdup(server_info, realm); + if (!server_info->domain) { + free_server_info(&server_info); + return NT_STATUS_NO_MEMORY; + } + + /* references the server_info into the session_info */ + nt_status = make_session_info(gensec_krb5_state, server_info, &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + free_server_info(&server_info); + return nt_status; + } - /* IF we have the PAC - otherwise (TODO) we need to get this - * data from elsewere - local ldb, or lookup of some - * kind... */ + talloc_free(server_info); - if (logon_info) { ptoken = talloc_p(session_info, struct nt_user_token); if (!ptoken) { return NT_STATUS_NO_MEMORY; @@ -666,16 +675,37 @@ static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security for (;ptoken->num_sids < logon_info->groups_count; ptoken->num_sids++) { sid = dom_sid_dup(session_info, logon_info->dom_sid); - ptoken->user_sids[ptoken->num_sids] = dom_sid_add_rid(session_info, sid, logon_info->groups[ptoken->num_sids - 2].rid); + ptoken->user_sids[ptoken->num_sids] + = dom_sid_add_rid(session_info, sid, + logon_info->groups[ptoken->num_sids - 2].rid); } debug_nt_user_token(DBGC_AUTH, 0, ptoken); session_info->nt_user_token = ptoken; } else { - session_info->nt_user_token = NULL; + TALLOC_CTX *mem_ctx = talloc_named(gensec_krb5_state, 0, "PAC-less session info discovery for %s@%s", username, realm); + if (!mem_ctx) { + return NT_STATUS_NO_MEMORY; + } + nt_status = sam_get_server_info(username, realm, gensec_krb5_state, &server_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(mem_ctx); + return nt_status; + } + + /* references the server_info into the session_info */ + nt_status = make_session_info(gensec_krb5_state, server_info, &session_info); + if (!NT_STATUS_IS_OK(nt_status)) { + talloc_free(mem_ctx); + return nt_status; + } + + talloc_free(mem_ctx); } + talloc_free(principal); + nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key); session_info->workstation = NULL; diff --git a/source4/libcli/auth/gensec_ntlmssp.c b/source4/libcli/auth/gensec_ntlmssp.c index 0683581495..48438aaae1 100644 --- a/source4/libcli/auth/gensec_ntlmssp.c +++ b/source4/libcli/auth/gensec_ntlmssp.c @@ -370,19 +370,16 @@ static NTSTATUS gensec_ntlmssp_update(struct gensec_security *gensec_security, T */ static NTSTATUS gensec_ntlmssp_session_info(struct gensec_security *gensec_security, - struct auth_session_info **session_info) + struct auth_session_info **session_info) { NTSTATUS nt_status; struct gensec_ntlmssp_state *gensec_ntlmssp_state = gensec_security->private_data; - nt_status = make_session_info(gensec_ntlmssp_state->server_info, session_info); + nt_status = make_session_info(gensec_ntlmssp_state, gensec_ntlmssp_state->server_info, session_info); if (!NT_STATUS_IS_OK(nt_status)) { return nt_status; } - /* the session_info owns this now */ - gensec_ntlmssp_state->server_info = NULL; - (*session_info)->session_key = data_blob_talloc(*session_info, gensec_ntlmssp_state->ntlmssp_state->session_key.data, gensec_ntlmssp_state->ntlmssp_state->session_key.length); |