struct winbindd_cli_state *state,
struct winbind_auth *r)
{
- r->out.result = WINBIND_STATUS_NOT_IMPLEMENTED;
+ NTSTATUS result = NT_STATUS_LOGON_FAILURE;
+ NTSTATUS krb5_result = NT_STATUS_OK;
+ fstring name_domain, name_user;
+ fstring full_account_name;
+ struct netr_SamInfo3 *info3 = NULL;
+ struct winbind_auth_compat_auth_plain_req *in;
+
+ in = &r->in.req.compat_auth_plain;
+
+ DEBUG(3, ("comapt auth plain account[%s] domain[%s]\n",
+ in->account_name,
+ in->domain_name?in->domain_name:"(NULL)"));
+
+ /* Parse domain and username */
+
+// ws_name_return( state->request.data.auth.user, WB_REPLACE_CHAR );
+
+// parse_domain_user(state->request.data.auth.user, name_domain, name_user);
+
+ if (domain->online == False) {
+ result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+ if (domain->startup) {
+ /* Logons are very important to users. If we're offline and
+ we get a request within the first 30 seconds of startup,
+ try very hard to find a DC and go online. */
+
+ DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
+ "request in startup mode.\n", domain->name ));
+
+ winbindd_flush_negative_conn_cache(domain);
+ result = init_dc_connection(domain);
+ }
+ }
+
+ DEBUG(10,("compat_auth_plain: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
+
+ /* Check for Kerberos authentication */
+ if (domain->online && (in->flags & WBFLAG_PAM_KRB5)) {
+
+ result = winbindd_dual_pam_auth_kerberos(domain, state, &info3);
+ /* save for later */
+ krb5_result = result;
+
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
+ goto process_result;
+ } else {
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos failed: %s\n", nt_errstr(result)));
+ }
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
+ DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
+ set_domain_offline( domain );
+ goto cached_logon;
+ }
+
+ /* there are quite some NT_STATUS errors where there is no
+ * point in retrying with a samlogon, we explictly have to take
+ * care not to increase the bad logon counter on the DC */
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
+ goto process_result;
+ }
+
+ if (in->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
+ DEBUG(3,("falling back to samlogon\n"));
+ goto sam_logon;
+ } else {
+ goto cached_logon;
+ }
+ }
+
+sam_logon:
+ /* Check for Samlogon authentication */
+ if (domain->online) {
+ result = winbindd_dual_pam_auth_samlogon(domain, state, &info3);
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
+ /* add the Krb5 err if we have one */
+ if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
+ info3->base.user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
+ }
+ goto process_result;
+ }
+
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
+ nt_errstr(result)));
+
+ if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
+ NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
+ {
+ DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
+ set_domain_offline( domain );
+ goto cached_logon;
+ }
+
+ if (domain->online) {
+ /* We're still online - fail. */
+ goto done;
+ }
+ }
+
+cached_logon:
+ /* Check for Cached logons */
+ if (!domain->online && (in->flags & WBFLAG_PAM_CACHED_LOGIN) &&
+ lp_winbind_offline_logon()) {
+
+ result = winbindd_dual_pam_auth_cached(domain, state, &info3);
+
+ if (NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
+ goto process_result;
+ } else {
+ DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
+ goto done;
+ }
+ }
+
+process_result:
+
+ if (NT_STATUS_IS_OK(result)) {
+
+ DOM_SID user_sid;
+
+ /* In all codepaths where result == NT_STATUS_OK info3 must have
+ been initialized. */
+ if (!info3) {
+ result = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+
+ netsamlogon_cache_store(name_user, info3);
+ wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
+
+ /* save name_to_sid info as early as possible (only if
+ this is our primary domain so we don't invalidate
+ the cache entry by storing the seq_num for the wrong
+ domain). */
+ if ( domain->primary ) {
+ sid_compose(&user_sid, info3->base.domain_sid,
+ info3->base.rid);
+ cache_name2sid(domain, name_domain, name_user,
+ SID_NAME_USER, &user_sid);
+ }
+
+ /* Check if the user is in the right group */
+
+ result = check_info3_in_groups(state->mem_ctx, info3,
+ in->num_require_membership_of_sids,
+ in->require_membership_of_sids);
+ if (!NT_STATUS_IS_OK(result)) {
+// DEBUG(3, ("User %s is not in the required group (%s), so plaintext authentication is rejected\n",
+// state->request.data.auth.user,
+// state->request.data.auth.require_membership_of_sid));
+ goto done;
+ }
+
+ result = append_data(state, info3, name_domain, name_user);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto done;
+ }
+
+ if ((in->flags & WBFLAG_PAM_CACHED_LOGIN)) {
+
+ /* Store in-memory creds for single-signon using ntlm_auth. */
+ result = winbindd_add_memory_creds(full_account_name,
+ get_uid_from_state(state),
+ in->password);
+
+ if (!NT_STATUS_IS_OK(result)) {
+ DEBUG(10,("Failed to store memory creds: %s\n", nt_errstr(result)));
+ goto done;
+ }
+
+ if (lp_winbind_offline_logon()) {
+ result = winbindd_store_creds(domain,
+ state->mem_ctx,
+ full_account_name,
+ in->password,
+ info3, NULL);
+ if (!NT_STATUS_IS_OK(result)) {
+
+ /* Release refcount. */
+ winbindd_delete_memory_creds(full_account_name);
+
+ DEBUG(10,("Failed to store creds: %s\n", nt_errstr(result)));
+ goto done;
+ }
+ }
+ }
+
+
+ if (state->request.flags & WBFLAG_PAM_GET_PWD_POLICY) {
+ result = fillup_password_policy(domain, state);
+
+ if (!NT_STATUS_IS_OK(result)
+ && !NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) )
+ {
+ DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(result)));
+ goto done;
+ }
+ }
+
+ result = NT_STATUS_OK;
+ }
+
+done:
+ /* give us a more useful (more correct?) error code */
+ if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
+ (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
+ result = NT_STATUS_NO_LOGON_SERVERS;
+ }
+
+ state->response.data.auth.nt_status = NT_STATUS_V(result);
+ fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
+
+ /* we might have given a more useful error above */
+ if (!*state->response.data.auth.error_string)
+ fstrcpy(state->response.data.auth.error_string, get_friendly_nt_error_msg(result));
+ state->response.data.auth.pam_error = nt_status_to_pam(result);
+
+ DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authentication for user %s returned %s (PAM: %d)\n",
+ state->request.data.auth.user,
+ state->response.data.auth.nt_status_string,
+ state->response.data.auth.pam_error));
+
+ if (!NT_STATUS_IS_OK(result)) {
+ r->out.result = WINBIND_STATUS_FOOBAR;
+ return;
+ }
+
+ r->out.result = WINBIND_STATUS_OK;
}