LCOV - code coverage report
Current view: top level - source3/winbindd - winbindd_pam.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 250 1585 15.8 %
Date: 2024-04-21 15:09:00 Functions: 8 30 26.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Winbind daemon - pam auth functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2000
       7             :    Copyright (C) Tim Potter 2001
       8             :    Copyright (C) Andrew Bartlett 2001-2002
       9             :    Copyright (C) Guenther Deschner 2005
      10             : 
      11             :    This program is free software; you can redistribute it and/or modify
      12             :    it under the terms of the GNU General Public License as published by
      13             :    the Free Software Foundation; either version 3 of the License, or
      14             :    (at your option) any later version.
      15             : 
      16             :    This program is distributed in the hope that it will be useful,
      17             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :    GNU General Public License for more details.
      20             : 
      21             :    You should have received a copy of the GNU General Public License
      22             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include "includes.h"
      26             : #include "ntdomain.h"
      27             : #include "winbindd.h"
      28             : #include "libsmb/namequery.h"
      29             : #include "../libcli/auth/libcli_auth.h"
      30             : #include "libcli/auth/pam_errors.h"
      31             : #include "../librpc/gen_ndr/ndr_samr_c.h"
      32             : #include "librpc/rpc/dcesrv_core.h"
      33             : #include "librpc/gen_ndr/ndr_winbind.h"
      34             : #include "rpc_client/cli_pipe.h"
      35             : #include "rpc_client/cli_samr.h"
      36             : #include "../librpc/gen_ndr/ndr_netlogon.h"
      37             : #include "rpc_client/cli_netlogon.h"
      38             : #include "smb_krb5.h"
      39             : #include "../libcli/security/security.h"
      40             : #include "ads.h"
      41             : #include "../librpc/gen_ndr/krb5pac.h"
      42             : #include "passdb/machine_sid.h"
      43             : #include "auth.h"
      44             : #include "../lib/tsocket/tsocket.h"
      45             : #include "auth/kerberos/pac_utils.h"
      46             : #include "auth/gensec/gensec.h"
      47             : #include "librpc/crypto/gse_krb5.h"
      48             : #include "lib/afs/afs_funcs.h"
      49             : #include "libsmb/samlogon_cache.h"
      50             : #include "rpc_client/util_netlogon.h"
      51             : #include "param/param.h"
      52             : #include "messaging/messaging.h"
      53             : #include "lib/util/string_wrappers.h"
      54             : #include "lib/crypto/gnutls_helpers.h"
      55             : 
      56             : #include "lib/crypto/gnutls_helpers.h"
      57             : #include <gnutls/crypto.h>
      58             : #include "lib/global_contexts.h"
      59             : 
      60             : #undef DBGC_CLASS
      61             : #define DBGC_CLASS DBGC_WINBIND
      62             : 
      63             : #define LOGON_KRB5_FAIL_CLOCK_SKEW      0x02000000
      64             : 
      65        1422 : static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
      66             :                                     struct winbindd_response *resp,
      67             :                                     uint16_t validation_level,
      68             :                                     union netr_Validation *validation)
      69             : {
      70        1422 :         struct netr_SamInfo3 *info3 = NULL;
      71        1422 :         char *ex = NULL;
      72           0 :         uint32_t i;
      73        1422 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
      74        1422 :         TALLOC_CTX *frame = talloc_stackframe();
      75             : 
      76        1422 :         status = map_validation_to_info3(frame,
      77             :                                          validation_level,
      78             :                                          validation,
      79             :                                          &info3);
      80        1422 :         if (!NT_STATUS_IS_OK(status)) {
      81           0 :                 goto out;
      82             :         }
      83             : 
      84        1422 :         resp->data.auth.info3.logon_time =
      85        1422 :                 nt_time_to_unix(info3->base.logon_time);
      86        1422 :         resp->data.auth.info3.logoff_time =
      87        1422 :                 nt_time_to_unix(info3->base.logoff_time);
      88        1422 :         resp->data.auth.info3.kickoff_time =
      89        1422 :                 nt_time_to_unix(info3->base.kickoff_time);
      90        1422 :         resp->data.auth.info3.pass_last_set_time =
      91        1422 :                 nt_time_to_unix(info3->base.last_password_change);
      92        1422 :         resp->data.auth.info3.pass_can_change_time =
      93        1422 :                 nt_time_to_unix(info3->base.allow_password_change);
      94        1422 :         resp->data.auth.info3.pass_must_change_time =
      95        1422 :                 nt_time_to_unix(info3->base.force_password_change);
      96             : 
      97        1422 :         resp->data.auth.info3.logon_count = info3->base.logon_count;
      98        1422 :         resp->data.auth.info3.bad_pw_count = info3->base.bad_password_count;
      99             : 
     100        1422 :         resp->data.auth.info3.user_rid = info3->base.rid;
     101        1422 :         resp->data.auth.info3.group_rid = info3->base.primary_gid;
     102        1422 :         sid_to_fstring(resp->data.auth.info3.dom_sid, info3->base.domain_sid);
     103             : 
     104        1422 :         resp->data.auth.info3.num_groups = info3->base.groups.count;
     105        1422 :         resp->data.auth.info3.user_flgs = info3->base.user_flags;
     106             : 
     107        1422 :         resp->data.auth.info3.acct_flags = info3->base.acct_flags;
     108        1422 :         resp->data.auth.info3.num_other_sids = info3->sidcount;
     109             : 
     110        1422 :         fstrcpy(resp->data.auth.info3.user_name,
     111             :                 info3->base.account_name.string);
     112        1422 :         fstrcpy(resp->data.auth.info3.full_name,
     113             :                 info3->base.full_name.string);
     114        1422 :         fstrcpy(resp->data.auth.info3.logon_script,
     115             :                 info3->base.logon_script.string);
     116        1422 :         fstrcpy(resp->data.auth.info3.profile_path,
     117             :                 info3->base.profile_path.string);
     118        1422 :         fstrcpy(resp->data.auth.info3.home_dir,
     119             :                 info3->base.home_directory.string);
     120        1422 :         fstrcpy(resp->data.auth.info3.dir_drive,
     121             :                 info3->base.home_drive.string);
     122             : 
     123        1422 :         fstrcpy(resp->data.auth.info3.logon_srv,
     124             :                 info3->base.logon_server.string);
     125        1422 :         fstrcpy(resp->data.auth.info3.logon_dom,
     126             :                 info3->base.logon_domain.string);
     127             : 
     128        1422 :         resp->data.auth.validation_level = validation_level;
     129        1422 :         if (validation_level == 6) {
     130        1276 :                 fstrcpy(resp->data.auth.info6.dns_domainname,
     131             :                         validation->sam6->dns_domainname.string);
     132        1276 :                 fstrcpy(resp->data.auth.info6.principal_name,
     133             :                         validation->sam6->principal_name.string);
     134             :         }
     135             : 
     136        1422 :         ex = talloc_strdup(frame, "");
     137        1422 :         if (ex == NULL) {
     138           0 :                 status = NT_STATUS_NO_MEMORY;
     139           0 :                 goto out;
     140             :         }
     141             : 
     142        7470 :         for (i=0; i < info3->base.groups.count; i++) {
     143       12096 :                 ex = talloc_asprintf_append_buffer(ex, "0x%08X:0x%08X\n",
     144        6048 :                                                    info3->base.groups.rids[i].rid,
     145        6048 :                                                    info3->base.groups.rids[i].attributes);
     146        6048 :                 if (ex == NULL) {
     147           0 :                         status = NT_STATUS_NO_MEMORY;
     148           0 :                         goto out;
     149             :                 }
     150             :         }
     151             : 
     152        4018 :         for (i=0; i < info3->sidcount; i++) {
     153           0 :                 struct dom_sid_buf sidbuf;
     154             : 
     155        2596 :                 ex = talloc_asprintf_append_buffer(
     156             :                         ex,
     157             :                         "%s:0x%08X\n",
     158        2596 :                         dom_sid_str_buf(info3->sids[i].sid, &sidbuf),
     159        2596 :                         info3->sids[i].attributes);
     160        2596 :                 if (ex == NULL) {
     161           0 :                         status = NT_STATUS_NO_MEMORY;
     162           0 :                         goto out;
     163             :                 }
     164             :         }
     165             : 
     166        1422 :         resp->length += talloc_get_size(ex);
     167        1422 :         resp->extra_data.data = talloc_move(mem_ctx, &ex);
     168             : 
     169        1422 :         status = NT_STATUS_OK;
     170        1422 : out:
     171        1422 :         TALLOC_FREE(frame);
     172        1422 :         return status;
     173             : }
     174             : 
     175           0 : static NTSTATUS append_info3_as_ndr(TALLOC_CTX *mem_ctx,
     176             :                                     struct winbindd_response *resp,
     177             :                                     struct netr_SamInfo3 *info3)
     178             : {
     179           0 :         DATA_BLOB blob;
     180           0 :         enum ndr_err_code ndr_err;
     181             : 
     182           0 :         ndr_err = ndr_push_struct_blob(&blob, mem_ctx, info3,
     183             :                                        (ndr_push_flags_fn_t)ndr_push_netr_SamInfo3);
     184           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     185           0 :                 DEBUG(0,("append_info3_as_ndr: failed to append\n"));
     186           0 :                 return ndr_map_error2ntstatus(ndr_err);
     187             :         }
     188             : 
     189           0 :         resp->extra_data.data = blob.data;
     190           0 :         resp->length += blob.length;
     191             : 
     192           0 :         return NT_STATUS_OK;
     193             : }
     194             : 
     195         192 : static NTSTATUS append_unix_username(uint16_t validation_level,
     196             :                                      union netr_Validation  *validation,
     197             :                                      const char *name_domain,
     198             :                                      const char *name_user,
     199             :                                      TALLOC_CTX *mem_ctx,
     200             :                                      char **_unix_username)
     201             : {
     202         192 :         TALLOC_CTX *tmp_ctx = NULL;
     203         192 :         const char *nt_username = NULL;
     204         192 :         const char *nt_domain = NULL;
     205         192 :         char *unix_username = NULL;
     206         192 :         struct netr_SamBaseInfo *base_info = NULL;
     207           0 :         NTSTATUS status;
     208             : 
     209         192 :         tmp_ctx = talloc_new(mem_ctx);
     210         192 :         if (tmp_ctx == NULL) {
     211           0 :                 return NT_STATUS_NO_MEMORY;
     212             :         }
     213             : 
     214             :         /* We've been asked to return the unix username, per
     215             :            'winbind use default domain' settings and the like */
     216             : 
     217         192 :         switch (validation_level) {
     218          30 :         case 3:
     219          30 :                 base_info = &validation->sam3->base;
     220          30 :                 break;
     221         162 :         case 6:
     222         162 :                 base_info = &validation->sam6->base;
     223         162 :                 break;
     224           0 :         default:
     225           0 :                 DBG_ERR("Invalid validation level %d\n", validation_level);
     226           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     227           0 :                 goto out;
     228             :         }
     229             : 
     230         192 :         nt_domain = talloc_strdup(tmp_ctx, base_info->logon_domain.string);
     231         192 :         if (!nt_domain) {
     232             :                 /* If the server didn't give us one, just use the one
     233             :                  * we sent them */
     234           0 :                 nt_domain = name_domain;
     235             :         }
     236             : 
     237         192 :         nt_username = talloc_strdup(tmp_ctx, base_info->account_name.string);
     238         192 :         if (!nt_username) {
     239             :                 /* If the server didn't give us one, just use the one
     240             :                  * we sent them */
     241           0 :                 nt_username = name_user;
     242             :         }
     243             : 
     244         192 :         unix_username = fill_domain_username_talloc(tmp_ctx,
     245             :                                                     nt_domain,
     246             :                                                     nt_username,
     247             :                                                     true);
     248         192 :         if (unix_username == NULL) {
     249           0 :                 status = NT_STATUS_NO_MEMORY;
     250           0 :                 goto out;
     251             :         }
     252             : 
     253         192 :         DBG_INFO("Setting unix username to [%s]\n", unix_username);
     254             : 
     255         192 :         *_unix_username = talloc_move(mem_ctx, &unix_username);
     256             : 
     257         192 :         status = NT_STATUS_OK;
     258         192 : out:
     259         192 :         TALLOC_FREE(tmp_ctx);
     260             : 
     261         192 :         return status;
     262             : }
     263             : 
     264           0 : static NTSTATUS append_afs_token(uint16_t validation_level,
     265             :                                  union netr_Validation  *validation,
     266             :                                  const char *name_domain,
     267             :                                  const char *name_user,
     268             :                                  TALLOC_CTX *mem_ctx,
     269             :                                  DATA_BLOB *_blob)
     270             : {
     271           0 :         TALLOC_CTX *tmp_ctx = NULL;
     272           0 :         char *afsname = NULL;
     273           0 :         char *cell;
     274           0 :         char *token;
     275           0 :         struct netr_SamBaseInfo *base_info = NULL;
     276           0 :         NTSTATUS status;
     277             : 
     278           0 :         tmp_ctx = talloc_new(mem_ctx);
     279           0 :         if (tmp_ctx == NULL) {
     280           0 :                 return NT_STATUS_NO_MEMORY;
     281             :         }
     282             : 
     283           0 :         switch (validation_level) {
     284           0 :         case 3:
     285           0 :                 base_info = &validation->sam3->base;
     286           0 :                 break;
     287           0 :         case 6:
     288           0 :                 base_info = &validation->sam6->base;
     289           0 :                 break;
     290           0 :         default:
     291           0 :                 DBG_ERR("Invalid validation level %d\n", validation_level);
     292           0 :                 status = NT_STATUS_INTERNAL_ERROR;
     293           0 :                 goto out;
     294             :         }
     295             : 
     296           0 :         afsname = talloc_strdup(tmp_ctx, lp_afs_username_map());
     297           0 :         if (afsname == NULL) {
     298           0 :                 status = NT_STATUS_NO_MEMORY;
     299           0 :                 goto out;
     300             :         }
     301             : 
     302           0 :         afsname = talloc_string_sub(tmp_ctx,
     303             :                                     lp_afs_username_map(),
     304             :                                     "%D", name_domain);
     305           0 :         afsname = talloc_string_sub(tmp_ctx, afsname,
     306             :                                     "%u", name_user);
     307           0 :         afsname = talloc_string_sub(tmp_ctx, afsname,
     308             :                                     "%U", name_user);
     309             : 
     310             :         {
     311           0 :                 struct dom_sid user_sid;
     312           0 :                 struct dom_sid_buf sidstr;
     313             : 
     314           0 :                 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
     315           0 :                 afsname = talloc_string_sub(
     316             :                         tmp_ctx,
     317             :                         afsname,
     318             :                         "%s",
     319           0 :                         dom_sid_str_buf(&user_sid, &sidstr));
     320             :         }
     321             : 
     322           0 :         if (afsname == NULL) {
     323           0 :                 status = NT_STATUS_NO_MEMORY;
     324           0 :                 goto out;
     325             :         }
     326             : 
     327           0 :         if (!strlower_m(afsname)) {
     328           0 :                 status = NT_STATUS_INVALID_PARAMETER;
     329           0 :                 goto out;
     330             :         }
     331             : 
     332           0 :         DEBUG(10, ("Generating token for user %s\n", afsname));
     333             : 
     334           0 :         cell = strchr(afsname, '@');
     335             : 
     336           0 :         if (cell == NULL) {
     337           0 :                 status = NT_STATUS_NO_MEMORY;
     338           0 :                 goto out;
     339             :         }
     340             : 
     341           0 :         *cell = '\0';
     342           0 :         cell += 1;
     343             : 
     344           0 :         token = afs_createtoken_str(afsname, cell);
     345           0 :         if (token == NULL) {
     346           0 :                 status = NT_STATUS_OK;
     347           0 :                 goto out;
     348             :         }
     349             : 
     350           0 :         talloc_steal(mem_ctx, token);
     351           0 :         *_blob = data_blob_string_const_null(token);
     352             : 
     353           0 :         status = NT_STATUS_OK;
     354           0 : out:
     355           0 :         TALLOC_FREE(tmp_ctx);
     356             : 
     357           0 :         return status;
     358             : }
     359             : 
     360        1101 : NTSTATUS extra_data_to_sid_array(const char *group_sid,
     361             :                                 TALLOC_CTX *mem_ctx,
     362             :                                 struct wbint_SidArray **_sid_array)
     363             : {
     364        1101 :         TALLOC_CTX *tmp_ctx = NULL;
     365        1101 :         struct wbint_SidArray *sid_array = NULL;
     366        1101 :         struct dom_sid *require_membership_of_sid = NULL;
     367        1101 :         uint32_t num_require_membership_of_sid = 0;
     368        1101 :         char *req_sid = NULL;
     369        1101 :         const char *p = NULL;
     370           0 :         NTSTATUS status;
     371             : 
     372        1101 :         if (_sid_array == NULL) {
     373           0 :                 return NT_STATUS_INVALID_PARAMETER;
     374             :         }
     375             : 
     376        1101 :         *_sid_array = NULL;
     377             : 
     378        1101 :         tmp_ctx = talloc_new(mem_ctx);
     379        1101 :         if (tmp_ctx == NULL) {
     380           0 :                 return NT_STATUS_NO_MEMORY;
     381             :         }
     382             : 
     383        1101 :         sid_array = talloc_zero(tmp_ctx, struct wbint_SidArray);
     384        1101 :         if (sid_array == NULL) {
     385           0 :                 status = NT_STATUS_NO_MEMORY;
     386           0 :                 goto fail;
     387             :         }
     388             : 
     389        1101 :         if (!group_sid || !group_sid[0]) {
     390             :                 /* NO sid supplied, all users may access */
     391        1049 :                 status = NT_STATUS_OK;
     392             :                 /*
     393             :                  * Always return an allocated wbint_SidArray,
     394             :                  * even if the array is empty.
     395             :                  */
     396        1049 :                 goto out;
     397             :         }
     398             : 
     399          52 :         num_require_membership_of_sid = 0;
     400          52 :         require_membership_of_sid = NULL;
     401          52 :         p = group_sid;
     402             : 
     403         104 :         while (next_token_talloc(tmp_ctx, &p, &req_sid, ",")) {
     404           0 :                 struct dom_sid sid;
     405             : 
     406          52 :                 if (!string_to_sid(&sid, req_sid)) {
     407           0 :                         DBG_ERR("check_info3_in_group: could not parse %s "
     408             :                                 "as a SID!\n", req_sid);
     409           0 :                         status = NT_STATUS_INVALID_PARAMETER;
     410           0 :                         goto fail;
     411             :                 }
     412             : 
     413          52 :                 status = add_sid_to_array(tmp_ctx, &sid,
     414             :                                           &require_membership_of_sid,
     415             :                                           &num_require_membership_of_sid);
     416          52 :                 if (!NT_STATUS_IS_OK(status)) {
     417           0 :                         DBG_ERR("add_sid_to_array failed\n");
     418           0 :                         goto fail;
     419             :                 }
     420             :         }
     421             : 
     422          52 :         sid_array->num_sids = num_require_membership_of_sid;
     423          52 :         sid_array->sids = talloc_move(sid_array, &require_membership_of_sid);
     424             : 
     425          52 :         status = NT_STATUS_OK;
     426        1101 : out:
     427        1101 :         *_sid_array = talloc_move(mem_ctx, &sid_array);
     428             : 
     429        1101 : fail:
     430        1101 :         TALLOC_FREE(tmp_ctx);
     431             : 
     432        1101 :         return status;
     433             : }
     434             : 
     435           0 : static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
     436             :                                      struct wbint_SidArray *sid_array)
     437             : /**
     438             :  * Check whether a user belongs to a group or list of groups.
     439             :  *
     440             :  * @param mem_ctx talloc memory context.
     441             :  * @param info3 user information, including group membership info.
     442             :  * @param group_sid One or more groups , separated by commas.
     443             :  *
     444             :  * @return NT_STATUS_OK on success,
     445             :  *    NT_STATUS_LOGON_FAILURE if the user does not belong,
     446             :  *    or other NT_STATUS_IS_ERR(status) for other kinds of failure.
     447             :  */
     448             : {
     449           0 :         size_t i;
     450           0 :         struct security_token *token;
     451           0 :         NTSTATUS status;
     452             : 
     453             :         /* Parse the 'required group' SID */
     454             : 
     455           0 :         if (sid_array == NULL || sid_array->num_sids == 0) {
     456             :                 /* NO sid supplied, all users may access */
     457           0 :                 return NT_STATUS_OK;
     458             :         }
     459             : 
     460             :         /*
     461             :          * This is a limited-use security_token for the purpose of
     462             :          * checking the SID list below, so no claims need to be added
     463             :          * and se_access_check() will never run.
     464             :          */
     465           0 :         token = security_token_initialise(talloc_tos(),
     466             :                                           CLAIMS_EVALUATION_INVALID_STATE);
     467           0 :         if (token == NULL) {
     468           0 :                 DEBUG(0, ("talloc failed\n"));
     469           0 :                 return NT_STATUS_NO_MEMORY;
     470             :         }
     471             : 
     472           0 :         status = sid_array_from_info3(token, info3,
     473             :                                       &token->sids,
     474             :                                       &token->num_sids,
     475             :                                       true);
     476           0 :         if (!NT_STATUS_IS_OK(status)) {
     477           0 :                 return status;
     478             :         }
     479             : 
     480           0 :         if (!NT_STATUS_IS_OK(status = add_aliases(get_global_sam_sid(),
     481             :                                                   token))
     482           0 :             || !NT_STATUS_IS_OK(status = add_aliases(&global_sid_Builtin,
     483             :                                                      token))) {
     484           0 :                 DEBUG(3, ("could not add aliases: %s\n",
     485             :                           nt_errstr(status)));
     486           0 :                 return status;
     487             :         }
     488             : 
     489           0 :         security_token_debug(DBGC_CLASS, 10, token);
     490             : 
     491           0 :         for (i=0; i<sid_array->num_sids; i++) {
     492           0 :                 struct dom_sid_buf buf;
     493           0 :                 DEBUG(10, ("Checking SID %s\n",
     494             :                            dom_sid_str_buf(&sid_array->sids[i],
     495             :                                            &buf)));
     496           0 :                 if (nt_token_check_sid(&sid_array->sids[i],
     497             :                                        token)) {
     498           0 :                         DEBUG(10, ("Access ok\n"));
     499           0 :                         return NT_STATUS_OK;
     500             :                 }
     501             :         }
     502             : 
     503             :         /* Do not distinguish this error from a wrong username/pw */
     504             : 
     505           0 :         return NT_STATUS_LOGON_FAILURE;
     506             : }
     507             : 
     508        3298 : struct winbindd_domain *find_auth_domain(uint8_t flags,
     509             :                                          const char *domain_name)
     510             : {
     511           0 :         struct winbindd_domain *domain;
     512             : 
     513        3298 :         if (IS_DC) {
     514        2293 :                 domain = find_domain_from_name_noinit(domain_name);
     515        2293 :                 if (domain == NULL) {
     516        2059 :                         DEBUG(3, ("Authentication for domain [%s] refused "
     517             :                                   "as it is not a trusted domain\n",
     518             :                                   domain_name));
     519        2059 :                         return NULL;
     520             :                 }
     521             : 
     522         234 :                 if (domain->secure_channel_type != SEC_CHAN_NULL) {
     523         234 :                         return domain;
     524             :                 }
     525             : 
     526           0 :                 return domain->routing_domain;
     527             :         }
     528             : 
     529        1005 :         if (strequal(domain_name, get_global_sam_name())) {
     530          78 :                 return find_domain_from_name_noinit(domain_name);
     531             :         }
     532             : 
     533         927 :         if (lp_winbind_use_krb5_enterprise_principals()) {
     534             :                 /*
     535             :                  * If we use enterprise principals
     536             :                  * we always go through our primary domain
     537             :                  * and follow the WRONG_REALM replies.
     538             :                  */
     539         927 :                 flags &= ~WBFLAG_PAM_CONTACT_TRUSTDOM;
     540             :         }
     541             : 
     542             :         /* we can auth against trusted domains */
     543         927 :         if (flags & WBFLAG_PAM_CONTACT_TRUSTDOM) {
     544           0 :                 domain = find_domain_from_name_noinit(domain_name);
     545           0 :                 if (domain == NULL) {
     546           0 :                         DEBUG(3, ("Authentication for domain [%s] skipped "
     547             :                                   "as it is not a trusted domain\n",
     548             :                                   domain_name));
     549             :                 } else {
     550           0 :                         return domain;
     551             :                 }
     552             :         }
     553             : 
     554         927 :         return find_our_domain();
     555             : }
     556             : 
     557           0 : static NTSTATUS get_password_policy(struct winbindd_domain *domain,
     558             :                                     TALLOC_CTX *mem_ctx,
     559             :                                     struct samr_DomInfo1 **_policy)
     560             : {
     561           0 :         NTSTATUS status;
     562           0 :         struct samr_DomInfo1 *policy = NULL;
     563             : 
     564           0 :         if ( !winbindd_can_contact_domain( domain ) ) {
     565           0 :                 DBG_INFO("No inbound trust to contact domain %s\n",
     566             :                          domain->name);
     567           0 :                 return NT_STATUS_NOT_SUPPORTED;
     568             :         }
     569             : 
     570           0 :         policy = talloc_zero(mem_ctx, struct samr_DomInfo1);
     571           0 :         if (policy == NULL) {
     572           0 :                 return NT_STATUS_NO_MEMORY;
     573             :         }
     574             : 
     575           0 :         status = wb_cache_password_policy(domain, mem_ctx, policy);
     576           0 :         if (NT_STATUS_IS_ERR(status)) {
     577           0 :                 TALLOC_FREE(policy);
     578           0 :                 return status;
     579             :         }
     580             : 
     581           0 :         *_policy = talloc_move(mem_ctx, &policy);
     582             : 
     583           0 :         return NT_STATUS_OK;
     584             : }
     585             : 
     586           0 : static NTSTATUS get_max_bad_attempts_from_lockout_policy(struct winbindd_domain *domain,
     587             :                                                          TALLOC_CTX *mem_ctx,
     588             :                                                          uint16_t *lockout_threshold)
     589             : {
     590           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     591           0 :         struct samr_DomInfo12 lockout_policy;
     592             : 
     593           0 :         *lockout_threshold = 0;
     594             : 
     595           0 :         status = wb_cache_lockout_policy(domain, mem_ctx, &lockout_policy);
     596           0 :         if (NT_STATUS_IS_ERR(status)) {
     597           0 :                 return status;
     598             :         }
     599             : 
     600           0 :         *lockout_threshold = lockout_policy.lockout_threshold;
     601             : 
     602           0 :         return NT_STATUS_OK;
     603             : }
     604             : 
     605           0 : static NTSTATUS get_pwd_properties(struct winbindd_domain *domain,
     606             :                                    TALLOC_CTX *mem_ctx,
     607             :                                    uint32_t *password_properties)
     608             : {
     609           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
     610           0 :         struct samr_DomInfo1 password_policy;
     611             : 
     612           0 :         *password_properties = 0;
     613             : 
     614           0 :         status = wb_cache_password_policy(domain, mem_ctx, &password_policy);
     615           0 :         if (NT_STATUS_IS_ERR(status)) {
     616           0 :                 return status;
     617             :         }
     618             : 
     619           0 :         *password_properties = password_policy.password_properties;
     620             : 
     621           0 :         return NT_STATUS_OK;
     622             : }
     623             : 
     624             : #ifdef HAVE_KRB5
     625             : 
     626           0 : static const char *generate_krb5_ccache(TALLOC_CTX *mem_ctx,
     627             :                                         const char *type,
     628             :                                         uid_t uid,
     629             :                                         const char **user_ccache_file)
     630             : {
     631             :         /* accept FILE and WRFILE as krb5_cc_type from the client and then
     632             :          * build the full ccname string based on the user's uid here -
     633             :          * Guenther*/
     634             : 
     635           0 :         const char *gen_cc = NULL;
     636             : 
     637           0 :         if (uid != -1) {
     638           0 :                 if (strequal(type, "FILE")) {
     639           0 :                         gen_cc = talloc_asprintf(
     640             :                                 mem_ctx, "FILE:/tmp/krb5cc_%d", uid);
     641             :                 }
     642           0 :                 if (strequal(type, "WRFILE")) {
     643           0 :                         gen_cc = talloc_asprintf(
     644             :                                 mem_ctx, "WRFILE:/tmp/krb5cc_%d", uid);
     645             :                 }
     646           0 :                 if (strequal(type, "KEYRING")) {
     647           0 :                         gen_cc = talloc_asprintf(
     648             :                                 mem_ctx, "KEYRING:persistent:%d", uid);
     649             :                 }
     650           0 :                 if (strequal(type, "KCM")) {
     651           0 :                         gen_cc = talloc_asprintf(mem_ctx,
     652             :                                                  "KCM:%d",
     653             :                                                  uid);
     654             :                 }
     655             : 
     656           0 :                 if (strnequal(type, "FILE:/", 6) ||
     657           0 :                     strnequal(type, "WRFILE:/", 8) ||
     658           0 :                     strnequal(type, "DIR:/", 5)) {
     659             : 
     660             :                         /* we allow only one "%u" substitution */
     661             : 
     662           0 :                         char *p;
     663             : 
     664           0 :                         p = strchr(type, '%');
     665           0 :                         if (p != NULL) {
     666             : 
     667           0 :                                 p++;
     668             : 
     669           0 :                                 if (p != NULL && *p == 'u' && strchr(p, '%') == NULL) {
     670           0 :                                         char uid_str[sizeof("18446744073709551615")];
     671             : 
     672           0 :                                         snprintf(uid_str, sizeof(uid_str), "%u", uid);
     673             : 
     674           0 :                                         gen_cc = talloc_string_sub2(mem_ctx,
     675             :                                                         type,
     676             :                                                         "%u",
     677             :                                                         uid_str,
     678             :                                                         /* remove_unsafe_characters */
     679             :                                                         false,
     680             :                                                         /* replace_once */
     681             :                                                         true,
     682             :                                                         /* allow_trailing_dollar */
     683             :                                                         false);
     684             :                                 }
     685             :                         }
     686             :                 }
     687             :         }
     688             : 
     689           0 :         *user_ccache_file = gen_cc;
     690             : 
     691           0 :         if (gen_cc == NULL) {
     692           0 :                 gen_cc = talloc_strdup(mem_ctx, "MEMORY:winbindd_pam_ccache");
     693             :         }
     694           0 :         if (gen_cc == NULL) {
     695           0 :                 DEBUG(0,("out of memory\n"));
     696           0 :                 return NULL;
     697             :         }
     698             : 
     699           0 :         DEBUG(10, ("using ccache: %s%s\n", gen_cc,
     700             :                    (*user_ccache_file == NULL) ? " (internal)":""));
     701             : 
     702           0 :         return gen_cc;
     703             : }
     704             : 
     705             : #endif
     706             : 
     707           0 : uid_t get_uid_from_request(struct winbindd_request *request)
     708             : {
     709           0 :         uid_t uid;
     710             : 
     711           0 :         uid = request->data.auth.uid;
     712             : 
     713           0 :         if (uid == (uid_t)-1) {
     714           0 :                 DEBUG(1,("invalid uid: '%u'\n", (unsigned int)uid));
     715           0 :                 return -1;
     716             :         }
     717           0 :         return uid;
     718             : }
     719             : 
     720             : /**********************************************************************
     721             :  Authenticate a user with a clear text password using Kerberos and fill up
     722             :  ccache if required
     723             :  **********************************************************************/
     724             : 
     725           0 : static NTSTATUS winbindd_raw_kerberos_login(TALLOC_CTX *mem_ctx,
     726             :                                             struct winbindd_domain *domain,
     727             :                                             const char *user,
     728             :                                             const char *pass,
     729             :                                             const char *krb5_cc_type,
     730             :                                             uid_t uid,
     731             :                                             struct netr_SamInfo6 **info6,
     732             :                                             const char **_krb5ccname)
     733             : {
     734             : #ifdef HAVE_KRB5
     735           0 :         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
     736           0 :         krb5_error_code krb5_ret;
     737           0 :         const char *cc = NULL;
     738           0 :         const char *principal_s = NULL;
     739           0 :         char *realm = NULL;
     740           0 :         char *name_namespace = NULL;
     741           0 :         char *name_domain = NULL;
     742           0 :         char *name_user = NULL;
     743           0 :         time_t ticket_lifetime = 0;
     744           0 :         time_t renewal_until = 0;
     745           0 :         time_t time_offset = 0;
     746           0 :         const char *user_ccache_file;
     747           0 :         struct PAC_LOGON_INFO *logon_info = NULL;
     748           0 :         struct PAC_UPN_DNS_INFO *upn_dns_info = NULL;
     749           0 :         struct PAC_DATA *pac_data = NULL;
     750           0 :         struct PAC_DATA_CTR *pac_data_ctr = NULL;
     751           0 :         const char *local_service;
     752           0 :         uint32_t i;
     753           0 :         struct netr_SamInfo6 *info6_copy = NULL;
     754           0 :         char *canon_principal = NULL;
     755           0 :         char *canon_realm = NULL;
     756           0 :         bool ok;
     757             : 
     758           0 :         *info6 = NULL;
     759             : 
     760           0 :         if (domain->alt_name == NULL) {
     761           0 :                 return NT_STATUS_INVALID_PARAMETER;
     762             :         }
     763             : 
     764           0 :         if (_krb5ccname != NULL) {
     765           0 :                 *_krb5ccname = NULL;
     766             :         }
     767             : 
     768             :         /* 1st step:
     769             :          * prepare a krb5_cc_cache string for the user */
     770             : 
     771           0 :         if (uid == -1) {
     772           0 :                 DEBUG(0,("no valid uid\n"));
     773             :         }
     774             : 
     775           0 :         cc = generate_krb5_ccache(mem_ctx,
     776             :                                   krb5_cc_type,
     777             :                                   uid,
     778             :                                   &user_ccache_file);
     779           0 :         if (cc == NULL) {
     780           0 :                 return NT_STATUS_NO_MEMORY;
     781             :         }
     782             : 
     783             : 
     784             :         /* 2nd step:
     785             :          * get kerberos properties */
     786             : 
     787           0 :         if (domain->backend_data.ads_conn != NULL) {
     788           0 :                 time_offset = domain->backend_data.ads_conn->auth.time_offset;
     789             :         }
     790             : 
     791             : 
     792             :         /* 3rd step:
     793             :          * do kerberos auth and setup ccache as the user */
     794             : 
     795           0 :         ok = parse_domain_user(mem_ctx,
     796             :                         user,
     797             :                         &name_namespace,
     798             :                         &name_domain,
     799             :                         &name_user);
     800           0 :         if (!ok) {
     801           0 :                 return NT_STATUS_INVALID_PARAMETER;
     802             :         }
     803             : 
     804           0 :         realm = talloc_strdup(mem_ctx, domain->alt_name);
     805           0 :         if (realm == NULL) {
     806           0 :                 return NT_STATUS_NO_MEMORY;
     807             :         }
     808             : 
     809           0 :         if (!strupper_m(realm)) {
     810           0 :                 return NT_STATUS_INVALID_PARAMETER;
     811             :         }
     812             : 
     813           0 :         if (lp_winbind_use_krb5_enterprise_principals() &&
     814           0 :             name_namespace[0] != '\0')
     815             :         {
     816           0 :                 principal_s = talloc_asprintf(mem_ctx,
     817             :                                               "%s@%s@%s",
     818             :                                               name_user,
     819             :                                               name_namespace,
     820             :                                               realm);
     821             :         } else {
     822           0 :                 principal_s = talloc_asprintf(mem_ctx,
     823             :                                               "%s@%s",
     824             :                                               name_user,
     825             :                                               realm);
     826             :         }
     827           0 :         if (principal_s == NULL) {
     828           0 :                 return NT_STATUS_NO_MEMORY;
     829             :         }
     830             : 
     831           0 :         local_service = talloc_asprintf(mem_ctx, "%s$@%s",
     832             :                                         lp_netbios_name(), lp_realm());
     833           0 :         if (local_service == NULL) {
     834           0 :                 return NT_STATUS_NO_MEMORY;
     835             :         }
     836             : 
     837             : 
     838             :         /* if this is a user ccache, we need to act as the user to let the krb5
     839             :          * library handle the chown, etc. */
     840             : 
     841             :         /************************ ENTERING NON-ROOT **********************/
     842             : 
     843           0 :         if (user_ccache_file != NULL) {
     844           0 :                 set_effective_uid(uid);
     845           0 :                 DEBUG(10,("winbindd_raw_kerberos_login: uid is %d\n", uid));
     846             :         }
     847             : 
     848           0 :         result = kerberos_return_pac(mem_ctx,
     849             :                                      principal_s,
     850             :                                      pass,
     851             :                                      time_offset,
     852             :                                      &ticket_lifetime,
     853             :                                      &renewal_until,
     854             :                                      cc,
     855             :                                      true,
     856             :                                      true,
     857             :                                      WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
     858             :                                      NULL,
     859             :                                      local_service,
     860             :                                      &canon_principal,
     861             :                                      &canon_realm,
     862             :                                      &pac_data_ctr);
     863           0 :         if (user_ccache_file != NULL) {
     864           0 :                 gain_root_privilege();
     865             :         }
     866             : 
     867             :         /************************ RETURNED TO ROOT **********************/
     868             : 
     869           0 :         if (!NT_STATUS_IS_OK(result)) {
     870           0 :                 goto failed;
     871             :         }
     872             : 
     873           0 :         if (pac_data_ctr == NULL) {
     874           0 :                 goto failed;
     875             :         }
     876             : 
     877           0 :         pac_data = pac_data_ctr->pac_data;
     878           0 :         if (pac_data == NULL) {
     879           0 :                 goto failed;
     880             :         }
     881             : 
     882           0 :         for (i=0; i < pac_data->num_buffers; i++) {
     883             : 
     884           0 :                 if (pac_data->buffers[i].type == PAC_TYPE_LOGON_INFO) {
     885           0 :                         logon_info = pac_data->buffers[i].info->logon_info.info;
     886           0 :                         continue;
     887             :                 }
     888             : 
     889           0 :                 if (pac_data->buffers[i].type == PAC_TYPE_UPN_DNS_INFO) {
     890           0 :                         upn_dns_info = &pac_data->buffers[i].info->upn_dns_info;
     891           0 :                         continue;
     892             :                 }
     893             :         }
     894             : 
     895           0 :         if (logon_info == NULL) {
     896           0 :                 DEBUG(10,("Missing logon_info in ticket of %s\n",
     897             :                         principal_s));
     898           0 :                 return NT_STATUS_INVALID_PARAMETER;
     899             :         }
     900             : 
     901           0 :         DEBUG(10,("winbindd_raw_kerberos_login: winbindd validated ticket of %s\n",
     902             :                 principal_s));
     903             : 
     904           0 :         result = create_info6_from_pac(mem_ctx, logon_info,
     905             :                                        upn_dns_info, &info6_copy);
     906           0 :         if (!NT_STATUS_IS_OK(result)) {
     907           0 :                 goto failed;
     908             :         }
     909             : 
     910             :         /* if we had a user's ccache then return that string for the pam
     911             :          * environment */
     912             : 
     913           0 :         if (user_ccache_file != NULL) {
     914             : 
     915           0 :                 if (_krb5ccname != NULL) {
     916           0 :                         *_krb5ccname = talloc_steal(mem_ctx, user_ccache_file);
     917             :                 }
     918             : 
     919           0 :                 result = add_ccache_to_list(principal_s,
     920             :                                             cc,
     921             :                                             user,
     922             :                                             pass,
     923             :                                             realm,
     924             :                                             uid,
     925             :                                             time(NULL),
     926             :                                             ticket_lifetime,
     927             :                                             renewal_until,
     928             :                                             false,
     929             :                                             canon_principal,
     930             :                                             canon_realm);
     931             : 
     932           0 :                 if (!NT_STATUS_IS_OK(result)) {
     933           0 :                         DEBUG(10,("winbindd_raw_kerberos_login: failed to add ccache to list: %s\n",
     934             :                                 nt_errstr(result)));
     935             :                 }
     936             :         } else {
     937             : 
     938             :                 /* need to delete the memory cred cache, it is not used anymore */
     939             : 
     940           0 :                 krb5_ret = ads_kdestroy(cc);
     941           0 :                 if (krb5_ret) {
     942           0 :                         DEBUG(3,("winbindd_raw_kerberos_login: "
     943             :                                  "could not destroy krb5 credential cache: "
     944             :                                  "%s\n", error_message(krb5_ret)));
     945             :                 }
     946             : 
     947             :         }
     948           0 :         *info6 = info6_copy;
     949           0 :         return NT_STATUS_OK;
     950             : 
     951           0 : failed:
     952             :         /*
     953             :          * Do not delete an existing valid credential cache, if the user
     954             :          * e.g. enters a wrong password
     955             :          */
     956           0 :         if ((strequal(krb5_cc_type, "FILE") || strequal(krb5_cc_type, "WRFILE"))
     957           0 :             && user_ccache_file != NULL) {
     958           0 :                 return result;
     959             :         }
     960             : 
     961             :         /* we could have created a new credential cache with a valid tgt in it
     962             :          * but we weren't able to get or verify the service ticket for this
     963             :          * local host and therefore didn't get the PAC, we need to remove that
     964             :          * cache entirely now */
     965             : 
     966           0 :         krb5_ret = ads_kdestroy(cc);
     967           0 :         if (krb5_ret) {
     968           0 :                 DEBUG(3,("winbindd_raw_kerberos_login: "
     969             :                          "could not destroy krb5 credential cache: "
     970             :                          "%s\n", error_message(krb5_ret)));
     971             :         }
     972             : 
     973           0 :         if (!NT_STATUS_IS_OK(remove_ccache(user))) {
     974           0 :                 DEBUG(3,("winbindd_raw_kerberos_login: "
     975             :                           "could not remove ccache for user %s\n",
     976             :                         user));
     977             :         }
     978             : 
     979           0 :         return result;
     980             : #else
     981             :         return NT_STATUS_NOT_SUPPORTED;
     982             : #endif /* HAVE_KRB5 */
     983             : }
     984             : 
     985             : /****************************************************************
     986             : ****************************************************************/
     987             : 
     988        3160 : bool check_request_flags(uint32_t flags)
     989             : {
     990        3160 :         uint32_t flags_edata = WBFLAG_PAM_AFS_TOKEN |
     991             :                                WBFLAG_PAM_INFO3_TEXT |
     992             :                                WBFLAG_PAM_INFO3_NDR;
     993             : 
     994        3160 :         if ( ( (flags & flags_edata) == WBFLAG_PAM_AFS_TOKEN) ||
     995        3160 :              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_NDR) ||
     996        3160 :              ( (flags & flags_edata) == WBFLAG_PAM_INFO3_TEXT)||
     997         277 :               !(flags & flags_edata) ) {
     998        3160 :                 return true;
     999             :         }
    1000             : 
    1001           0 :         DEBUG(1, ("check_request_flags: invalid request flags[0x%08X]\n",
    1002             :                   flags));
    1003             : 
    1004           0 :         return false;
    1005             : }
    1006             : 
    1007             : /****************************************************************
    1008             : ****************************************************************/
    1009             : 
    1010        1637 : NTSTATUS append_auth_data(TALLOC_CTX *mem_ctx,
    1011             :                           struct winbindd_response *resp,
    1012             :                           uint32_t request_flags,
    1013             :                           uint16_t validation_level,
    1014             :                           union netr_Validation *validation,
    1015             :                           const char *name_domain,
    1016             :                           const char *name_user)
    1017             : {
    1018        1637 :         struct netr_SamInfo3 *info3 = NULL;
    1019        1637 :         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
    1020             : 
    1021        1637 :         result = map_validation_to_info3(talloc_tos(),
    1022             :                                          validation_level,
    1023             :                                          validation,
    1024             :                                          &info3);
    1025        1637 :         if (!NT_STATUS_IS_OK(result)) {
    1026           0 :                 goto out;
    1027             :         }
    1028             : 
    1029        1637 :         if (request_flags & WBFLAG_PAM_USER_SESSION_KEY) {
    1030         756 :                 memcpy(resp->data.auth.user_session_key,
    1031         756 :                        info3->base.key.key,
    1032             :                        sizeof(resp->data.auth.user_session_key)
    1033             :                        /* 16 */);
    1034             :         }
    1035             : 
    1036        1637 :         if (request_flags & WBFLAG_PAM_LMKEY) {
    1037         696 :                 memcpy(resp->data.auth.first_8_lm_hash,
    1038         696 :                        info3->base.LMSessKey.key,
    1039             :                        sizeof(resp->data.auth.first_8_lm_hash)
    1040             :                        /* 8 */);
    1041             :         }
    1042             : 
    1043        1637 :         if (request_flags & WBFLAG_PAM_UNIX_NAME) {
    1044         192 :                 char *unix_username = NULL;
    1045         192 :                 result = append_unix_username(validation_level,
    1046             :                                               validation,
    1047             :                                               name_domain,
    1048             :                                               name_user,
    1049             :                                               mem_ctx,
    1050             :                                               &unix_username);
    1051         192 :                 if (!NT_STATUS_IS_OK(result)) {
    1052           0 :                         DEBUG(10,("Failed to append Unix Username: %s\n",
    1053             :                                 nt_errstr(result)));
    1054           0 :                         goto out;
    1055             :                 }
    1056         192 :                 fstrcpy(resp->data.auth.unix_username, unix_username);
    1057         192 :                 TALLOC_FREE(unix_username);
    1058             :         }
    1059             : 
    1060             :         /* currently, anything from here on potentially overwrites extra_data. */
    1061             : 
    1062        1637 :         if (request_flags & WBFLAG_PAM_INFO3_NDR) {
    1063           0 :                 result = append_info3_as_ndr(mem_ctx, resp, info3);
    1064           0 :                 if (!NT_STATUS_IS_OK(result)) {
    1065           0 :                         DEBUG(10,("Failed to append INFO3 (NDR): %s\n",
    1066             :                                 nt_errstr(result)));
    1067           0 :                         goto out;
    1068             :                 }
    1069             :         }
    1070             : 
    1071        1637 :         if (request_flags & WBFLAG_PAM_INFO3_TEXT) {
    1072        1422 :                 result = append_info3_as_txt(mem_ctx, resp,
    1073             :                                              validation_level,
    1074             :                                              validation);
    1075        1422 :                 if (!NT_STATUS_IS_OK(result)) {
    1076           0 :                         DEBUG(10,("Failed to append INFO3 (TXT): %s\n",
    1077             :                                 nt_errstr(result)));
    1078           0 :                         goto out;
    1079             :                 }
    1080             :         }
    1081             : 
    1082        1637 :         if (request_flags & WBFLAG_PAM_AFS_TOKEN) {
    1083           0 :                 DATA_BLOB blob = data_blob_null;
    1084           0 :                 result = append_afs_token(validation_level,
    1085             :                                           validation,
    1086             :                                           name_domain,
    1087             :                                           name_user,
    1088             :                                           mem_ctx,
    1089             :                                           &blob);
    1090           0 :                 if (!NT_STATUS_IS_OK(result)) {
    1091           0 :                         DEBUG(10,("Failed to append AFS token: %s\n",
    1092             :                                 nt_errstr(result)));
    1093           0 :                         goto out;
    1094             :                 }
    1095           0 :                 resp->extra_data.data = blob.data;
    1096           0 :                 resp->length += blob.length;
    1097             :         }
    1098             : 
    1099        1637 :         result = NT_STATUS_OK;
    1100        1637 : out:
    1101        1637 :         TALLOC_FREE(info3);
    1102        1637 :         return result;
    1103             : }
    1104             : 
    1105           0 : static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
    1106             :                                               bool krb5_auth,
    1107             :                                               const char *user,
    1108             :                                               const char *pass,
    1109             :                                               const char *krb5_cc_type,
    1110             :                                               uid_t uid,
    1111             :                                               TALLOC_CTX *mem_ctx,
    1112             :                                               uint16_t *_validation_level,
    1113             :                                               union netr_Validation **_validation,
    1114             :                                               const char **_krb5ccname)
    1115             : {
    1116           0 :         TALLOC_CTX *tmp_ctx = NULL;
    1117           0 :         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
    1118           0 :         uint16_t max_allowed_bad_attempts;
    1119           0 :         char *name_namespace = NULL;
    1120           0 :         char *name_domain = NULL;
    1121           0 :         char *name_user = NULL;
    1122           0 :         struct dom_sid sid;
    1123           0 :         enum lsa_SidType type;
    1124           0 :         uchar new_nt_pass[NT_HASH_LEN];
    1125           0 :         const uint8_t *cached_nt_pass;
    1126           0 :         const uint8_t *cached_salt;
    1127           0 :         struct netr_SamInfo3 *my_info3;
    1128           0 :         time_t kickoff_time, must_change_time;
    1129           0 :         bool password_good = false;
    1130           0 :         bool ok;
    1131             : #ifdef HAVE_KRB5
    1132           0 :         struct winbindd_tdc_domain *tdc_domain = NULL;
    1133             : #endif
    1134             : 
    1135           0 :         if (_validation == NULL) {
    1136           0 :                 return NT_STATUS_INVALID_PARAMETER;
    1137             :         }
    1138           0 :         *_validation = NULL;
    1139             : 
    1140           0 :         if (_krb5ccname != NULL) {
    1141           0 :                 *_krb5ccname = NULL;
    1142             :         }
    1143             : 
    1144           0 :         DEBUG(10,("winbindd_dual_pam_auth_cached\n"));
    1145             : 
    1146           0 :         tmp_ctx = talloc_new(mem_ctx);
    1147           0 :         if (tmp_ctx == NULL) {
    1148           0 :                 return NT_STATUS_NO_MEMORY;
    1149             :         }
    1150             : 
    1151             :         /* Parse domain and username */
    1152             : 
    1153           0 :         ok = parse_domain_user(tmp_ctx,
    1154             :                         user,
    1155             :                         &name_namespace,
    1156             :                         &name_domain,
    1157             :                         &name_user);
    1158           0 :         if (!ok) {
    1159           0 :                 DBG_DEBUG("parse_domain_user failed\n");
    1160           0 :                 result = NT_STATUS_NO_SUCH_USER;
    1161           0 :                 goto out;
    1162             :         }
    1163             : 
    1164           0 :         if (!lookup_cached_name(name_namespace,
    1165             :                                 name_domain,
    1166             :                                 name_user,
    1167             :                                 &sid,
    1168             :                                 &type)) {
    1169           0 :                 DEBUG(10,("winbindd_dual_pam_auth_cached: no such user in the cache\n"));
    1170           0 :                 result = NT_STATUS_NO_SUCH_USER;
    1171           0 :                 goto out;
    1172             :         }
    1173             : 
    1174           0 :         if (type != SID_NAME_USER) {
    1175           0 :                 DEBUG(10,("winbindd_dual_pam_auth_cached: not a user (%s)\n", sid_type_lookup(type)));
    1176           0 :                 result = NT_STATUS_LOGON_FAILURE;
    1177           0 :                 goto out;
    1178             :         }
    1179             : 
    1180           0 :         result = winbindd_get_creds(domain,
    1181             :                                     tmp_ctx,
    1182             :                                     &sid,
    1183             :                                     &my_info3,
    1184             :                                     &cached_nt_pass,
    1185             :                                     &cached_salt);
    1186           0 :         if (!NT_STATUS_IS_OK(result)) {
    1187           0 :                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get creds: %s\n", nt_errstr(result)));
    1188           0 :                 goto out;
    1189             :         }
    1190             : 
    1191           0 :         E_md4hash(pass, new_nt_pass);
    1192             : 
    1193           0 :         dump_data_pw("new_nt_pass", new_nt_pass, NT_HASH_LEN);
    1194           0 :         dump_data_pw("cached_nt_pass", cached_nt_pass, NT_HASH_LEN);
    1195           0 :         if (cached_salt) {
    1196           0 :                 dump_data_pw("cached_salt", cached_salt, NT_HASH_LEN);
    1197             :         }
    1198             : 
    1199           0 :         if (cached_salt) {
    1200             :                 /* In this case we didn't store the nt_hash itself,
    1201             :                    but the MD5 combination of salt + nt_hash. */
    1202           0 :                 uchar salted_hash[NT_HASH_LEN];
    1203           0 :                 gnutls_hash_hd_t hash_hnd = NULL;
    1204           0 :                 int rc;
    1205             : 
    1206           0 :                 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
    1207           0 :                 if (rc < 0) {
    1208           0 :                         result = gnutls_error_to_ntstatus(
    1209             :                                         rc, NT_STATUS_HASH_NOT_SUPPORTED);
    1210           0 :                         goto out;
    1211             :                 }
    1212             : 
    1213           0 :                 rc = gnutls_hash(hash_hnd, cached_salt, 16);
    1214           0 :                 if (rc < 0) {
    1215           0 :                         gnutls_hash_deinit(hash_hnd, NULL);
    1216           0 :                         result = gnutls_error_to_ntstatus(
    1217             :                                         rc, NT_STATUS_HASH_NOT_SUPPORTED);
    1218           0 :                         goto out;
    1219             :                 }
    1220           0 :                 rc = gnutls_hash(hash_hnd, new_nt_pass, 16);
    1221           0 :                 if (rc < 0) {
    1222           0 :                         gnutls_hash_deinit(hash_hnd, NULL);
    1223           0 :                         result = gnutls_error_to_ntstatus(
    1224             :                                         rc, NT_STATUS_HASH_NOT_SUPPORTED);
    1225           0 :                         goto out;
    1226             :                 }
    1227           0 :                 gnutls_hash_deinit(hash_hnd, salted_hash);
    1228             : 
    1229           0 :                 password_good = mem_equal_const_time(cached_nt_pass, salted_hash,
    1230             :                                                      NT_HASH_LEN);
    1231             :         } else {
    1232             :                 /* Old cached cred - direct store of nt_hash (bad bad bad !). */
    1233           0 :                 password_good = mem_equal_const_time(cached_nt_pass, new_nt_pass,
    1234             :                                                      NT_HASH_LEN);
    1235             :         }
    1236             : 
    1237           0 :         if (password_good) {
    1238             : 
    1239             :                 /* User *DOES* know the password, update logon_time and reset
    1240             :                  * bad_pw_count */
    1241             : 
    1242           0 :                 my_info3->base.user_flags |= NETLOGON_CACHED_ACCOUNT;
    1243             : 
    1244           0 :                 if (my_info3->base.acct_flags & ACB_AUTOLOCK) {
    1245           0 :                         result = NT_STATUS_ACCOUNT_LOCKED_OUT;
    1246           0 :                         goto out;
    1247             :                 }
    1248             : 
    1249           0 :                 if (my_info3->base.acct_flags & ACB_DISABLED) {
    1250           0 :                         result = NT_STATUS_ACCOUNT_DISABLED;
    1251           0 :                         goto out;
    1252             :                 }
    1253             : 
    1254           0 :                 if (my_info3->base.acct_flags & ACB_WSTRUST) {
    1255           0 :                         result = NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT;
    1256           0 :                         goto out;
    1257             :                 }
    1258             : 
    1259           0 :                 if (my_info3->base.acct_flags & ACB_SVRTRUST) {
    1260           0 :                         result = NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT;
    1261           0 :                         goto out;
    1262             :                 }
    1263             : 
    1264           0 :                 if (my_info3->base.acct_flags & ACB_DOMTRUST) {
    1265           0 :                         result = NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT;
    1266           0 :                         goto out;
    1267             :                 }
    1268             : 
    1269           0 :                 if (!(my_info3->base.acct_flags & ACB_NORMAL)) {
    1270           0 :                         DEBUG(0,("winbindd_dual_pam_auth_cached: what's wrong with that one?: 0x%08x\n",
    1271             :                                 my_info3->base.acct_flags));
    1272           0 :                         result = NT_STATUS_LOGON_FAILURE;
    1273           0 :                         goto out;
    1274             :                 }
    1275             : 
    1276           0 :                 kickoff_time = nt_time_to_unix(my_info3->base.kickoff_time);
    1277           0 :                 if (kickoff_time != 0 && time(NULL) > kickoff_time) {
    1278           0 :                         result = NT_STATUS_ACCOUNT_EXPIRED;
    1279           0 :                         goto out;
    1280             :                 }
    1281             : 
    1282           0 :                 must_change_time = nt_time_to_unix(my_info3->base.force_password_change);
    1283           0 :                 if (must_change_time != 0 && must_change_time < time(NULL)) {
    1284             :                         /* we allow grace logons when the password has expired */
    1285           0 :                         my_info3->base.user_flags |= NETLOGON_GRACE_LOGON;
    1286             :                         /* return NT_STATUS_PASSWORD_EXPIRED; */
    1287           0 :                         goto success;
    1288             :                 }
    1289             : 
    1290             : #ifdef HAVE_KRB5
    1291           0 :                 if ((krb5_auth) &&
    1292           0 :                     ((tdc_domain = wcache_tdc_fetch_domain(tmp_ctx, name_domain)) != NULL) &&
    1293           0 :                     ((tdc_domain->trust_type & LSA_TRUST_TYPE_UPLEVEL) ||
    1294             :                     /* used to cope with the case winbindd starting without network. */
    1295           0 :                     !strequal(tdc_domain->domain_name, tdc_domain->dns_name))) {
    1296           0 :                         const char *cc = NULL;
    1297           0 :                         char *realm = NULL;
    1298           0 :                         const char *principal_s = NULL;
    1299           0 :                         const char *user_ccache_file;
    1300             : 
    1301           0 :                         if (domain->alt_name == NULL) {
    1302           0 :                                 result = NT_STATUS_INVALID_PARAMETER;
    1303           0 :                                 goto out;
    1304             :                         }
    1305             : 
    1306           0 :                         if (uid == -1) {
    1307           0 :                                 DEBUG(0,("winbindd_dual_pam_auth_cached: invalid uid\n"));
    1308           0 :                                 result = NT_STATUS_INVALID_PARAMETER;
    1309           0 :                                 goto out;
    1310             :                         }
    1311             : 
    1312           0 :                         cc = generate_krb5_ccache(tmp_ctx,
    1313             :                                                   krb5_cc_type,
    1314             :                                                   uid,
    1315             :                                                   &user_ccache_file);
    1316           0 :                         if (cc == NULL) {
    1317           0 :                                 result = NT_STATUS_NO_MEMORY;
    1318           0 :                                 goto out;
    1319             :                         }
    1320             : 
    1321           0 :                         realm = talloc_strdup(tmp_ctx, domain->alt_name);
    1322           0 :                         if (realm == NULL) {
    1323           0 :                                 result = NT_STATUS_NO_MEMORY;
    1324           0 :                                 goto out;
    1325             :                         }
    1326             : 
    1327           0 :                         if (!strupper_m(realm)) {
    1328           0 :                                 result = NT_STATUS_INVALID_PARAMETER;
    1329           0 :                                 goto out;
    1330             :                         }
    1331             : 
    1332           0 :                         principal_s = talloc_asprintf(tmp_ctx, "%s@%s", name_user, realm);
    1333           0 :                         if (principal_s == NULL) {
    1334           0 :                                 result = NT_STATUS_NO_MEMORY;
    1335           0 :                                 goto out;
    1336             :                         }
    1337             : 
    1338           0 :                         if (user_ccache_file != NULL) {
    1339             : 
    1340           0 :                                 if (_krb5ccname != NULL) {
    1341           0 :                                         *_krb5ccname = talloc_move(mem_ctx,
    1342             :                                                         &user_ccache_file);
    1343             :                                 }
    1344             : 
    1345           0 :                                 result = add_ccache_to_list(principal_s,
    1346             :                                                             cc,
    1347             :                                                             user,
    1348             :                                                             pass,
    1349             :                                                             realm,
    1350             :                                                             uid,
    1351             :                                                             time(NULL),
    1352           0 :                                                             time(NULL) + lp_winbind_cache_time(),
    1353           0 :                                                             time(NULL) + WINBINDD_PAM_AUTH_KRB5_RENEW_TIME,
    1354             :                                                             true,
    1355             :                                                             principal_s,
    1356             :                                                             realm);
    1357             : 
    1358           0 :                                 if (!NT_STATUS_IS_OK(result)) {
    1359           0 :                                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed "
    1360             :                                                 "to add ccache to list: %s\n",
    1361             :                                                 nt_errstr(result)));
    1362             :                                 }
    1363             :                         }
    1364             :                 }
    1365             : #endif /* HAVE_KRB5 */
    1366           0 :  success:
    1367             :                 /* FIXME: we possibly should handle logon hours as well (does xp when
    1368             :                  * offline?) see auth/auth_sam.c:sam_account_ok for details */
    1369             : 
    1370           0 :                 unix_to_nt_time(&my_info3->base.logon_time, time(NULL));
    1371           0 :                 my_info3->base.bad_password_count = 0;
    1372             : 
    1373           0 :                 result = winbindd_update_creds_by_info3(domain,
    1374             :                                                         user,
    1375             :                                                         pass,
    1376             :                                                         my_info3);
    1377           0 :                 if (!NT_STATUS_IS_OK(result)) {
    1378           0 :                         DEBUG(1,("winbindd_dual_pam_auth_cached: failed to update creds: %s\n",
    1379             :                                 nt_errstr(result)));
    1380           0 :                         goto out;
    1381             :                 }
    1382             : 
    1383           0 :                 result = map_info3_to_validation(mem_ctx,
    1384             :                                                  my_info3,
    1385             :                                                  _validation_level,
    1386             :                                                  _validation);
    1387           0 :                 if (!NT_STATUS_IS_OK(result)) {
    1388           0 :                         DBG_ERR("map_info3_to_validation failed: %s\n",
    1389             :                                 nt_errstr(result));
    1390           0 :                         goto out;
    1391             :                 }
    1392             : 
    1393           0 :                 result = NT_STATUS_OK;
    1394           0 :                 goto out;
    1395             :         }
    1396             : 
    1397             :         /* User does *NOT* know the correct password, modify info3 accordingly, but only if online */
    1398           0 :         if (domain->online == false) {
    1399           0 :                 goto failed;
    1400             :         }
    1401             : 
    1402             :         /* failure of this is not critical */
    1403           0 :         result = get_max_bad_attempts_from_lockout_policy(domain, tmp_ctx, &max_allowed_bad_attempts);
    1404           0 :         if (!NT_STATUS_IS_OK(result)) {
    1405           0 :                 DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get max_allowed_bad_attempts. "
    1406             :                           "Won't be able to honour account lockout policies\n"));
    1407             :         }
    1408             : 
    1409             :         /* increase counter */
    1410           0 :         my_info3->base.bad_password_count++;
    1411             : 
    1412           0 :         if (max_allowed_bad_attempts == 0) {
    1413           0 :                 goto failed;
    1414             :         }
    1415             : 
    1416             :         /* lockout user */
    1417           0 :         if (my_info3->base.bad_password_count >= max_allowed_bad_attempts) {
    1418             : 
    1419           0 :                 uint32_t password_properties;
    1420             : 
    1421           0 :                 result = get_pwd_properties(domain, tmp_ctx, &password_properties);
    1422           0 :                 if (!NT_STATUS_IS_OK(result)) {
    1423           0 :                         DEBUG(10,("winbindd_dual_pam_auth_cached: failed to get password properties.\n"));
    1424             :                 }
    1425             : 
    1426           0 :                 if ((my_info3->base.rid != DOMAIN_RID_ADMINISTRATOR) ||
    1427           0 :                     (password_properties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
    1428           0 :                         my_info3->base.acct_flags |= ACB_AUTOLOCK;
    1429             :                 }
    1430             :         }
    1431             : 
    1432           0 : failed:
    1433           0 :         result = winbindd_update_creds_by_info3(domain, user, NULL, my_info3);
    1434           0 :         if (!NT_STATUS_IS_OK(result)) {
    1435           0 :                 DEBUG(0,("winbindd_dual_pam_auth_cached: failed to update creds %s\n",
    1436             :                         nt_errstr(result)));
    1437             :         }
    1438             : 
    1439           0 :         result = NT_STATUS_LOGON_FAILURE;
    1440             : 
    1441           0 : out:
    1442           0 :         TALLOC_FREE(tmp_ctx);
    1443             : 
    1444           0 :         return result;
    1445             : }
    1446             : 
    1447           0 : static NTSTATUS winbindd_dual_pam_auth_kerberos(struct winbindd_domain *domain,
    1448             :                                                 const char *user,
    1449             :                                                 const char *pass,
    1450             :                                                 const char *krb5_cc_type,
    1451             :                                                 uid_t uid,
    1452             :                                                 TALLOC_CTX *mem_ctx,
    1453             :                                                 uint16_t *_validation_level,
    1454             :                                                 union netr_Validation **_validation,
    1455             :                                                 const char **_krb5ccname)
    1456             : {
    1457           0 :         struct netr_SamInfo6 *info6 = NULL;
    1458           0 :         struct winbindd_domain *contact_domain;
    1459           0 :         char *name_namespace = NULL;
    1460           0 :         char *name_domain = NULL;
    1461           0 :         char *name_user = NULL;
    1462           0 :         NTSTATUS result;
    1463           0 :         bool ok;
    1464             : 
    1465           0 :         DEBUG(10,("winbindd_dual_pam_auth_kerberos\n"));
    1466             : 
    1467             :         /* Parse domain and username */
    1468             : 
    1469           0 :         ok = parse_domain_user(mem_ctx,
    1470             :                                user,
    1471             :                                &name_namespace,
    1472             :                                &name_domain,
    1473             :                                &name_user);
    1474           0 :         if (!ok) {
    1475           0 :                 result = NT_STATUS_INVALID_PARAMETER;
    1476           0 :                 goto done;
    1477             :         }
    1478             : 
    1479             :         /* what domain should we contact? */
    1480             : 
    1481           0 :         if (lp_winbind_use_krb5_enterprise_principals()) {
    1482           0 :                 contact_domain = find_auth_domain(0, name_namespace);
    1483             :         } else {
    1484           0 :                 contact_domain = find_domain_from_name(name_namespace);
    1485             :         }
    1486           0 :         if (contact_domain == NULL) {
    1487           0 :                 DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
    1488             :                           user, name_domain, name_user, name_namespace));
    1489           0 :                 result = NT_STATUS_NO_SUCH_USER;
    1490           0 :                 goto done;
    1491             :         }
    1492             : 
    1493           0 :         if (contact_domain->initialized &&
    1494           0 :             contact_domain->active_directory) {
    1495           0 :                 goto try_login;
    1496             :         }
    1497             : 
    1498           0 :         if (!contact_domain->initialized) {
    1499           0 :                 init_dc_connection(contact_domain, false);
    1500             :         }
    1501             : 
    1502           0 :         if (!contact_domain->active_directory) {
    1503           0 :                 DEBUG(3,("krb5 auth requested but domain (%s) is not Active Directory\n",
    1504             :                       contact_domain->name));
    1505           0 :                 return NT_STATUS_INVALID_LOGON_TYPE;
    1506             :         }
    1507           0 : try_login:
    1508           0 :         result = winbindd_raw_kerberos_login(
    1509             :                 mem_ctx,
    1510             :                 contact_domain,
    1511             :                 user,
    1512             :                 pass,
    1513             :                 krb5_cc_type,
    1514             :                 uid,
    1515             :                 &info6,
    1516             :                 _krb5ccname);
    1517           0 :         if (!NT_STATUS_IS_OK(result)) {
    1518           0 :                 goto done;
    1519             :         }
    1520             : 
    1521           0 :         result = map_info6_to_validation(mem_ctx,
    1522             :                                          info6,
    1523             :                                          _validation_level,
    1524             :                                          _validation);
    1525           0 :         TALLOC_FREE(info6);
    1526           0 :         if (!NT_STATUS_IS_OK(result)) {
    1527           0 :                 DBG_ERR("map_info6_to_validation failed: %s\n",
    1528             :                         nt_errstr(result));
    1529             :         }
    1530             : 
    1531           0 : done:
    1532           0 :         return result;
    1533             : }
    1534             : 
    1535           0 : static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
    1536             :                                           uint32_t logon_parameters,
    1537             :                                           const char *domain,
    1538             :                                           const char *user,
    1539             :                                           const uint64_t logon_id,
    1540             :                                           const char *client_name,
    1541             :                                           const int client_pid,
    1542             :                                           const DATA_BLOB *challenge,
    1543             :                                           const DATA_BLOB *lm_resp,
    1544             :                                           const DATA_BLOB *nt_resp,
    1545             :                                           const struct tsocket_address *remote,
    1546             :                                           const struct tsocket_address *local,
    1547             :                                           bool interactive,
    1548             :                                           uint8_t *pauthoritative,
    1549             :                                           struct netr_SamInfo3 **pinfo3)
    1550             : {
    1551           0 :         struct auth_context *auth_context;
    1552           0 :         struct auth_serversupplied_info *server_info;
    1553           0 :         struct auth_usersupplied_info *user_info = NULL;
    1554           0 :         struct netr_SamInfo3 *info3;
    1555           0 :         NTSTATUS status;
    1556           0 :         bool ok;
    1557           0 :         TALLOC_CTX *frame = talloc_stackframe();
    1558             : 
    1559             :         /*
    1560             :          * We are authoritative by default
    1561             :          */
    1562           0 :         *pauthoritative = 1;
    1563             : 
    1564           0 :         status = make_user_info(frame, &user_info, user, user, domain, domain,
    1565             :                                 lp_netbios_name(), remote, local,
    1566             :                                 "winbind",
    1567             :                                 lm_resp, nt_resp, NULL, NULL,
    1568             :                                 NULL, AUTH_PASSWORD_RESPONSE);
    1569           0 :         if (!NT_STATUS_IS_OK(status)) {
    1570           0 :                 DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
    1571           0 :                 TALLOC_FREE(frame);
    1572           0 :                 return status;
    1573             :         }
    1574             : 
    1575           0 :         user_info->logon_parameters = logon_parameters;
    1576           0 :         user_info->logon_id = logon_id;
    1577           0 :         user_info->auth_description = talloc_asprintf(
    1578             :                 frame, "PASSDB, %s, %d", client_name, client_pid);
    1579           0 :         if (user_info->auth_description == NULL) {
    1580           0 :                 TALLOC_FREE(frame);
    1581           0 :                 return NT_STATUS_NO_MEMORY;
    1582             :         }
    1583             : 
    1584             :         /* We don't want to come back to winbindd or to do PAM account checks */
    1585           0 :         user_info->flags |= USER_INFO_INFO3_AND_NO_AUTHZ;
    1586             : 
    1587           0 :         if (interactive) {
    1588           0 :                 user_info->flags |= USER_INFO_INTERACTIVE_LOGON;
    1589             :         }
    1590             : 
    1591           0 :         status = make_auth3_context_for_winbind(frame, &auth_context);
    1592           0 :         if (!NT_STATUS_IS_OK(status)) {
    1593           0 :                 DBG_ERR("make_auth3_context_for_winbind failed: %s\n",
    1594             :                         nt_errstr(status));
    1595           0 :                 TALLOC_FREE(frame);
    1596           0 :                 return status;
    1597             :         }
    1598             : 
    1599           0 :         ok = auth3_context_set_challenge(auth_context,
    1600           0 :                                          challenge->data, "fixed");
    1601           0 :         if (!ok) {
    1602           0 :                 TALLOC_FREE(frame);
    1603           0 :                 return NT_STATUS_NO_MEMORY;
    1604             :         }
    1605             : 
    1606           0 :         status = auth_check_ntlm_password(mem_ctx,
    1607             :                                           auth_context,
    1608             :                                           user_info,
    1609             :                                           &server_info,
    1610             :                                           pauthoritative);
    1611           0 :         if (!NT_STATUS_IS_OK(status)) {
    1612           0 :                 TALLOC_FREE(frame);
    1613           0 :                 return status;
    1614             :         }
    1615             : 
    1616           0 :         info3 = talloc_zero(mem_ctx, struct netr_SamInfo3);
    1617           0 :         if (info3 == NULL) {
    1618           0 :                 TALLOC_FREE(frame);
    1619           0 :                 return NT_STATUS_NO_MEMORY;
    1620             :         }
    1621             : 
    1622           0 :         status = serverinfo_to_SamInfo3(server_info, info3);
    1623           0 :         if (!NT_STATUS_IS_OK(status)) {
    1624           0 :                 TALLOC_FREE(frame);
    1625           0 :                 TALLOC_FREE(info3);
    1626           0 :                 DEBUG(0, ("serverinfo_to_SamInfo3 failed: %s\n",
    1627             :                           nt_errstr(status)));
    1628           0 :                 return status;
    1629             :         }
    1630             : 
    1631           0 :         *pinfo3 = info3;
    1632           0 :         DBG_DEBUG("Authenticating user %s\\%s returned %s\n",
    1633             :                   domain,
    1634             :                   user,
    1635             :                   nt_errstr(status));
    1636           0 :         TALLOC_FREE(frame);
    1637           0 :         return status;
    1638             : }
    1639             : 
    1640           0 : static NTSTATUS winbind_samlogon_retry_loop(struct winbindd_domain *domain,
    1641             :                                             TALLOC_CTX *mem_ctx,
    1642             :                                             uint32_t logon_parameters,
    1643             :                                             const char *username,
    1644             :                                             const char *password,
    1645             :                                             const char *domainname,
    1646             :                                             const char *workstation,
    1647             :                                             const uint64_t logon_id,
    1648             :                                             bool plaintext_given,
    1649             :                                             DATA_BLOB chal,
    1650             :                                             DATA_BLOB lm_response,
    1651             :                                             DATA_BLOB nt_response,
    1652             :                                             bool interactive,
    1653             :                                             uint8_t *authoritative,
    1654             :                                             uint32_t *flags,
    1655             :                                             uint16_t *_validation_level,
    1656             :                                             union netr_Validation **_validation)
    1657             : {
    1658           0 :         int attempts = 0;
    1659           0 :         int netr_attempts = 0;
    1660           0 :         bool retry = false;
    1661           0 :         bool valid_result = false;
    1662           0 :         NTSTATUS result;
    1663           0 :         enum netr_LogonInfoClass logon_type_i;
    1664           0 :         enum netr_LogonInfoClass logon_type_n;
    1665           0 :         uint16_t validation_level = UINT16_MAX;
    1666           0 :         union netr_Validation *validation = NULL;
    1667           0 :         TALLOC_CTX *base_ctx = NULL;
    1668           0 :         struct netr_SamBaseInfo *base_info = NULL;
    1669             : 
    1670           0 :         do {
    1671           0 :                 struct rpc_pipe_client *netlogon_pipe;
    1672           0 :                 struct netlogon_creds_cli_context *netlogon_creds_ctx = NULL;
    1673             : 
    1674             :                 /*
    1675             :                  * We should always reset authoritative to 1
    1676             :                  * before calling a server again.
    1677             :                  *
    1678             :                  * Otherwise we could treat a local problem as
    1679             :                  * non-authoritative.
    1680             :                  */
    1681           0 :                 *authoritative = 1;
    1682             : 
    1683           0 :                 retry = false;
    1684             : 
    1685           0 :                 D_DEBUG("Creating a DCERPC netlogon connection for SAM logon. "
    1686             :                         "netlogon attempt: %d, samlogon attempt: %d.\n",
    1687             :                         netr_attempts,
    1688             :                         attempts);
    1689           0 :                 result = cm_connect_netlogon_secure(domain, &netlogon_pipe,
    1690             :                                                     &netlogon_creds_ctx);
    1691             : 
    1692           0 :                 if (NT_STATUS_EQUAL(result,
    1693             :                                     NT_STATUS_CANT_ACCESS_DOMAIN_INFO)) {
    1694             :                         /*
    1695             :                          * This means we don't have a trust account.
    1696             :                          */
    1697           0 :                         *authoritative = 0;
    1698           0 :                         result = NT_STATUS_NO_SUCH_USER;
    1699           0 :                         break;
    1700             :                 }
    1701             : 
    1702           0 :                 if (!NT_STATUS_IS_OK(result)) {
    1703           0 :                         DEBUG(3,("Could not open handle to NETLOGON pipe "
    1704             :                                  "(error: %s, attempts: %d)\n",
    1705             :                                   nt_errstr(result), netr_attempts));
    1706             : 
    1707           0 :                         reset_cm_connection_on_error(domain, NULL, result);
    1708             : 
    1709             :                         /* After the first retry always close the connection */
    1710           0 :                         if (netr_attempts > 0) {
    1711           0 :                                 DEBUG(3, ("This is again a problem for this "
    1712             :                                           "particular call, forcing the close "
    1713             :                                           "of this connection\n"));
    1714           0 :                                 invalidate_cm_connection(domain);
    1715             :                         }
    1716             : 
    1717             :                         /* After the second retry failover to the next DC */
    1718           0 :                         if (netr_attempts > 1) {
    1719             :                                 /*
    1720             :                                  * If the netlogon server is not reachable then
    1721             :                                  * it is possible that the DC is rebuilding
    1722             :                                  * sysvol and shutdown netlogon for that time.
    1723             :                                  * We should failover to the next dc.
    1724             :                                  */
    1725           0 :                                 DEBUG(3, ("This is the third problem for this "
    1726             :                                           "particular call, adding DC to the "
    1727             :                                           "negative cache list: %s %s\n", domain->name, domain->dcname));
    1728           0 :                                 add_failed_connection_entry(domain->name,
    1729           0 :                                                             domain->dcname,
    1730             :                                                             result);
    1731           0 :                                 saf_delete(domain->name);
    1732             :                         }
    1733             : 
    1734             :                         /* Only allow 3 retries */
    1735           0 :                         if (netr_attempts < 3) {
    1736           0 :                                 DEBUG(3, ("The connection to netlogon "
    1737             :                                           "failed, retrying\n"));
    1738           0 :                                 netr_attempts++;
    1739           0 :                                 retry = true;
    1740           0 :                                 continue;
    1741             :                         }
    1742           0 :                         return result;
    1743             :                 }
    1744             : 
    1745           0 :                 logon_type_i = NetlogonInteractiveInformation;
    1746           0 :                 logon_type_n = NetlogonNetworkInformation;
    1747           0 :                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
    1748           0 :                         logon_type_i = NetlogonInteractiveTransitiveInformation;
    1749           0 :                         logon_type_n = NetlogonNetworkTransitiveInformation;
    1750             :                 }
    1751             : 
    1752           0 :                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
    1753           0 :                         logon_type_i = NetlogonInteractiveTransitiveInformation;
    1754           0 :                         logon_type_n = NetlogonNetworkTransitiveInformation;
    1755             :                 }
    1756             : 
    1757           0 :                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
    1758           0 :                         logon_type_i = NetlogonInteractiveInformation;
    1759           0 :                         logon_type_n = NetlogonNetworkInformation;
    1760             :                 }
    1761             : 
    1762           0 :                 if (domain->domain_trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
    1763           0 :                         logon_type_i = NetlogonInteractiveInformation;
    1764           0 :                         logon_type_n = NetlogonNetworkInformation;
    1765             :                 }
    1766             : 
    1767           0 :                 netr_attempts = 0;
    1768           0 :                 if (plaintext_given) {
    1769           0 :                         result = rpccli_netlogon_password_logon(
    1770             :                                 netlogon_creds_ctx,
    1771           0 :                                 netlogon_pipe->binding_handle,
    1772             :                                 mem_ctx,
    1773             :                                 logon_parameters,
    1774             :                                 domainname,
    1775             :                                 username,
    1776             :                                 password,
    1777             :                                 workstation,
    1778             :                                 logon_id,
    1779             :                                 logon_type_i,
    1780             :                                 authoritative,
    1781             :                                 flags,
    1782             :                                 &validation_level,
    1783             :                                 &validation);
    1784           0 :                 } else if (interactive) {
    1785           0 :                         result = rpccli_netlogon_interactive_logon(
    1786             :                                 netlogon_creds_ctx,
    1787           0 :                                 netlogon_pipe->binding_handle,
    1788             :                                 mem_ctx,
    1789             :                                 logon_parameters,
    1790             :                                 username,
    1791             :                                 domainname,
    1792             :                                 workstation,
    1793             :                                 logon_id,
    1794             :                                 lm_response,
    1795             :                                 nt_response,
    1796             :                                 logon_type_i,
    1797             :                                 authoritative,
    1798             :                                 flags,
    1799             :                                 &validation_level,
    1800             :                                 &validation);
    1801             :                 } else {
    1802           0 :                         result = rpccli_netlogon_network_logon(
    1803             :                                 netlogon_creds_ctx,
    1804           0 :                                 netlogon_pipe->binding_handle,
    1805             :                                 mem_ctx,
    1806             :                                 logon_parameters,
    1807             :                                 username,
    1808             :                                 domainname,
    1809             :                                 workstation,
    1810             :                                 logon_id,
    1811             :                                 chal,
    1812             :                                 lm_response,
    1813             :                                 nt_response,
    1814             :                                 logon_type_n,
    1815             :                                 authoritative,
    1816             :                                 flags,
    1817             :                                 &validation_level,
    1818             :                                 &validation);
    1819             :                 }
    1820             : 
    1821             :                 /*
    1822             :                  * we increment this after the "feature negotiation"
    1823             :                  * for can_do_samlogon_ex and can_do_validation6
    1824             :                  */
    1825           0 :                 attempts += 1;
    1826             : 
    1827             :                 /* We have to try a second time as cm_connect_netlogon
    1828             :                    might not yet have noticed that the DC has killed
    1829             :                    our connection. */
    1830             : 
    1831           0 :                 retry = reset_cm_connection_on_error(domain,
    1832           0 :                                                      netlogon_pipe->binding_handle,
    1833             :                                                      result);
    1834           0 :                 if (retry) {
    1835           0 :                         DBG_PREFIX(attempts > 1 ? DBGLVL_NOTICE : DBGLVL_INFO, (
    1836             :                                    "This is problem %d for this "
    1837             :                                    "particular call,"
    1838             :                                    "DOMAIN[%s] DC[%s] - %s\n",
    1839             :                                    attempts,
    1840             :                                    domain->name,
    1841             :                                    domain->dcname,
    1842             :                                    nt_errstr(result)));
    1843           0 :                         continue;
    1844             :                 }
    1845             : 
    1846           0 :                 valid_result = true;
    1847             : 
    1848           0 :                 if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE)) {
    1849             :                         /*
    1850             :                          * Got DCERPC_FAULT_OP_RNG_ERROR for SamLogon
    1851             :                          * (no Ex). This happens against old Samba
    1852             :                          * DCs, if LogonSamLogonEx() fails with an error
    1853             :                          * e.g. NT_STATUS_NO_SUCH_USER or NT_STATUS_WRONG_PASSWORD.
    1854             :                          *
    1855             :                          * The server will log something like this:
    1856             :                          * api_net_sam_logon_ex: Failed to marshall NET_R_SAM_LOGON_EX.
    1857             :                          *
    1858             :                          * This sets the whole connection into a fault_state mode
    1859             :                          * and all following request get NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE.
    1860             :                          *
    1861             :                          * This also happens to our retry with LogonSamLogonWithFlags()
    1862             :                          * and LogonSamLogon().
    1863             :                          *
    1864             :                          * In order to recover from this situation, we need to
    1865             :                          * drop the connection.
    1866             :                          */
    1867           0 :                         invalidate_cm_connection(domain);
    1868           0 :                         result = NT_STATUS_LOGON_FAILURE;
    1869           0 :                         break;
    1870             :                 }
    1871             : 
    1872           0 :         } while ( (attempts < 3) && retry );
    1873             : 
    1874           0 :         if (!valid_result) {
    1875             :                 /*
    1876             :                  * This matches what windows does. In a chain of transitive
    1877             :                  * trusts the ACCESS_DENIED/authoritative=0 is not propagated
    1878             :                  * instead of NT_STATUS_NO_LOGON_SERVERS/authoritative=1 is
    1879             :                  * passed along the chain if there's no other DC is available.
    1880             :                  */
    1881           0 :                 DBG_WARNING("Mapping %s/authoritative=%u to "
    1882             :                             "NT_STATUS_NO_LOGON_SERVERS/authoritative=1 for"
    1883             :                             "USERNAME[%s] USERDOMAIN[%s] REMOTE-DOMAIN[%s] \n",
    1884             :                             nt_errstr(result),
    1885             :                             *authoritative,
    1886             :                             username,
    1887             :                             domainname,
    1888             :                             domain->name);
    1889           0 :                 *authoritative = 1;
    1890           0 :                 return NT_STATUS_NO_LOGON_SERVERS;
    1891             :         }
    1892             : 
    1893           0 :         if (!NT_STATUS_IS_OK(result)) {
    1894           0 :                 return result;
    1895             :         }
    1896             : 
    1897           0 :         switch (validation_level) {
    1898           0 :         case 3:
    1899           0 :                 base_ctx = validation->sam3;
    1900           0 :                 base_info = &validation->sam3->base;
    1901           0 :                 break;
    1902           0 :         case 6:
    1903           0 :                 base_ctx = validation->sam6;
    1904           0 :                 base_info = &validation->sam6->base;
    1905           0 :                 break;
    1906           0 :         default:
    1907           0 :                 smb_panic(__location__);
    1908             :         }
    1909             : 
    1910           0 :         if (base_info->acct_flags == 0 || base_info->account_name.string == NULL) {
    1911           0 :                 struct dom_sid user_sid;
    1912           0 :                 struct dom_sid_buf sid_buf;
    1913           0 :                 const char *acct_flags_src = "server";
    1914           0 :                 const char *acct_name_src = "server";
    1915             : 
    1916             :                 /*
    1917             :                  * Handle the case where a NT4 DC does not fill in the acct_flags in
    1918             :                  * the samlogon reply info3. Yes, in 2021, there are still admins
    1919             :                  * around with real NT4 DCs.
    1920             :                  *
    1921             :                  * We used to call dcerpc_samr_QueryUserInfo(level=16) to fetch
    1922             :                  * acct_flags, but as NT4 DCs reject authentication with workstation
    1923             :                  * accounts with NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT, even if
    1924             :                  * MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT is specified, we only ever got
    1925             :                  * ACB_NORMAL back (maybe with ACB_PWNOEXP in addition).
    1926             :                  *
    1927             :                  * For network logons NT4 DCs also skip the
    1928             :                  * account_name, so we have to fallback to the
    1929             :                  * one given by the client.
    1930             :                  */
    1931             : 
    1932           0 :                 if (base_info->acct_flags == 0) {
    1933           0 :                         base_info->acct_flags = ACB_NORMAL;
    1934           0 :                         if (base_info->force_password_change == NTTIME_MAX) {
    1935           0 :                                 base_info->acct_flags |= ACB_PWNOEXP;
    1936             :                         }
    1937           0 :                         acct_flags_src = "calculated";
    1938             :                 }
    1939             : 
    1940           0 :                 if (base_info->account_name.string == NULL) {
    1941           0 :                         base_info->account_name.string = talloc_strdup(base_ctx,
    1942             :                                                                        username);
    1943           0 :                         if (base_info->account_name.string == NULL) {
    1944           0 :                                 TALLOC_FREE(validation);
    1945           0 :                                 return NT_STATUS_NO_MEMORY;
    1946             :                         }
    1947           0 :                         acct_name_src = "client";
    1948             :                 }
    1949             : 
    1950           0 :                 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
    1951             : 
    1952           0 :                 DBG_DEBUG("Fallback to %s_acct_flags[0x%x] %s_acct_name[%s] for %s\n",
    1953             :                           acct_flags_src,
    1954             :                           base_info->acct_flags,
    1955             :                           acct_name_src,
    1956             :                           base_info->account_name.string,
    1957             :                           dom_sid_str_buf(&user_sid, &sid_buf));
    1958             :         }
    1959             : 
    1960           0 :         *_validation_level = validation_level;
    1961           0 :         *_validation = validation;
    1962           0 :         return NT_STATUS_OK;
    1963             : }
    1964             : 
    1965           0 : static NTSTATUS nt_dual_auth_passdb(TALLOC_CTX *mem_ctx,
    1966             :                                     fstring name_user,
    1967             :                                     fstring name_domain,
    1968             :                                     const char *pass,
    1969             :                                     uint64_t logon_id,
    1970             :                                     const char *client_name,
    1971             :                                     const int client_pid,
    1972             :                                     const struct tsocket_address *remote,
    1973             :                                     const struct tsocket_address *local,
    1974             :                                     uint8_t *authoritative,
    1975             :                                     struct netr_SamInfo3 **info3)
    1976             : {
    1977           0 :         unsigned char local_nt_response[24];
    1978           0 :         uchar chal[8];
    1979           0 :         DATA_BLOB chal_blob;
    1980           0 :         DATA_BLOB lm_resp;
    1981           0 :         DATA_BLOB nt_resp;
    1982             : 
    1983             :         /* do password magic */
    1984             : 
    1985           0 :         generate_random_buffer(chal, sizeof(chal));
    1986           0 :         chal_blob = data_blob_const(chal, sizeof(chal));
    1987             : 
    1988           0 :         if (lp_client_ntlmv2_auth()) {
    1989           0 :                 DATA_BLOB server_chal;
    1990           0 :                 DATA_BLOB names_blob;
    1991           0 :                 server_chal = data_blob_const(chal, 8);
    1992             : 
    1993             :                 /* note that the 'workgroup' here is for the local
    1994             :                    machine.  The 'server name' must match the
    1995             :                    'workstation' passed to the actual SamLogon call.
    1996             :                 */
    1997           0 :                 names_blob = NTLMv2_generate_names_blob(mem_ctx,
    1998             :                                                         lp_netbios_name(),
    1999             :                                                         lp_workgroup());
    2000             : 
    2001           0 :                 if (!SMBNTLMv2encrypt(mem_ctx, name_user, name_domain,
    2002             :                                       pass, &server_chal, &names_blob,
    2003             :                                       &lm_resp, &nt_resp, NULL, NULL)) {
    2004           0 :                         data_blob_free(&names_blob);
    2005           0 :                         DEBUG(0, ("SMBNTLMv2encrypt() failed!\n"));
    2006           0 :                         return NT_STATUS_NO_MEMORY;
    2007             :                 }
    2008           0 :                 data_blob_free(&names_blob);
    2009             :         } else {
    2010           0 :                 int rc;
    2011           0 :                 lm_resp = data_blob_null;
    2012             : 
    2013           0 :                 rc = SMBNTencrypt(pass, chal, local_nt_response);
    2014           0 :                 if (rc != 0) {
    2015           0 :                         DEBUG(0, ("SMBNTencrypt() failed!\n"));
    2016           0 :                         return gnutls_error_to_ntstatus(rc,
    2017             :                                     NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
    2018             :                 }
    2019             : 
    2020           0 :                 nt_resp = data_blob_talloc(mem_ctx, local_nt_response,
    2021             :                                            sizeof(local_nt_response));
    2022             :         }
    2023             : 
    2024           0 :         return winbindd_dual_auth_passdb(talloc_tos(), 0, name_domain,
    2025             :                                          name_user, logon_id, client_name,
    2026             :                                          client_pid, &chal_blob, &lm_resp,
    2027             :                                          &nt_resp, remote, local,
    2028             :                                          true, /* interactive */
    2029             :                                          authoritative, info3);
    2030             : }
    2031             : 
    2032           0 : static NTSTATUS winbindd_dual_pam_auth_samlogon(
    2033             :         TALLOC_CTX *mem_ctx,
    2034             :         struct winbindd_domain *domain,
    2035             :         const char *user,
    2036             :         const char *pass,
    2037             :         uint64_t logon_id,
    2038             :         const char *client_name,
    2039             :         const int client_pid,
    2040             :         uint32_t request_flags,
    2041             :         const struct tsocket_address *remote,
    2042             :         const struct tsocket_address *local,
    2043             :         uint16_t *_validation_level,
    2044             :         union netr_Validation **_validation)
    2045             : {
    2046           0 :         char *name_namespace = NULL;
    2047           0 :         char *name_domain = NULL;
    2048           0 :         char *name_user = NULL;
    2049           0 :         NTSTATUS result;
    2050           0 :         uint8_t authoritative = 1;
    2051           0 :         uint32_t flags = 0;
    2052           0 :         uint16_t validation_level = 0;
    2053           0 :         union netr_Validation *validation = NULL;
    2054           0 :         bool ok;
    2055             : 
    2056           0 :         DEBUG(10,("winbindd_dual_pam_auth_samlogon\n"));
    2057             : 
    2058             :         /* Parse domain and username */
    2059             : 
    2060           0 :         ok = parse_domain_user(mem_ctx,
    2061             :                         user,
    2062             :                         &name_namespace,
    2063             :                         &name_domain,
    2064             :                         &name_user);
    2065           0 :         if (!ok) {
    2066           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2067             :         }
    2068             : 
    2069             :         /*
    2070             :          * We check against domain->name instead of
    2071             :          * name_domain, as find_auth_domain() ->
    2072             :          * find_domain_from_name_noinit() already decided
    2073             :          * that we are in a child for the correct domain.
    2074             :          *
    2075             :          * name_domain can also be lp_realm()
    2076             :          * we need to check against domain->name.
    2077             :          */
    2078           0 :         if (strequal(domain->name, get_global_sam_name())) {
    2079           0 :                 struct netr_SamInfo3 *info3 = NULL;
    2080             : 
    2081           0 :                 result = nt_dual_auth_passdb(mem_ctx, name_user, name_domain,
    2082             :                                              pass, logon_id, client_name,
    2083             :                                              client_pid, remote, local,
    2084             :                                              &authoritative, &info3);
    2085             : 
    2086             :                 /*
    2087             :                  * We need to try the remote NETLOGON server if this is
    2088             :                  * not authoritative (for example on the RODC).
    2089             :                  */
    2090           0 :                 if (authoritative != 0) {
    2091           0 :                         if (!NT_STATUS_IS_OK(result)) {
    2092           0 :                                 return result;
    2093             :                         }
    2094           0 :                         result = map_info3_to_validation(mem_ctx,
    2095             :                                                          info3,
    2096             :                                                          &validation_level,
    2097             :                                                          &validation);
    2098           0 :                         TALLOC_FREE(info3);
    2099           0 :                         if (!NT_STATUS_IS_OK(result)) {
    2100           0 :                                 return result;
    2101             :                         }
    2102             : 
    2103           0 :                         goto done;
    2104             :                 }
    2105             :         }
    2106             : 
    2107             :         /* check authentication loop */
    2108             : 
    2109           0 :         result = winbind_samlogon_retry_loop(domain,
    2110             :                                              mem_ctx,
    2111             :                                              0,
    2112             :                                              name_user,
    2113             :                                              pass,
    2114             :                                              name_domain,
    2115             :                                              lp_netbios_name(),
    2116             :                                              logon_id,
    2117             :                                              true, /* plaintext_given */
    2118             :                                              data_blob_null,
    2119             :                                              data_blob_null, data_blob_null,
    2120             :                                              true, /* interactive */
    2121             :                                              &authoritative,
    2122             :                                              &flags,
    2123             :                                              &validation_level,
    2124             :                                              &validation);
    2125           0 :         if (!NT_STATUS_IS_OK(result)) {
    2126           0 :                 return result;
    2127             :         }
    2128             : 
    2129           0 : done:
    2130           0 :         *_validation_level = validation_level;
    2131           0 :         *_validation = validation;
    2132             : 
    2133           0 :         return NT_STATUS_OK;
    2134             : }
    2135             : 
    2136             : /*
    2137             :  * @brief generate an authentication message in the logs.
    2138             :  *
    2139             :  */
    2140           0 : static void log_authentication(
    2141             :         TALLOC_CTX *mem_ctx,
    2142             :         const struct winbindd_domain *domain,
    2143             :         const char *client_name,
    2144             :         pid_t client_pid,
    2145             :         uint16_t validation_level,
    2146             :         union netr_Validation *validation,
    2147             :         const struct timeval start_time,
    2148             :         const uint64_t logon_id,
    2149             :         const char *command,
    2150             :         const char *user_name,
    2151             :         const char *domain_name,
    2152             :         const char *workstation,
    2153             :         const DATA_BLOB lm_resp,
    2154             :         const DATA_BLOB nt_resp,
    2155             :         const struct tsocket_address *remote,
    2156             :         const struct tsocket_address *local,
    2157             :         NTSTATUS result)
    2158             : {
    2159           0 :         struct auth_usersupplied_info *ui = NULL;
    2160           0 :         struct dom_sid *sid = NULL;
    2161           0 :         struct loadparm_context *lp_ctx = NULL;
    2162           0 :         struct imessaging_context *msg_ctx = NULL;
    2163           0 :         struct netr_SamBaseInfo *base_info = NULL;
    2164             : 
    2165           0 :         if (validation != NULL) {
    2166           0 :                 switch (validation_level) {
    2167           0 :                 case 3:
    2168           0 :                         base_info = &validation->sam3->base;
    2169           0 :                         break;
    2170           0 :                 case 6:
    2171           0 :                         base_info = &validation->sam6->base;
    2172           0 :                         break;
    2173           0 :                 default:
    2174           0 :                         DBG_WARNING("Unexpected validation level '%d'\n",
    2175             :                                     validation_level);
    2176           0 :                         break;
    2177             :                 }
    2178             :         }
    2179             : 
    2180           0 :         ui = talloc_zero(mem_ctx, struct auth_usersupplied_info);
    2181           0 :         ui->logon_id = logon_id;
    2182           0 :         ui->service_description = "winbind";
    2183           0 :         ui->password.response.nt.length = nt_resp.length;
    2184           0 :         ui->password.response.nt.data = nt_resp.data;
    2185           0 :         ui->password.response.lanman.length = lm_resp.length;
    2186           0 :         ui->password.response.lanman.data = lm_resp.data;
    2187           0 :         if (nt_resp.length == 0 && lm_resp.length == 0) {
    2188           0 :                 ui->password_state = AUTH_PASSWORD_PLAIN;
    2189             :         } else {
    2190           0 :                 ui->password_state = AUTH_PASSWORD_RESPONSE;
    2191             :         }
    2192             :         /*
    2193             :          * In the event of a failure ui->auth_description will be null,
    2194             :          * the logging code handles this correctly so it can be ignored.
    2195             :          */
    2196           0 :         ui->auth_description = talloc_asprintf(
    2197             :                 ui,
    2198             :                 "%s, %s, %d",
    2199             :                 command,
    2200             :                 client_name,
    2201             :                 client_pid);
    2202           0 :         if (ui->auth_description == NULL) {
    2203           0 :                 DBG_ERR("OOM Unable to create auth_description\n");
    2204             :         }
    2205           0 :         ui->client.account_name = user_name;
    2206           0 :         ui->client.domain_name = domain_name;
    2207           0 :         ui->workstation_name = workstation;
    2208           0 :         ui->remote_host = remote;
    2209           0 :         ui->local_host = local;
    2210             : 
    2211           0 :         if (base_info != NULL) {
    2212           0 :                 sid = dom_sid_dup(ui, base_info->domain_sid);
    2213           0 :                 if (sid != NULL) {
    2214           0 :                         sid_append_rid(sid, base_info->rid);
    2215             :                 }
    2216             :         }
    2217             : 
    2218           0 :         if (lp_auth_event_notification()) {
    2219           0 :                 lp_ctx = loadparm_init_s3(ui, loadparm_s3_helpers());
    2220           0 :                 msg_ctx = imessaging_client_init(
    2221             :                     ui, lp_ctx, global_event_context());
    2222             :         }
    2223           0 :         log_authentication_event(
    2224             :             msg_ctx,
    2225             :             lp_ctx,
    2226             :             &start_time,
    2227             :             ui,
    2228             :             result,
    2229             :             base_info != NULL ? base_info->logon_domain.string : "",
    2230             :             base_info != NULL ? base_info->account_name.string : "",
    2231             :             sid,
    2232             :             NULL /* client_audit_info */,
    2233             :             NULL /* server_audit_info */);
    2234           0 :         TALLOC_FREE(ui);
    2235           0 : }
    2236             : 
    2237           0 : NTSTATUS _wbint_PamAuth(struct pipes_struct *p,
    2238             :                         struct wbint_PamAuth *r)
    2239             : {
    2240           0 :         struct winbindd_domain *domain = wb_child_domain();
    2241           0 :         NTSTATUS result = NT_STATUS_LOGON_FAILURE;
    2242           0 :         NTSTATUS krb5_result = NT_STATUS_OK;
    2243           0 :         char *name_namespace = NULL;
    2244           0 :         char *name_domain = NULL;
    2245           0 :         char *name_user = NULL;
    2246           0 :         char *mapped_user = NULL;
    2247           0 :         const char *domain_user = NULL;
    2248           0 :         uint16_t validation_level = UINT16_MAX;
    2249           0 :         union netr_Validation *validation = NULL;
    2250           0 :         struct netr_SamBaseInfo *base_info = NULL;
    2251           0 :         NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
    2252           0 :         bool ok;
    2253           0 :         uint64_t logon_id = 0;
    2254           0 :         const struct timeval start_time = timeval_current();
    2255           0 :         const struct tsocket_address *remote = NULL;
    2256           0 :         const struct tsocket_address *local = NULL;
    2257           0 :         const char *krb5ccname = NULL;
    2258           0 :         uid_t uid;
    2259           0 :         pid_t client_pid;
    2260             : 
    2261           0 :         if (domain == NULL) {
    2262           0 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
    2263             :         }
    2264             : 
    2265             :         /* Cut client_pid to 32bit */
    2266           0 :         client_pid = r->in.client_pid;
    2267           0 :         if ((uint64_t)client_pid != r->in.client_pid) {
    2268           0 :                 DBG_DEBUG("pid out of range\n");
    2269           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2270             :         }
    2271             : 
    2272             :         /* Cut uid to 32bit */
    2273           0 :         uid = r->in.info->uid;
    2274           0 :         if ((uint64_t)uid != r->in.info->uid) {
    2275           0 :                 DBG_DEBUG("uid out of range\n");
    2276           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2277             :         }
    2278             : 
    2279             :         /*
    2280             :          * Generate a logon_id for this session.
    2281             :          */
    2282           0 :         logon_id = generate_random_u64();
    2283           0 :         remote = dcesrv_connection_get_remote_address(p->dce_call->conn);
    2284           0 :         local = dcesrv_connection_get_local_address(p->dce_call->conn);
    2285           0 :         DEBUG(3, ("[%"PRIu32"]: dual pam auth %s\n", client_pid,
    2286             :                   r->in.info->username));
    2287             : 
    2288             :         /* Parse domain and username */
    2289             : 
    2290           0 :         name_map_status = normalize_name_unmap(p->mem_ctx,
    2291           0 :                                                r->in.info->username,
    2292             :                                                &mapped_user);
    2293             : 
    2294             :         /* If the name normalization didn't actually do anything,
    2295             :            just use the original name */
    2296             : 
    2297           0 :         if (!NT_STATUS_IS_OK(name_map_status) &&
    2298           0 :             !NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED))
    2299             :         {
    2300           0 :                 mapped_user = discard_const(r->in.info->username);
    2301             :         }
    2302             : 
    2303           0 :         ok = parse_domain_user(p->mem_ctx,
    2304             :                                mapped_user,
    2305             :                                &name_namespace,
    2306             :                                &name_domain,
    2307             :                                &name_user);
    2308           0 :         if (!ok) {
    2309           0 :                 result = NT_STATUS_INVALID_PARAMETER;
    2310           0 :                 goto done;
    2311             :         }
    2312             : 
    2313           0 :         if (mapped_user != r->in.info->username) {
    2314           0 :                 domain_user = talloc_asprintf(talloc_tos(),
    2315             :                                               "%s%c%s",
    2316             :                                               name_domain,
    2317           0 :                                               *lp_winbind_separator(),
    2318             :                                               name_user);
    2319           0 :                 if (domain_user == NULL) {
    2320           0 :                         result = NT_STATUS_NO_MEMORY;
    2321           0 :                         goto done;
    2322             :                 }
    2323           0 :                 r->in.info->username = domain_user;
    2324             :         }
    2325             : 
    2326           0 :         if (!domain->online) {
    2327           0 :                 result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
    2328           0 :                 if (domain->startup) {
    2329             :                         /* Logons are very important to users. If we're offline and
    2330             :                            we get a request within the first 30 seconds of startup,
    2331             :                            try very hard to find a DC and go online. */
    2332             : 
    2333           0 :                         DEBUG(10,("winbindd_dual_pam_auth: domain: %s offline and auth "
    2334             :                                 "request in startup mode.\n", domain->name ));
    2335             : 
    2336           0 :                         winbindd_flush_negative_conn_cache(domain);
    2337           0 :                         result = init_dc_connection(domain, false);
    2338             :                 }
    2339             :         }
    2340             : 
    2341           0 :         DEBUG(10,("winbindd_dual_pam_auth: domain: %s last was %s\n", domain->name, domain->online ? "online":"offline"));
    2342             : 
    2343             :         /* Check for Kerberos authentication */
    2344           0 :         if (domain->online && (r->in.flags & WBFLAG_PAM_KRB5)) {
    2345           0 :                 result = winbindd_dual_pam_auth_kerberos(
    2346             :                                 domain,
    2347           0 :                                 r->in.info->username,
    2348           0 :                                 r->in.info->password,
    2349           0 :                                 r->in.info->krb5_cc_type,
    2350             :                                 uid,
    2351             :                                 p->mem_ctx,
    2352             :                                 &validation_level,
    2353             :                                 &validation,
    2354             :                                 &krb5ccname);
    2355             : 
    2356             :                 /* save for later */
    2357           0 :                 krb5_result = result;
    2358             : 
    2359           0 :                 if (NT_STATUS_IS_OK(result)) {
    2360           0 :                         DEBUG(10,("winbindd_dual_pam_auth_kerberos succeeded\n"));
    2361           0 :                         goto process_result;
    2362             :                 }
    2363             : 
    2364           0 :                 DBG_DEBUG("winbindd_dual_pam_auth_kerberos failed: %s\n",
    2365             :                           nt_errstr(result));
    2366             : 
    2367           0 :                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
    2368           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
    2369           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
    2370           0 :                         DEBUG(10,("winbindd_dual_pam_auth_kerberos setting domain to offline\n"));
    2371           0 :                         set_domain_offline( domain );
    2372           0 :                         goto cached_logon;
    2373             :                 }
    2374             : 
    2375             :                 /* there are quite some NT_STATUS errors where there is no
    2376             :                  * point in retrying with a samlogon, we explicitly have to take
    2377             :                  * care not to increase the bad logon counter on the DC */
    2378             : 
    2379           0 :                 if (NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_DISABLED) ||
    2380           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_EXPIRED) ||
    2381           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_ACCOUNT_LOCKED_OUT) ||
    2382           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_LOGON_HOURS) ||
    2383           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_INVALID_WORKSTATION) ||
    2384           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_LOGON_FAILURE) ||
    2385           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) ||
    2386           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
    2387           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
    2388           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
    2389           0 :                         goto done;
    2390             :                 }
    2391             : 
    2392           0 :                 if (r->in.flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
    2393           0 :                         DEBUG(3,("falling back to samlogon\n"));
    2394           0 :                         goto sam_logon;
    2395             :                 } else {
    2396           0 :                         goto cached_logon;
    2397             :                 }
    2398             :         }
    2399             : 
    2400           0 : sam_logon:
    2401             :         /* Check for Samlogon authentication */
    2402           0 :         if (domain->online) {
    2403           0 :                 result = winbindd_dual_pam_auth_samlogon(
    2404             :                         p->mem_ctx,
    2405             :                         domain,
    2406           0 :                         r->in.info->username,
    2407           0 :                         r->in.info->password,
    2408             :                         logon_id,
    2409             :                         r->in.client_name,
    2410             :                         client_pid,
    2411             :                         r->in.flags,
    2412             :                         remote,
    2413             :                         local,
    2414             :                         &validation_level,
    2415             :                         &validation);
    2416             : 
    2417           0 :                 if (NT_STATUS_IS_OK(result)) {
    2418           0 :                         DEBUG(10,("winbindd_dual_pam_auth_samlogon succeeded\n"));
    2419             : 
    2420           0 :                         switch (validation_level) {
    2421           0 :                         case 3:
    2422           0 :                                 base_info = &validation->sam3->base;
    2423           0 :                                 break;
    2424           0 :                         case 6:
    2425           0 :                                 base_info = &validation->sam6->base;
    2426           0 :                                 break;
    2427           0 :                         default:
    2428           0 :                                 DBG_ERR("Bad validation level %d\n",
    2429             :                                         validation_level);
    2430           0 :                                 result = NT_STATUS_INTERNAL_ERROR;
    2431           0 :                                 goto done;
    2432             :                         }
    2433             : 
    2434             :                         /* add the Krb5 err if we have one */
    2435           0 :                         if ( NT_STATUS_EQUAL(krb5_result, NT_STATUS_TIME_DIFFERENCE_AT_DC ) ) {
    2436           0 :                                 base_info->user_flags |= LOGON_KRB5_FAIL_CLOCK_SKEW;
    2437             :                         }
    2438             : 
    2439           0 :                         goto process_result;
    2440             :                 }
    2441             : 
    2442           0 :                 DEBUG(10,("winbindd_dual_pam_auth_samlogon failed: %s\n",
    2443             :                           nt_errstr(result)));
    2444             : 
    2445           0 :                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_LOGON_SERVERS) ||
    2446           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_IO_TIMEOUT) ||
    2447           0 :                     NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND))
    2448             :                 {
    2449           0 :                         DEBUG(10,("winbindd_dual_pam_auth_samlogon setting domain to offline\n"));
    2450           0 :                         set_domain_offline( domain );
    2451           0 :                         goto cached_logon;
    2452             :                 }
    2453             : 
    2454           0 :                 if (domain->online) {
    2455             :                         /* We're still online - fail. */
    2456           0 :                         goto done;
    2457             :                 }
    2458             :         }
    2459             : 
    2460           0 : cached_logon:
    2461             :         /* Check for Cached logons */
    2462           0 :         if (!domain->online && (r->in.flags & WBFLAG_PAM_CACHED_LOGIN) &&
    2463           0 :             lp_winbind_offline_logon()) {
    2464           0 :                 result = winbindd_dual_pam_auth_cached(domain,
    2465           0 :                                 (r->in.flags & WBFLAG_PAM_KRB5),
    2466           0 :                                 r->in.info->username,
    2467           0 :                                 r->in.info->password,
    2468           0 :                                 r->in.info->krb5_cc_type,
    2469             :                                 uid,
    2470             :                                 p->mem_ctx,
    2471             :                                 &validation_level,
    2472             :                                 &validation,
    2473             :                                 &krb5ccname);
    2474             : 
    2475           0 :                 if (!NT_STATUS_IS_OK(result)) {
    2476           0 :                         DEBUG(10,("winbindd_dual_pam_auth_cached failed: %s\n", nt_errstr(result)));
    2477           0 :                         goto done;
    2478             :                 }
    2479           0 :                 DEBUG(10,("winbindd_dual_pam_auth_cached succeeded\n"));
    2480             :         }
    2481             : 
    2482           0 : process_result:
    2483             : 
    2484           0 :         if (NT_STATUS_IS_OK(result)) {
    2485           0 :                 struct dom_sid user_sid;
    2486           0 :                 TALLOC_CTX *base_ctx = NULL;
    2487           0 :                 struct netr_SamInfo3 *info3 = NULL;
    2488             : 
    2489           0 :                 switch (validation_level) {
    2490           0 :                 case 3:
    2491           0 :                         base_ctx = validation->sam3;
    2492           0 :                         base_info = &validation->sam3->base;
    2493           0 :                         break;
    2494           0 :                 case 6:
    2495           0 :                         base_ctx = validation->sam6;
    2496           0 :                         base_info = &validation->sam6->base;
    2497           0 :                         break;
    2498           0 :                 default:
    2499           0 :                         DBG_ERR("Bad validation level %d\n", validation_level);
    2500           0 :                         result = NT_STATUS_INTERNAL_ERROR;
    2501           0 :                         goto done;
    2502             :                 }
    2503             : 
    2504           0 :                 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
    2505             : 
    2506           0 :                 if (base_info->full_name.string == NULL) {
    2507           0 :                         struct netr_SamInfo3 *cached_info3;
    2508             : 
    2509           0 :                         cached_info3 = netsamlogon_cache_get(p->mem_ctx,
    2510             :                                                              &user_sid);
    2511           0 :                         if (cached_info3 != NULL &&
    2512           0 :                             cached_info3->base.full_name.string != NULL) {
    2513           0 :                                 base_info->full_name.string = talloc_strdup(
    2514             :                                         base_ctx,
    2515             :                                         cached_info3->base.full_name.string);
    2516           0 :                                 if (base_info->full_name.string == NULL) {
    2517           0 :                                         result = NT_STATUS_NO_MEMORY;
    2518           0 :                                         goto done;
    2519             :                                 }
    2520             :                         } else {
    2521             : 
    2522             :                                 /* this might fail so we don't check the return code */
    2523           0 :                                 wcache_query_user_fullname(domain,
    2524             :                                                 base_ctx,
    2525             :                                                 &user_sid,
    2526             :                                                 &base_info->full_name.string);
    2527             :                         }
    2528             :                 }
    2529             : 
    2530           0 :                 result = map_validation_to_info3(talloc_tos(),
    2531             :                                                  validation_level,
    2532             :                                                  validation,
    2533             :                                                  &info3);
    2534           0 :                 if (!NT_STATUS_IS_OK(result)) {
    2535           0 :                         goto done;
    2536             :                 }
    2537             : 
    2538           0 :                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
    2539             :                                            &user_sid);
    2540           0 :                 netsamlogon_cache_store(name_user, info3);
    2541             : 
    2542             :                 /* save name_to_sid info as early as possible (only if
    2543             :                    this is our primary domain so we don't invalidate
    2544             :                    the cache entry by storing the seq_num for the wrong
    2545             :                    domain). */
    2546           0 :                 if ( domain->primary ) {
    2547           0 :                         cache_name2sid(domain, name_domain, name_user,
    2548             :                                        SID_NAME_USER, &user_sid);
    2549             :                 }
    2550             : 
    2551             :                 /* Check if the user is in the right group */
    2552             : 
    2553           0 :                 result = check_info3_in_group(info3,
    2554             :                                               r->in.require_membership_of_sid);
    2555           0 :                 if (!NT_STATUS_IS_OK(result)) {
    2556           0 :                         char *s = NDR_PRINT_STRUCT_STRING(p->mem_ctx,
    2557             :                                         wbint_SidArray,
    2558             :                                         r->in.require_membership_of_sid);
    2559           0 :                         DBG_NOTICE("User %s is not in the required groups:\n",
    2560             :                                    r->in.info->username);
    2561           0 :                         DEBUGADD(DBGLVL_NOTICE, ("%s", s));
    2562           0 :                         DEBUGADD(DBGLVL_NOTICE,
    2563             :                                  ("Plaintext authentication is rejected\n"));
    2564           0 :                         goto done;
    2565             :                 }
    2566             : 
    2567           0 :                 if (!is_allowed_domain(info3->base.logon_domain.string)) {
    2568           0 :                         DBG_NOTICE("Authentication failed for user [%s] "
    2569             :                                    "from firewalled domain [%s]\n",
    2570             :                                    info3->base.account_name.string,
    2571             :                                    info3->base.logon_domain.string);
    2572           0 :                         result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
    2573           0 :                         goto done;
    2574             :                 }
    2575             : 
    2576           0 :                 r->out.validation = talloc_zero(p->mem_ctx,
    2577             :                                                 struct wbint_Validation);
    2578           0 :                 if (r->out.validation == NULL) {
    2579           0 :                         result = NT_STATUS_NO_MEMORY;
    2580           0 :                         goto done;
    2581             :                 }
    2582             : 
    2583           0 :                 r->out.validation->level = validation_level;
    2584           0 :                 r->out.validation->validation = talloc_steal(r->out.validation,
    2585             :                                                              validation);
    2586           0 :                 r->out.validation->krb5ccname = talloc_steal(r->out.validation,
    2587             :                                                              krb5ccname);
    2588           0 :                 if ((r->in.flags & WBFLAG_PAM_CACHED_LOGIN)
    2589           0 :                     && lp_winbind_offline_logon()) {
    2590             : 
    2591           0 :                         result = winbindd_store_creds(domain,
    2592           0 :                                                       r->in.info->username,
    2593           0 :                                                       r->in.info->password,
    2594             :                                                       info3);
    2595             :                 }
    2596             : 
    2597           0 :                 result = NT_STATUS_OK;
    2598             :         }
    2599             : 
    2600           0 : done:
    2601             :         /* give us a more useful (more correct?) error code */
    2602           0 :         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
    2603           0 :             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
    2604           0 :                 result = NT_STATUS_NO_LOGON_SERVERS;
    2605             :         }
    2606             : 
    2607           0 :         DBG_PREFIX(NT_STATUS_IS_OK(result) ? 5 : 2,
    2608             :                    ("Plain-text authentication for user %s returned %s"
    2609             :                    " (PAM: %d)\n",
    2610             :                    r->in.info->username,
    2611             :                    nt_errstr(result),
    2612             :                    nt_status_to_pam(result)));
    2613             : 
    2614             :         /*
    2615             :          * Log the winbind pam authentication, the logon_id will tie this to
    2616             :          * any of the logons invoked from this request.
    2617             :          */
    2618             : 
    2619           0 :         log_authentication(
    2620             :             p->mem_ctx,
    2621             :             domain,
    2622             :             r->in.client_name,
    2623             :             client_pid,
    2624             :             validation_level,
    2625             :             validation,
    2626             :             start_time,
    2627             :             logon_id,
    2628             :             "PAM_AUTH",
    2629             :             name_user,
    2630             :             name_domain,
    2631             :             NULL,
    2632             :             data_blob_null,
    2633             :             data_blob_null,
    2634             :             remote,
    2635             :             local,
    2636             :             result);
    2637             : 
    2638           0 :         if (NT_STATUS_IS_OK(result)) {
    2639           0 :                 gpupdate_user_init(r->in.info->username);
    2640             :         }
    2641             : 
    2642           0 :         return result;
    2643             : }
    2644             : 
    2645           0 : NTSTATUS winbind_dual_SamLogon(struct winbindd_domain *domain,
    2646             :                                TALLOC_CTX *mem_ctx,
    2647             :                                bool interactive,
    2648             :                                uint32_t logon_parameters,
    2649             :                                const char *name_user,
    2650             :                                const char *name_domain,
    2651             :                                const char *workstation,
    2652             :                                const uint64_t logon_id,
    2653             :                                const char* client_name,
    2654             :                                const int client_pid,
    2655             :                                DATA_BLOB chal_blob,
    2656             :                                DATA_BLOB lm_response,
    2657             :                                DATA_BLOB nt_response,
    2658             :                                const struct tsocket_address *remote,
    2659             :                                const struct tsocket_address *local,
    2660             :                                uint8_t *authoritative,
    2661             :                                bool skip_sam,
    2662             :                                uint32_t *flags,
    2663             :                                uint16_t *_validation_level,
    2664             :                                union netr_Validation **_validation)
    2665             : {
    2666           0 :         uint16_t validation_level = 0;
    2667           0 :         union netr_Validation *validation = NULL;
    2668           0 :         NTSTATUS result;
    2669             : 
    2670             :         /*
    2671             :          * We check against domain->name instead of
    2672             :          * name_domain, as find_auth_domain() ->
    2673             :          * find_domain_from_name_noinit() already decided
    2674             :          * that we are in a child for the correct domain.
    2675             :          *
    2676             :          * name_domain can also be lp_realm()
    2677             :          * we need to check against domain->name.
    2678             :          */
    2679           0 :         if (!skip_sam && strequal(domain->name, get_global_sam_name())) {
    2680           0 :                 struct netr_SamInfo3 *info3 = NULL;
    2681             : 
    2682           0 :                 result = winbindd_dual_auth_passdb(
    2683             :                         talloc_tos(),
    2684             :                         logon_parameters,
    2685             :                         name_domain, name_user,
    2686             :                         logon_id,
    2687             :                         client_name,
    2688             :                         client_pid,
    2689             :                         &chal_blob, &lm_response, &nt_response,
    2690             :                         remote,
    2691             :                         local,
    2692             :                         interactive,
    2693             :                         authoritative,
    2694             :                         &info3);
    2695           0 :                 if (NT_STATUS_IS_OK(result)) {
    2696           0 :                         result = map_info3_to_validation(mem_ctx,
    2697             :                                                          info3,
    2698             :                                                          &validation_level,
    2699             :                                                          &validation);
    2700           0 :                         TALLOC_FREE(info3);
    2701           0 :                         if (!NT_STATUS_IS_OK(result)) {
    2702           0 :                                 goto done;
    2703             :                         }
    2704             :                 }
    2705             : 
    2706             :                 /*
    2707             :                  * We need to try the remote NETLOGON server if this is
    2708             :                  * not authoritative.
    2709             :                  */
    2710           0 :                 if (*authoritative != 0) {
    2711           0 :                         *flags = 0;
    2712           0 :                         goto process_result;
    2713             :                 }
    2714             :         }
    2715             : 
    2716           0 :         result = winbind_samlogon_retry_loop(domain,
    2717             :                                              mem_ctx,
    2718             :                                              logon_parameters,
    2719             :                                              name_user,
    2720             :                                              NULL, /* password */
    2721             :                                              name_domain,
    2722             :                                              /* Bug #3248 - found by Stefan Burkei. */
    2723             :                                              workstation, /* We carefully set this above so use it... */
    2724             :                                              logon_id,
    2725             :                                              false, /* plaintext_given */
    2726             :                                              chal_blob,
    2727             :                                              lm_response,
    2728             :                                              nt_response,
    2729             :                                              interactive,
    2730             :                                              authoritative,
    2731             :                                              flags,
    2732             :                                              &validation_level,
    2733             :                                              &validation);
    2734           0 :         if (!NT_STATUS_IS_OK(result)) {
    2735           0 :                 goto done;
    2736             :         }
    2737             : 
    2738           0 : process_result:
    2739             : 
    2740           0 :         if (NT_STATUS_IS_OK(result)) {
    2741           0 :                 struct dom_sid user_sid;
    2742           0 :                 TALLOC_CTX *base_ctx = NULL;
    2743           0 :                 struct netr_SamBaseInfo *base_info = NULL;
    2744           0 :                 struct netr_SamInfo3 *info3 = NULL;
    2745             : 
    2746           0 :                 switch (validation_level) {
    2747           0 :                 case 3:
    2748           0 :                         base_ctx = validation->sam3;
    2749           0 :                         base_info = &validation->sam3->base;
    2750           0 :                         break;
    2751           0 :                 case 6:
    2752           0 :                         base_ctx = validation->sam6;
    2753           0 :                         base_info = &validation->sam6->base;
    2754           0 :                         break;
    2755           0 :                 default:
    2756           0 :                         result = NT_STATUS_INTERNAL_ERROR;
    2757           0 :                         goto done;
    2758             :                 }
    2759             : 
    2760           0 :                 sid_compose(&user_sid, base_info->domain_sid, base_info->rid);
    2761             : 
    2762           0 :                 if (base_info->full_name.string == NULL) {
    2763           0 :                         struct netr_SamInfo3 *cached_info3;
    2764             : 
    2765           0 :                         cached_info3 = netsamlogon_cache_get(mem_ctx,
    2766             :                                                              &user_sid);
    2767           0 :                         if (cached_info3 != NULL &&
    2768           0 :                             cached_info3->base.full_name.string != NULL)
    2769             :                         {
    2770           0 :                                 base_info->full_name.string = talloc_strdup(
    2771             :                                         base_ctx,
    2772             :                                         cached_info3->base.full_name.string);
    2773             :                         } else {
    2774             : 
    2775             :                                 /* this might fail so we don't check the return code */
    2776           0 :                                 wcache_query_user_fullname(domain,
    2777             :                                                 base_ctx,
    2778             :                                                 &user_sid,
    2779             :                                                 &base_info->full_name.string);
    2780             :                         }
    2781             :                 }
    2782             : 
    2783           0 :                 result = map_validation_to_info3(talloc_tos(),
    2784             :                                                  validation_level,
    2785             :                                                  validation,
    2786             :                                                  &info3);
    2787           0 :                 if (!NT_STATUS_IS_OK(result)) {
    2788           0 :                         goto done;
    2789             :                 }
    2790           0 :                 wcache_invalidate_samlogon(find_domain_from_name(name_domain),
    2791             :                                            &user_sid);
    2792           0 :                 netsamlogon_cache_store(name_user, info3);
    2793           0 :                 TALLOC_FREE(info3);
    2794             :         }
    2795             : 
    2796           0 : done:
    2797             : 
    2798             :         /* give us a more useful (more correct?) error code */
    2799           0 :         if ((NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) ||
    2800           0 :             (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)))) {
    2801           0 :                 result = NT_STATUS_NO_LOGON_SERVERS;
    2802             :         }
    2803             : 
    2804           0 :         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
    2805             :               ("NTLM CRAP authentication for user [%s]\\[%s] returned %s\n",
    2806             :                name_domain,
    2807             :                name_user,
    2808             :                nt_errstr(result)));
    2809             : 
    2810           0 :         if (!NT_STATUS_IS_OK(result)) {
    2811           0 :                 return result;
    2812             :         }
    2813             : 
    2814           0 :         *_validation_level = validation_level;
    2815           0 :         *_validation = validation;
    2816           0 :         return NT_STATUS_OK;
    2817             : }
    2818             : 
    2819           0 : NTSTATUS _wbint_PamAuthCrap(struct pipes_struct *p, struct wbint_PamAuthCrap *r)
    2820             : {
    2821           0 :         struct winbindd_domain *domain = wb_child_domain();
    2822           0 :         NTSTATUS result;
    2823           0 :         uint64_t logon_id = 0;
    2824           0 :         uint8_t authoritative = 1;
    2825           0 :         uint32_t flags = 0;
    2826           0 :         uint16_t validation_level = UINT16_MAX;
    2827           0 :         union netr_Validation *validation = NULL;
    2828           0 :         const struct timeval start_time = timeval_current();
    2829           0 :         const struct tsocket_address *remote = NULL;
    2830           0 :         const struct tsocket_address *local = NULL;
    2831           0 :         struct netr_SamInfo3 *info3 = NULL;
    2832           0 :         pid_t client_pid;
    2833             : 
    2834           0 :         if (domain == NULL) {
    2835           0 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
    2836             :         }
    2837             : 
    2838             :         /* Cut client_pid to 32bit */
    2839           0 :         client_pid = r->in.client_pid;
    2840           0 :         if ((uint64_t)client_pid != r->in.client_pid) {
    2841           0 :                 DBG_DEBUG("pid out of range\n");
    2842           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2843             :         }
    2844             : 
    2845           0 :         logon_id = generate_random_u64();
    2846           0 :         remote = dcesrv_connection_get_remote_address(p->dce_call->conn);
    2847           0 :         local = dcesrv_connection_get_local_address(p->dce_call->conn);
    2848             : 
    2849           0 :         DBG_NOTICE("[%"PRIu32"]: pam auth crap domain: %s user: %s\n",
    2850             :                    client_pid, r->in.domain, r->in.user);
    2851             : 
    2852           0 :         result = winbind_dual_SamLogon(domain,
    2853             :                                        p->mem_ctx,
    2854             :                                        false, /* interactive */
    2855             :                                        r->in.logon_parameters,
    2856             :                                        r->in.user,
    2857             :                                        r->in.domain,
    2858             :                                        r->in.workstation,
    2859             :                                        logon_id,
    2860             :                                        r->in.client_name,
    2861             :                                        client_pid,
    2862             :                                        r->in.chal,
    2863             :                                        r->in.lm_resp,
    2864             :                                        r->in.nt_resp,
    2865             :                                        remote,
    2866             :                                        local,
    2867             :                                        &authoritative,
    2868             :                                        false,
    2869             :                                        &flags,
    2870             :                                        &validation_level,
    2871             :                                        &validation);
    2872           0 :         if (!NT_STATUS_IS_OK(result)) {
    2873           0 :                 goto done;
    2874             :         }
    2875             : 
    2876           0 :         result = map_validation_to_info3(p->mem_ctx,
    2877             :                                          validation_level,
    2878             :                                          validation,
    2879             :                                          &info3);
    2880           0 :         if (!NT_STATUS_IS_OK(result)) {
    2881           0 :                 goto done;
    2882             :         }
    2883             : 
    2884             :         /* Check if the user is in the right group */
    2885           0 :         result = check_info3_in_group(info3, r->in.require_membership_of_sid);
    2886           0 :         if (!NT_STATUS_IS_OK(result)) {
    2887           0 :                 char *s = NDR_PRINT_STRUCT_STRING(p->mem_ctx,
    2888             :                                                   wbint_SidArray,
    2889             :                                                   r->in.require_membership_of_sid);
    2890           0 :                 DBG_NOTICE("User %s is not in the required groups:\n",
    2891             :                            r->in.user);
    2892           0 :                 DEBUGADD(DBGLVL_NOTICE, ("%s", s));
    2893           0 :                 DEBUGADD(DBGLVL_NOTICE,
    2894             :                          ("CRAP authentication is rejected\n"));
    2895           0 :                 goto done;
    2896             :         }
    2897             : 
    2898           0 :         if (!is_allowed_domain(info3->base.logon_domain.string)) {
    2899           0 :                 DBG_NOTICE("Authentication failed for user [%s] "
    2900             :                            "from firewalled domain [%s]\n",
    2901             :                            info3->base.account_name.string,
    2902             :                            info3->base.logon_domain.string);
    2903           0 :                 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
    2904           0 :                 goto done;
    2905             :         }
    2906             : 
    2907           0 :         r->out.validation = talloc_zero(p->mem_ctx,
    2908             :                                         struct wbint_PamAuthCrapValidation);
    2909           0 :         if (r->out.validation == NULL) {
    2910           0 :                 result = NT_STATUS_NO_MEMORY;
    2911           0 :                 goto done;
    2912             :         }
    2913             : 
    2914           0 :         r->out.validation->level = validation_level;
    2915           0 :         r->out.validation->validation = talloc_move(r->out.validation,
    2916             :                                                     &validation);
    2917           0 : done:
    2918             : 
    2919           0 :         if (r->in.flags & WBFLAG_PAM_NT_STATUS_SQUASH) {
    2920           0 :                 result = nt_status_squash(result);
    2921             :         }
    2922             : 
    2923           0 :         *r->out.authoritative = authoritative;
    2924             : 
    2925             :         /*
    2926             :          * Log the winbind pam authentication, the logon_id will tie this to
    2927             :          * any of the logons invoked from this request.
    2928             :          */
    2929           0 :         log_authentication(
    2930             :             p->mem_ctx,
    2931             :             domain,
    2932             :             r->in.client_name,
    2933             :             client_pid,
    2934           0 :             r->out.validation->level,
    2935           0 :             r->out.validation->validation,
    2936             :             start_time,
    2937             :             logon_id,
    2938             :             "NTLM_AUTH",
    2939             :             r->in.user,
    2940             :             r->in.domain,
    2941             :             r->in.workstation,
    2942             :             r->in.lm_resp,
    2943             :             r->in.nt_resp,
    2944             :             remote,
    2945             :             local,
    2946             :             result);
    2947             : 
    2948           0 :         return result;
    2949             : }
    2950             : 
    2951           0 : NTSTATUS _wbint_PamAuthChangePassword(struct pipes_struct *p,
    2952             :                                       struct wbint_PamAuthChangePassword *r)
    2953             : {
    2954           0 :         struct winbindd_domain *contact_domain = wb_child_domain();
    2955           0 :         struct policy_handle dom_pol;
    2956           0 :         struct rpc_pipe_client *cli = NULL;
    2957           0 :         bool got_info = false;
    2958           0 :         struct samr_DomInfo1 *info = NULL;
    2959           0 :         struct userPwdChangeFailureInformation *reject = NULL;
    2960           0 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
    2961           0 :         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
    2962           0 :         char *namespace = NULL;
    2963           0 :         char *domain = NULL;
    2964           0 :         char *user = NULL;
    2965           0 :         struct dcerpc_binding_handle *b = NULL;
    2966           0 :         bool ok;
    2967           0 :         pid_t client_pid;
    2968             : 
    2969           0 :         ZERO_STRUCT(dom_pol);
    2970             : 
    2971           0 :         if (contact_domain == NULL) {
    2972           0 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
    2973             :         }
    2974             : 
    2975             :         /* Cut client_pid to 32bit */
    2976           0 :         client_pid = r->in.client_pid;
    2977           0 :         if ((uint64_t)client_pid != r->in.client_pid) {
    2978           0 :                 DBG_DEBUG("pid out of range\n");
    2979           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2980             :         }
    2981             : 
    2982           0 :         DBG_NOTICE("[%"PRIu32"]: dual pam chauthtok %s\n",
    2983             :                    client_pid, r->in.user);
    2984             : 
    2985           0 :         ok = parse_domain_user(p->mem_ctx,
    2986             :                                r->in.user,
    2987             :                                &namespace,
    2988             :                                &domain,
    2989             :                                &user);
    2990           0 :         if (!ok) {
    2991           0 :                 goto done;
    2992             :         }
    2993             : 
    2994           0 :         if (!is_allowed_domain(domain)) {
    2995           0 :                 DBG_NOTICE("Authentication failed for user [%s] "
    2996             :                            "from firewalled domain [%s]\n",
    2997             :                            user, domain);
    2998           0 :                 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
    2999           0 :                 goto done;
    3000             :         }
    3001             : 
    3002             :         /* Initialize reject reason */
    3003           0 :         *r->out.reject_reason = Undefined;
    3004             : 
    3005             :         /* Get sam handle */
    3006             : 
    3007           0 :         result = cm_connect_sam(contact_domain,
    3008             :                                 p->mem_ctx,
    3009             :                                 true,
    3010             :                                 &cli,
    3011             :                                 &dom_pol);
    3012           0 :         if (!NT_STATUS_IS_OK(result)) {
    3013           0 :                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
    3014           0 :                 goto done;
    3015             :         }
    3016             : 
    3017           0 :         b = cli->binding_handle;
    3018             : 
    3019           0 :         status = dcerpc_samr_chgpasswd_user4(cli->binding_handle,
    3020             :                                              p->mem_ctx,
    3021           0 :                                              cli->srv_name_slash,
    3022             :                                              user,
    3023             :                                              r->in.old_password,
    3024             :                                              r->in.new_password,
    3025             :                                              &result);
    3026           0 :         if (NT_STATUS_IS_OK(status) && NT_STATUS_IS_OK(result)) {
    3027             :                 /* Password successfully changed. */
    3028           0 :                 goto done;
    3029             :         }
    3030           0 :         if (!NT_STATUS_IS_OK(status)) {
    3031           0 :                 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
    3032           0 :                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_SUPPORTED) ||
    3033           0 :                     NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
    3034             :                         /* DO NOT FALLBACK TO RC4 */
    3035           0 :                         if (lp_weak_crypto() == SAMBA_WEAK_CRYPTO_DISALLOWED) {
    3036           0 :                                 result = NT_STATUS_STRONG_CRYPTO_NOT_SUPPORTED;
    3037           0 :                                 goto process_result;
    3038             :                         }
    3039             :                 }
    3040             :         } else {
    3041             :                 /* Password change was unsuccessful. */
    3042           0 :                 if (!NT_STATUS_IS_OK(result)) {
    3043           0 :                         goto done;
    3044             :                 }
    3045             :         }
    3046             : 
    3047           0 :         result = rpccli_samr_chgpasswd_user3(cli,
    3048             :                                              p->mem_ctx,
    3049             :                                              user,
    3050             :                                              r->in.new_password,
    3051             :                                              r->in.old_password,
    3052             :                                              &info,
    3053             :                                              &reject);
    3054             : 
    3055             :         /* Windows 2003 returns NT_STATUS_PASSWORD_RESTRICTION */
    3056             : 
    3057           0 :         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) ) {
    3058             : 
    3059           0 :                 *r->out.dominfo = talloc_steal(p->mem_ctx, info);
    3060           0 :                 *r->out.reject_reason = reject->extendedFailureReason;
    3061             : 
    3062           0 :                 got_info = true;
    3063             :         }
    3064             : 
    3065             :         /* atm the pidl generated rpccli_samr_ChangePasswordUser3 function will
    3066             :          * return with NT_STATUS_BUFFER_TOO_SMALL for w2k dcs as w2k just
    3067             :          * returns with 4byte error code (NT_STATUS_NOT_SUPPORTED) which is too
    3068             :          * short to comply with the samr_ChangePasswordUser3 idl - gd */
    3069             : 
    3070             :         /* only fallback when the chgpasswd_user3 call is not supported */
    3071           0 :         if (NT_STATUS_EQUAL(result, NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE) ||
    3072           0 :             NT_STATUS_EQUAL(result, NT_STATUS_NOT_SUPPORTED) ||
    3073           0 :             NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL) ||
    3074           0 :             NT_STATUS_EQUAL(result, NT_STATUS_NOT_IMPLEMENTED)) {
    3075             : 
    3076           0 :                 DEBUG(10,("Password change with chgpasswd_user3 failed with: %s, retrying chgpasswd_user2\n",
    3077             :                         nt_errstr(result)));
    3078             : 
    3079           0 :                 result = rpccli_samr_chgpasswd_user2(cli,
    3080             :                                                      p->mem_ctx,
    3081             :                                                      user,
    3082             :                                                      r->in.new_password,
    3083             :                                                      r->in.old_password);
    3084             : 
    3085             :                 /* Windows 2000 returns NT_STATUS_ACCOUNT_RESTRICTION.
    3086             :                    Map to the same status code as Windows 2003. */
    3087             : 
    3088           0 :                 if ( NT_STATUS_EQUAL(NT_STATUS_ACCOUNT_RESTRICTION, result ) ) {
    3089           0 :                         result = NT_STATUS_PASSWORD_RESTRICTION;
    3090             :                 }
    3091             :         }
    3092             : 
    3093           0 : done:
    3094             : 
    3095           0 :         if (NT_STATUS_IS_OK(result)
    3096           0 :             && (r->in.flags & WBFLAG_PAM_CACHED_LOGIN)
    3097           0 :             && lp_winbind_offline_logon()) {
    3098           0 :                 result = winbindd_update_creds_by_name(contact_domain, user,
    3099             :                                                        r->in.new_password);
    3100             :                 /* Again, this happens when we login from gdm or xdm
    3101             :                  * and the password expires, *BUT* cached credentials
    3102             :                  * don't exist. winbindd_update_creds_by_name()
    3103             :                  * returns NT_STATUS_NO_SUCH_USER.
    3104             :                  * This is not a failure.
    3105             :                  * --- BoYang
    3106             :                  * */
    3107           0 :                 if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
    3108           0 :                         result = NT_STATUS_OK;
    3109             :                 }
    3110             : 
    3111           0 :                 if (!NT_STATUS_IS_OK(result)) {
    3112           0 :                         DEBUG(10, ("Failed to store creds: %s\n",
    3113             :                                    nt_errstr(result)));
    3114           0 :                         goto process_result;
    3115             :                 }
    3116             :         }
    3117             : 
    3118           0 :         if (!NT_STATUS_IS_OK(result) && !got_info && contact_domain) {
    3119             : 
    3120           0 :                 NTSTATUS policy_ret;
    3121             : 
    3122           0 :                 policy_ret = get_password_policy(contact_domain,
    3123             :                                                  p->mem_ctx,
    3124             :                                                  &info);
    3125             : 
    3126             :                 /* failure of this is non critical, it will just provide no
    3127             :                  * additional information to the client why the change has
    3128             :                  * failed - Guenther */
    3129             : 
    3130           0 :                 if (!NT_STATUS_IS_OK(policy_ret)) {
    3131           0 :                         DEBUG(10,("Failed to get password policies: %s\n", nt_errstr(policy_ret)));
    3132           0 :                         goto process_result;
    3133             :                 }
    3134             : 
    3135           0 :                 *r->out.dominfo = talloc_steal(p->mem_ctx, info);
    3136             :         }
    3137             : 
    3138           0 : process_result:
    3139             : 
    3140           0 :         if (strequal(contact_domain->name, get_global_sam_name())) {
    3141             :                 /* FIXME: internal rpc pipe does not cache handles yet */
    3142           0 :                 if (b) {
    3143           0 :                         if (is_valid_policy_hnd(&dom_pol)) {
    3144           0 :                                 NTSTATUS _result;
    3145           0 :                                 dcerpc_samr_Close(b,
    3146             :                                                   p->mem_ctx,
    3147             :                                                   &dom_pol,
    3148             :                                                   &_result);
    3149             :                         }
    3150           0 :                         TALLOC_FREE(cli);
    3151             :                 }
    3152             :         }
    3153             : 
    3154           0 :         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
    3155             :               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
    3156             :                domain,
    3157             :                user,
    3158             :                nt_errstr(result),
    3159             :                nt_status_to_pam(result)));
    3160             : 
    3161           0 :         return result;
    3162             : }
    3163             : 
    3164           0 : NTSTATUS _wbint_PamLogOff(struct pipes_struct *p, struct wbint_PamLogOff *r)
    3165             : {
    3166           0 :         struct winbindd_domain *domain = wb_child_domain();
    3167           0 :         NTSTATUS result = NT_STATUS_NOT_SUPPORTED;
    3168           0 :         pid_t client_pid;
    3169           0 :         uid_t user_uid;
    3170             : 
    3171           0 :         if (domain == NULL) {
    3172           0 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
    3173             :         }
    3174             : 
    3175             :         /* Cut client_pid to 32bit */
    3176           0 :         client_pid = r->in.client_pid;
    3177           0 :         if ((uint64_t)client_pid != r->in.client_pid) {
    3178           0 :                 DBG_DEBUG("pid out of range\n");
    3179           0 :                 return NT_STATUS_INVALID_PARAMETER;
    3180             :         }
    3181             : 
    3182             :         /* Cut uid to 32bit */
    3183           0 :         user_uid = r->in.uid;
    3184           0 :         if ((uint64_t)user_uid != r->in.uid) {
    3185           0 :                 DBG_DEBUG("uid out of range\n");
    3186           0 :                 return NT_STATUS_INVALID_PARAMETER;
    3187             :         }
    3188             : 
    3189           0 :         DBG_NOTICE("[%"PRIu32"]: pam dual logoff %s\n", client_pid, r->in.user);
    3190             : 
    3191           0 :         if (!(r->in.flags & WBFLAG_PAM_KRB5)) {
    3192           0 :                 result = NT_STATUS_OK;
    3193           0 :                 goto process_result;
    3194             :         }
    3195             : 
    3196           0 :         if ((r->in.krb5ccname == NULL) || (strlen(r->in.krb5ccname) == 0)) {
    3197           0 :                 result = NT_STATUS_OK;
    3198           0 :                 goto process_result;
    3199             :         }
    3200             : 
    3201             : #ifdef HAVE_KRB5
    3202             : 
    3203           0 :         if (user_uid == (uid_t)-1) {
    3204           0 :                 DBG_DEBUG("Invalid uid for user '%s'\n", r->in.user);
    3205           0 :                 goto process_result;
    3206             :         }
    3207             : 
    3208             :         /* what we need here is to find the corresponding krb5 ccache name *we*
    3209             :          * created for a given username and destroy it */
    3210             : 
    3211           0 :         if (!ccache_entry_exists(r->in.user)) {
    3212           0 :                 result = NT_STATUS_OK;
    3213           0 :                 DBG_DEBUG("No entry found for user '%s'.\n", r->in.user);
    3214           0 :                 goto process_result;
    3215             :         }
    3216             : 
    3217           0 :         if (!ccache_entry_identical(r->in.user, user_uid, r->in.krb5ccname)) {
    3218           0 :                 DBG_DEBUG("Cached entry differs for user '%s'\n", r->in.user);
    3219           0 :                 goto process_result;
    3220             :         }
    3221             : 
    3222           0 :         result = remove_ccache(r->in.user);
    3223           0 :         if (!NT_STATUS_IS_OK(result)) {
    3224           0 :                 DBG_DEBUG("Failed to remove ccache for user '%s': %s\n",
    3225             :                           r->in.user, nt_errstr(result));
    3226           0 :                 goto process_result;
    3227             :         }
    3228             : 
    3229             :         /*
    3230             :          * Remove any mlock'ed memory creds in the child
    3231             :          * we might be using for krb5 ticket renewal.
    3232             :          */
    3233             : 
    3234           0 :         winbindd_delete_memory_creds(r->in.user);
    3235             : 
    3236             : #else
    3237             :         result = NT_STATUS_NOT_SUPPORTED;
    3238             : #endif
    3239             : 
    3240           0 : process_result:
    3241             : 
    3242           0 :         return result;
    3243             : }
    3244             : 
    3245             : /* Change user password with auth crap*/
    3246             : 
    3247           0 : NTSTATUS _wbint_PamAuthCrapChangePassword(struct pipes_struct *p,
    3248             :                                 struct wbint_PamAuthCrapChangePassword *r)
    3249             : {
    3250           0 :         NTSTATUS result;
    3251           0 :         char *namespace = NULL;
    3252           0 :         char *domain = NULL;
    3253           0 :         char *user = NULL;
    3254           0 :         struct policy_handle dom_pol;
    3255           0 :         struct winbindd_domain *contact_domain = wb_child_domain();
    3256           0 :         struct rpc_pipe_client *cli = NULL;
    3257           0 :         struct dcerpc_binding_handle *b = NULL;
    3258           0 :         TALLOC_CTX *frame = talloc_stackframe();
    3259           0 :         pid_t client_pid;
    3260             : 
    3261           0 :         ZERO_STRUCT(dom_pol);
    3262             : 
    3263           0 :         if (contact_domain == NULL) {
    3264           0 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
    3265             :         }
    3266             : 
    3267             :         /* Cut client_pid to 32bit */
    3268           0 :         client_pid = r->in.client_pid;
    3269           0 :         if ((uint64_t)client_pid != r->in.client_pid) {
    3270           0 :                 DBG_DEBUG("pid out of range\n");
    3271           0 :                 return NT_STATUS_INVALID_PARAMETER;
    3272             :         }
    3273             : 
    3274           0 :         DBG_NOTICE("[%"PRIu32"]: pam change pswd auth crap domain: %s "
    3275             :                    "user: %s\n", client_pid, r->in.domain, r->in.user);
    3276             : 
    3277           0 :         if (lp_winbind_offline_logon()) {
    3278           0 :                 DEBUG(0,("Refusing password change as winbind offline logons are enabled. "));
    3279           0 :                 DEBUGADD(0,("Changing passwords here would risk inconsistent logons\n"));
    3280           0 :                 result = NT_STATUS_ACCESS_DENIED;
    3281           0 :                 goto done;
    3282             :         }
    3283             : 
    3284           0 :         if (r->in.domain != NULL && strlen(r->in.domain) > 0) {
    3285           0 :                 user = talloc_strdup(frame, "");
    3286           0 :                 namespace = talloc_strdup(frame, "");
    3287           0 :                 domain = talloc_strdup(frame, r->in.domain);
    3288           0 :                 if (domain == NULL || user == NULL || namespace == NULL) {
    3289           0 :                         result = NT_STATUS_NO_MEMORY;
    3290           0 :                         goto done;
    3291             :                 }
    3292             : 
    3293             :         } else {
    3294           0 :                 bool ok;
    3295             : 
    3296           0 :                 ok = parse_domain_user(frame,
    3297             :                                        r->in.user,
    3298             :                                        &namespace,
    3299             :                                        &domain,
    3300             :                                        &user);
    3301           0 :                 if (!ok) {
    3302           0 :                         result = NT_STATUS_INVALID_PARAMETER;
    3303           0 :                         goto done;
    3304             :                 }
    3305             : 
    3306           0 :                 if (strlen(domain) == 0) {
    3307           0 :                         DBG_NOTICE("no domain specified with username (%s) - "
    3308             :                                    "failing auth\n", r->in.user);
    3309           0 :                         result = NT_STATUS_NO_SUCH_USER;
    3310           0 :                         goto done;
    3311             :                 }
    3312             :         }
    3313             : 
    3314           0 :         if (!*domain && lp_winbind_use_default_domain()) {
    3315           0 :                 TALLOC_FREE(domain);
    3316           0 :                 domain = talloc_strdup(frame, lp_workgroup());
    3317           0 :                 if (domain == NULL) {
    3318           0 :                         result = NT_STATUS_NO_MEMORY;
    3319           0 :                         goto done;
    3320             :                 }
    3321             :         }
    3322             : 
    3323           0 :         if (!is_allowed_domain(domain)) {
    3324           0 :                 DBG_NOTICE("Authentication failed for user [%s] "
    3325             :                            "from firewalled domain [%s]\n",
    3326             :                            r->in.user,
    3327             :                            domain);
    3328           0 :                 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
    3329           0 :                 goto done;
    3330             :         }
    3331             : 
    3332           0 :         if(!*user) {
    3333           0 :                 TALLOC_FREE(user);
    3334           0 :                 user = talloc_strdup(frame, r->in.user);
    3335           0 :                 if (user == NULL) {
    3336           0 :                         result = NT_STATUS_NO_SUCH_USER;
    3337           0 :                         goto done;
    3338             :                 }
    3339             :         }
    3340             : 
    3341             :         /* Get sam handle */
    3342             : 
    3343           0 :         result = cm_connect_sam(contact_domain,
    3344             :                                 p->mem_ctx,
    3345             :                                 true,
    3346             :                                 &cli,
    3347             :                                 &dom_pol);
    3348           0 :         if (!NT_STATUS_IS_OK(result)) {
    3349           0 :                 DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
    3350           0 :                 goto done;
    3351             :         }
    3352             : 
    3353           0 :         b = cli->binding_handle;
    3354             : 
    3355           0 :         result = rpccli_samr_chng_pswd_auth_crap(cli,
    3356             :                                                  p->mem_ctx,
    3357             :                                                  user,
    3358             :                                                  r->in.new_nt_pswd,
    3359             :                                                  r->in.old_nt_hash_enc,
    3360             :                                                  r->in.new_lm_pswd,
    3361             :                                                  r->in.old_lm_hash_enc);
    3362             : 
    3363           0 :  done:
    3364             : 
    3365           0 :         if (strequal(contact_domain->name, get_global_sam_name())) {
    3366             :                 /* FIXME: internal rpc pipe does not cache handles yet */
    3367           0 :                 if (b) {
    3368           0 :                         if (is_valid_policy_hnd(&dom_pol)) {
    3369           0 :                                 NTSTATUS _result;
    3370           0 :                                 dcerpc_samr_Close(b,
    3371             :                                                   p->mem_ctx,
    3372             :                                                   &dom_pol,
    3373             :                                                   &_result);
    3374             :                         }
    3375           0 :                         TALLOC_FREE(cli);
    3376             :                 }
    3377             :         }
    3378             : 
    3379           0 :         DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2,
    3380             :               ("Password change for user [%s]\\[%s] returned %s (PAM: %d)\n",
    3381             :                domain, user,
    3382             :                nt_errstr(result),
    3383             :                nt_status_to_pam(result)));
    3384           0 :         TALLOC_FREE(frame);
    3385           0 :         return result;
    3386             : }
    3387             : 
    3388             : #ifdef HAVE_KRB5
    3389         870 : static NTSTATUS extract_pac_vrfy_sigs(TALLOC_CTX *mem_ctx, DATA_BLOB pac_blob,
    3390             :                                       struct PAC_DATA **p_pac_data)
    3391             : {
    3392         870 :         krb5_context krbctx = NULL;
    3393           0 :         krb5_error_code k5ret;
    3394           0 :         krb5_keytab keytab;
    3395           0 :         krb5_kt_cursor cursor;
    3396           0 :         krb5_keytab_entry entry;
    3397         870 :         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
    3398             : 
    3399         870 :         ZERO_STRUCT(entry);
    3400         870 :         ZERO_STRUCT(cursor);
    3401             : 
    3402         870 :         k5ret = smb_krb5_init_context_common(&krbctx);
    3403         870 :         if (k5ret) {
    3404           0 :                 DBG_ERR("kerberos init context failed (%s)\n",
    3405             :                         error_message(k5ret));
    3406           0 :                 status = krb5_to_nt_status(k5ret);
    3407           0 :                 goto out;
    3408             :         }
    3409             : 
    3410         870 :         k5ret =  gse_krb5_get_server_keytab(krbctx, &keytab);
    3411         870 :         if (k5ret) {
    3412           0 :                 DEBUG(1, ("Failed to get keytab: %s\n",
    3413             :                           error_message(k5ret)));
    3414           0 :                 status = krb5_to_nt_status(k5ret);
    3415           0 :                 goto out_free;
    3416             :         }
    3417             : 
    3418         870 :         k5ret = krb5_kt_start_seq_get(krbctx, keytab, &cursor);
    3419         870 :         if (k5ret) {
    3420           0 :                 DEBUG(1, ("Failed to start seq: %s\n",
    3421             :                           error_message(k5ret)));
    3422           0 :                 status = krb5_to_nt_status(k5ret);
    3423           0 :                 goto out_keytab;
    3424             :         }
    3425             : 
    3426         870 :         k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
    3427        3525 :         while (k5ret == 0) {
    3428        3525 :                 status = kerberos_decode_pac(mem_ctx,
    3429             :                                              pac_blob,
    3430             :                                              krbctx,
    3431             :                                              NULL, /* krbtgt_keyblock */
    3432             :                                              KRB5_KT_KEY(&entry), /* service_keyblock */
    3433             :                                              NULL, /* client_principal */
    3434             :                                              0, /* tgs_authtime */
    3435             :                                              p_pac_data);
    3436        3525 :                 (void)smb_krb5_kt_free_entry(krbctx, &entry);
    3437        3525 :                 if (NT_STATUS_IS_OK(status)) {
    3438         870 :                         break;
    3439             :                 }
    3440        2655 :                 k5ret = krb5_kt_next_entry(krbctx, keytab, &entry, &cursor);
    3441             :         }
    3442         870 :         if (k5ret != 0 && k5ret != KRB5_KT_END) {
    3443           0 :                 DEBUG(1, ("Failed to get next entry: %s\n",
    3444             :                           error_message(k5ret)));
    3445           0 :                 (void)smb_krb5_kt_free_entry(krbctx, &entry);
    3446             :         }
    3447             : 
    3448         870 :         k5ret = krb5_kt_end_seq_get(krbctx, keytab, &cursor);
    3449         870 :         if (k5ret) {
    3450           0 :                 DEBUG(1, ("Failed to end seq: %s\n",
    3451             :                           error_message(k5ret)));
    3452             :         }
    3453         870 : out_keytab:
    3454         870 :         k5ret = krb5_kt_close(krbctx, keytab);
    3455         870 :         if (k5ret) {
    3456           0 :                 DEBUG(1, ("Failed to close keytab: %s\n",
    3457             :                           error_message(k5ret)));
    3458             :         }
    3459         870 : out_free:
    3460         870 :         krb5_free_context(krbctx);
    3461         870 : out:
    3462         870 :         return status;
    3463             : }
    3464             : 
    3465         870 : NTSTATUS winbindd_pam_auth_pac_verify(struct winbindd_cli_state *state,
    3466             :                                       TALLOC_CTX *mem_ctx,
    3467             :                                       bool *p_is_trusted,
    3468             :                                       uint16_t *p_validation_level,
    3469             :                                       union netr_Validation **p_validation)
    3470             : {
    3471         870 :         struct winbindd_request *req = state->request;
    3472           0 :         DATA_BLOB pac_blob;
    3473         870 :         struct PAC_DATA *pac_data = NULL;
    3474         870 :         struct PAC_LOGON_INFO *logon_info = NULL;
    3475         870 :         struct PAC_UPN_DNS_INFO *upn_dns_info = NULL;
    3476         870 :         struct netr_SamInfo6 *info6 = NULL;
    3477         870 :         uint16_t validation_level = 0;
    3478         870 :         union netr_Validation *validation = NULL;
    3479         870 :         struct netr_SamInfo3 *info3_copy = NULL;
    3480           0 :         NTSTATUS result;
    3481         870 :         bool is_trusted = false;
    3482           0 :         uint32_t i;
    3483         870 :         TALLOC_CTX *tmp_ctx = NULL;
    3484             : 
    3485         870 :         tmp_ctx = talloc_new(mem_ctx);
    3486         870 :         if (tmp_ctx == NULL) {
    3487           0 :                 return NT_STATUS_NO_MEMORY;
    3488             :         }
    3489             : 
    3490         870 :         *p_is_trusted = false;
    3491         870 :         *p_validation_level = 0;
    3492         870 :         *p_validation = NULL;
    3493             : 
    3494         870 :         pac_blob = data_blob_const(req->extra_data.data, req->extra_len);
    3495         870 :         result = extract_pac_vrfy_sigs(tmp_ctx, pac_blob, &pac_data);
    3496         870 :         if (NT_STATUS_IS_OK(result)) {
    3497         870 :                 is_trusted = true;
    3498             :         }
    3499         870 :         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
    3500             :                 /* Try without signature verification */
    3501           0 :                 result = kerberos_decode_pac(tmp_ctx,
    3502             :                                              pac_blob,
    3503             :                                              NULL, /* krb5_context */
    3504             :                                              NULL, /* krbtgt_keyblock */
    3505             :                                              NULL, /* service_keyblock */
    3506             :                                              NULL, /* client_principal */
    3507             :                                              0, /* tgs_authtime */
    3508             :                                              &pac_data);
    3509             :         }
    3510         870 :         if (!NT_STATUS_IS_OK(result)) {
    3511           0 :                 DEBUG(1, ("Error during PAC signature verification: %s\n",
    3512             :                           nt_errstr(result)));
    3513           0 :                 goto out;
    3514             :         }
    3515             : 
    3516        7334 :         for (i=0; i < pac_data->num_buffers; i++) {
    3517        6464 :                 if (pac_data->buffers[i].type == PAC_TYPE_LOGON_INFO) {
    3518         870 :                         logon_info = pac_data->buffers[i].info->logon_info.info;
    3519         870 :                         continue;
    3520             :                 }
    3521        5594 :                 if (pac_data->buffers[i].type == PAC_TYPE_UPN_DNS_INFO) {
    3522         746 :                         upn_dns_info = &pac_data->buffers[i].info->upn_dns_info;
    3523         746 :                         continue;
    3524             :                 }
    3525             :         }
    3526             : 
    3527         870 :         result = create_info6_from_pac(tmp_ctx,
    3528             :                                        logon_info,
    3529             :                                        upn_dns_info,
    3530             :                                        &info6);
    3531         870 :         if (!NT_STATUS_IS_OK(result)) {
    3532           0 :                 goto out;
    3533             :         }
    3534             : 
    3535         870 :         if (!is_allowed_domain(info6->base.logon_domain.string)) {
    3536           2 :                 DBG_NOTICE("Authentication failed for user [%s] "
    3537             :                            "from firewalled domain [%s]\n",
    3538             :                            info6->base.account_name.string,
    3539             :                            info6->base.logon_domain.string);
    3540           2 :                 result = NT_STATUS_AUTHENTICATION_FIREWALL_FAILED;
    3541           2 :                 goto out;
    3542             :         }
    3543             : 
    3544         868 :         result = map_info6_to_validation(tmp_ctx,
    3545             :                                          info6,
    3546             :                                          &validation_level,
    3547             :                                          &validation);
    3548         868 :         if (!NT_STATUS_IS_OK(result)) {
    3549           0 :                 goto out;
    3550             :         }
    3551             : 
    3552         868 :         result = map_validation_to_info3(tmp_ctx,
    3553             :                                          validation_level,
    3554             :                                          validation,
    3555             :                                          &info3_copy);
    3556         868 :         if (!NT_STATUS_IS_OK(result)) {
    3557           0 :                 goto out;
    3558             :         }
    3559             : 
    3560         868 :         if (is_trusted) {
    3561             :                 /*
    3562             :                  * Signature verification succeeded, we can
    3563             :                  * trust the PAC and prime the netsamlogon
    3564             :                  * and name2sid caches. DO NOT DO THIS
    3565             :                  * in the signature verification failed
    3566             :                  * code path.
    3567             :                  */
    3568         868 :                 struct winbindd_domain *domain = NULL;
    3569             : 
    3570         868 :                 netsamlogon_cache_store(NULL, info3_copy);
    3571             : 
    3572             :                 /*
    3573             :                  * We're in the parent here, so find the child
    3574             :                  * pointer from the PAC domain name.
    3575             :                  */
    3576         868 :                 domain = find_lookup_domain_from_name(
    3577         868 :                                 info3_copy->base.logon_domain.string);
    3578         868 :                 if (domain && domain->primary ) {
    3579           0 :                         struct dom_sid user_sid;
    3580           0 :                         struct dom_sid_buf buf;
    3581             : 
    3582         868 :                         sid_compose(&user_sid,
    3583         868 :                                 info3_copy->base.domain_sid,
    3584         868 :                                 info3_copy->base.rid);
    3585             : 
    3586         868 :                         cache_name2sid_trusted(domain,
    3587         868 :                                 info3_copy->base.logon_domain.string,
    3588         868 :                                 info3_copy->base.account_name.string,
    3589             :                                 SID_NAME_USER,
    3590             :                                 &user_sid);
    3591             : 
    3592         868 :                         DBG_INFO("PAC for user %s\\%s SID %s primed cache\n",
    3593             :                                 info3_copy->base.logon_domain.string,
    3594             :                                 info3_copy->base.account_name.string,
    3595             :                                 dom_sid_str_buf(&user_sid, &buf));
    3596             :                 }
    3597             :         }
    3598             : 
    3599         868 :         *p_is_trusted = is_trusted;
    3600         868 :         *p_validation_level = validation_level;
    3601         868 :         *p_validation = talloc_move(mem_ctx, &validation);
    3602             : 
    3603         868 :         result = NT_STATUS_OK;
    3604         870 : out:
    3605         870 :         TALLOC_FREE(tmp_ctx);
    3606         870 :         return result;
    3607             : }
    3608             : #else /* HAVE_KRB5 */
    3609             : NTSTATUS winbindd_pam_auth_pac_verify(struct winbindd_cli_state *state,
    3610             :                                       TALLOC_CTX *mem_ctx,
    3611             :                                       bool *p_is_trusted,
    3612             :                                       uint16_t *p_validation_level,
    3613             :                                       union netr_Validation **p_validation);
    3614             : {
    3615             : 
    3616             :         *p_is_trusted = false;
    3617             :         *p_validation_level = 0;
    3618             :         *p_validation = NULL;
    3619             :         return NT_STATUS_NO_SUCH_USER;
    3620             : }
    3621             : #endif /* HAVE_KRB5 */

Generated by: LCOV version 1.14