LCOV - code coverage report
Current view: top level - source4/auth/ntlm - auth_winbind.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 112 131 85.5 %
Date: 2024-06-13 04:01:37 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Winbind authentication mechnism
       5             : 
       6             :    Copyright (C) Tim Potter 2000
       7             :    Copyright (C) Andrew Bartlett 2001 - 2002
       8             :    Copyright (C) Stefan Metzmacher 2005
       9             :    
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             :    
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             :    
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include <tevent.h>
      26             : #include "../lib/util/tevent_ntstatus.h"
      27             : #include "auth/auth.h"
      28             : #include "auth/ntlm/auth_proto.h"
      29             : #include "librpc/gen_ndr/ndr_winbind_c.h"
      30             : #include "lib/messaging/irpc.h"
      31             : #include "param/param.h"
      32             : #include "nsswitch/libwbclient/wbclient.h"
      33             : #include "auth/auth_sam_reply.h"
      34             : #include "libcli/security/security.h"
      35             : #include "dsdb/samdb/samdb.h"
      36             : #include "auth/auth_sam.h"
      37             : 
      38             : #undef DBGC_CLASS
      39             : #define DBGC_CLASS DBGC_AUTH
      40             : 
      41             : _PUBLIC_ NTSTATUS auth4_winbind_init(TALLOC_CTX *);
      42             : 
      43         538 : static NTSTATUS winbind_want_check(struct auth_method_context *ctx,
      44             :                                    TALLOC_CTX *mem_ctx,
      45             :                                    const struct auth_usersupplied_info *user_info)
      46             : {
      47         538 :         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
      48          10 :                 return NT_STATUS_NOT_IMPLEMENTED;
      49             :         }
      50             : 
      51             :         /* TODO: maybe limit the user scope to remote users only */
      52         528 :         return NT_STATUS_OK;
      53             : }
      54             : 
      55             : struct winbind_check_password_state {
      56             :         struct auth_method_context *ctx;
      57             :         const struct auth_usersupplied_info *user_info;
      58             :         struct winbind_SamLogon req;
      59             :         struct auth_user_info_dc *user_info_dc;
      60             :         bool authoritative;
      61             : };
      62             : 
      63             : static void winbind_check_password_done(struct tevent_req *subreq);
      64             : 
      65             : /*
      66             :  Authenticate a user with a challenge/response
      67             :  using IRPC to the winbind task
      68             : */
      69         528 : static struct tevent_req *winbind_check_password_send(TALLOC_CTX *mem_ctx,
      70             :                                 struct tevent_context *ev,
      71             :                                 struct auth_method_context *ctx,
      72             :                                 const struct auth_usersupplied_info *user_info)
      73             : {
      74         528 :         struct tevent_req *req = NULL;
      75         528 :         struct winbind_check_password_state *state = NULL;
      76             :         NTSTATUS status;
      77             :         struct dcerpc_binding_handle *irpc_handle;
      78             :         const struct auth_usersupplied_info *user_info_new;
      79             :         struct netr_IdentityInfo *identity_info;
      80             :         struct imessaging_context *msg_ctx;
      81         528 :         struct tevent_req *subreq = NULL;
      82             : 
      83         528 :         req = tevent_req_create(mem_ctx, &state,
      84             :                                 struct winbind_check_password_state);
      85         528 :         if (req == NULL) {
      86           0 :                 return NULL;
      87             :         }
      88         528 :         state->ctx = ctx;
      89         528 :         state->user_info = user_info;
      90         528 :         state->authoritative = true;
      91             : 
      92         528 :         msg_ctx = imessaging_client_init(state, ctx->auth_ctx->lp_ctx, ev);
      93         528 :         if (msg_ctx == NULL) {
      94           0 :                 DEBUG(1, ("imessaging_init failed\n"));
      95           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_SERVER_STATE);
      96           0 :                 return tevent_req_post(req, ev);
      97             :         }
      98             : 
      99         528 :         irpc_handle = irpc_binding_handle_by_name(state, msg_ctx,
     100             :                                                   "winbind_server",
     101             :                                                   &ndr_table_winbind);
     102         528 :         if (irpc_handle == NULL) {
     103           0 :                 DEBUG(0, ("Winbind authentication for [%s]\\[%s] failed, " 
     104             :                           "no winbind_server running!\n",
     105             :                           user_info->client.domain_name, user_info->client.account_name));
     106           0 :                 tevent_req_nterror(req, NT_STATUS_NO_LOGON_SERVERS);
     107           0 :                 return tevent_req_post(req, ev);
     108             :         }
     109             : 
     110             :         /*
     111             :          * 120 seconds should be enough even for trusted domains.
     112             :          *
     113             :          * Currently winbindd has a much lower limit.
     114             :          * And tests with Windows RODCs show that it
     115             :          * returns NO_LOGON_SERVERS after 90-100 seconds
     116             :          * if it can't reach any RWDC.
     117             :          */
     118         528 :         dcerpc_binding_handle_set_timeout(irpc_handle, 120);
     119             : 
     120         528 :         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
     121             :                 struct netr_PasswordInfo *password_info;
     122             : 
     123         118 :                 status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_HASH,
     124             :                                            user_info, &user_info_new);
     125         118 :                 if (tevent_req_nterror(req, status)) {
     126           0 :                         return tevent_req_post(req, ev);
     127             :                 }
     128         118 :                 user_info = user_info_new;
     129             : 
     130         118 :                 password_info = talloc_zero(state, struct netr_PasswordInfo);
     131         118 :                 if (tevent_req_nomem(password_info, req)) {
     132           0 :                         return tevent_req_post(req, ev);
     133             :                 }
     134             : 
     135         118 :                 password_info->lmpassword = *user_info->password.hash.lanman;
     136         118 :                 password_info->ntpassword = *user_info->password.hash.nt;
     137             : 
     138         118 :                 identity_info = &password_info->identity_info;
     139         118 :                 state->req.in.logon_level    = 1;
     140         118 :                 state->req.in.logon.password= password_info;
     141             :         } else {
     142             :                 struct netr_NetworkInfo *network_info;
     143             :                 uint8_t chal[8];
     144             : 
     145         410 :                 status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE,
     146             :                                            user_info, &user_info_new);
     147         410 :                 if (tevent_req_nterror(req, status)) {
     148           0 :                         return tevent_req_post(req, ev);
     149             :                 }
     150         410 :                 user_info = user_info_new;
     151             : 
     152         410 :                 network_info = talloc_zero(state, struct netr_NetworkInfo);
     153         410 :                 if (tevent_req_nomem(network_info, req)) {
     154           0 :                         return tevent_req_post(req, ev);
     155             :                 }
     156             : 
     157         410 :                 status = auth_get_challenge(ctx->auth_ctx, chal);
     158         410 :                 if (tevent_req_nterror(req, status)) {
     159           0 :                         return tevent_req_post(req, ev);
     160             :                 }
     161             : 
     162         410 :                 memcpy(network_info->challenge, chal, sizeof(network_info->challenge));
     163             : 
     164         410 :                 network_info->nt.length = user_info->password.response.nt.length;
     165         410 :                 network_info->nt.data        = user_info->password.response.nt.data;
     166             : 
     167         410 :                 network_info->lm.length = user_info->password.response.lanman.length;
     168         410 :                 network_info->lm.data        = user_info->password.response.lanman.data;
     169             : 
     170         410 :                 identity_info = &network_info->identity_info;
     171         410 :                 state->req.in.logon_level    = 2;
     172         410 :                 state->req.in.logon.network = network_info;
     173             :         }
     174             : 
     175         528 :         identity_info->domain_name.string    = user_info->client.domain_name;
     176         528 :         identity_info->parameter_control     = user_info->logon_parameters; /* see MSV1_0_* */
     177         528 :         identity_info->logon_id                      = user_info->logon_id;
     178         528 :         identity_info->account_name.string   = user_info->client.account_name;
     179         528 :         identity_info->workstation.string    = user_info->workstation_name;
     180             : 
     181         528 :         state->req.in.validation_level = 6;
     182             : 
     183         528 :         subreq = dcerpc_winbind_SamLogon_r_send(state, ev, irpc_handle,
     184         528 :                                                 &state->req);
     185         528 :         if (tevent_req_nomem(subreq, req)) {
     186           0 :                 return tevent_req_post(req, ev);
     187             :         }
     188         528 :         tevent_req_set_callback(subreq,
     189             :                                 winbind_check_password_done,
     190             :                                 req);
     191             : 
     192         528 :         return req;
     193             : }
     194             : 
     195         528 : static void winbind_check_password_done(struct tevent_req *subreq)
     196             : {
     197         399 :         struct tevent_req *req =
     198         528 :                 tevent_req_callback_data(subreq,
     199             :                 struct tevent_req);
     200         399 :         struct winbind_check_password_state *state =
     201         528 :                 tevent_req_data(req,
     202             :                 struct winbind_check_password_state);
     203         528 :         struct auth_method_context *ctx = state->ctx;
     204         528 :         const struct auth_usersupplied_info *user_info = state->user_info;
     205         528 :         struct ldb_dn *domain_dn = NULL;
     206         528 :         const char *nt4_domain = NULL;
     207         528 :         const char *nt4_account = NULL;
     208         528 :         struct ldb_message *msg = NULL;
     209             :         NTSTATUS status;
     210             : 
     211         528 :         status = dcerpc_winbind_SamLogon_r_recv(subreq, state);
     212         528 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     213           0 :                 status = NT_STATUS_NO_LOGON_SERVERS;
     214             :         }
     215         528 :         TALLOC_FREE(subreq);
     216         528 :         if (tevent_req_nterror(req, status)) {
     217         243 :                 return;
     218             :         }
     219             : 
     220         526 :         status = state->req.out.result;
     221         526 :         if (!NT_STATUS_IS_OK(status)) {
     222         239 :                 if (!state->req.out.authoritative) {
     223         170 :                         state->authoritative = false;
     224             :                 }
     225         239 :                 tevent_req_nterror(req, status);
     226         239 :                 return;
     227             :         }
     228             : 
     229         499 :         status = make_user_info_dc_netlogon_validation(state,
     230          75 :                                                       user_info->client.account_name,
     231         287 :                                                       state->req.in.validation_level,
     232         287 :                                                       &state->req.out.validation,
     233             :                                                       true, /* This user was authenticated */
     234             :                                                       &state->user_info_dc);
     235         287 :         if (tevent_req_nterror(req, status)) {
     236           0 :                 return;
     237             :         }
     238             : 
     239         287 :         nt4_domain = state->user_info_dc->info->domain_name;
     240         287 :         nt4_account = state->user_info_dc->info->account_name;
     241             : 
     242         287 :         if (lpcfg_is_mydomain(ctx->auth_ctx->lp_ctx, nt4_domain)) {
     243         123 :                 domain_dn = ldb_get_default_basedn(ctx->auth_ctx->sam_ctx);
     244             :         }
     245             : 
     246         287 :         if (domain_dn != NULL) {
     247             :                 /*
     248             :                  * At best, reset the badPwdCount to 0 if the account exists.
     249             :                  * This means that lockouts happen at a badPwdCount earlier than
     250             :                  * normal, but makes it more fault tolerant.
     251             :                  */
     252         123 :                 status = authsam_search_account(state, ctx->auth_ctx->sam_ctx,
     253             :                                                 nt4_account, domain_dn, &msg);
     254         123 :                 if (NT_STATUS_IS_OK(status)) {
     255         245 :                         status = authsam_logon_success_accounting(
     256         123 :                                 ctx->auth_ctx->sam_ctx, msg,
     257             :                                 domain_dn,
     258         123 :                                 user_info->flags & USER_INFO_INTERACTIVE_LOGON,
     259             :                                 NULL, NULL);
     260         123 :                         if (tevent_req_nterror(req, status)) {
     261           0 :                                 return;
     262             :                         }
     263             :                 }
     264             :         }
     265             : 
     266             :         /*
     267             :          * We need to expand group memberships within our local domain,
     268             :          * as the token might be generated by a trusted domain, unless we're
     269             :          * an RODC.
     270             :          */
     271         499 :         status = authsam_update_user_info_dc(state->user_info_dc,
     272         287 :                                              ctx->auth_ctx->sam_ctx,
     273             :                                              state->user_info_dc);
     274         287 :         if (tevent_req_nterror(req, status)) {
     275           0 :                 return;
     276             :         }
     277             : 
     278         287 :         tevent_req_done(req);
     279             : }
     280             : 
     281         528 : static NTSTATUS winbind_check_password_recv(struct tevent_req *req,
     282             :                                             TALLOC_CTX *mem_ctx,
     283             :                                             struct auth_user_info_dc **user_info_dc,
     284             :                                             bool *pauthoritative)
     285             : {
     286         399 :         struct winbind_check_password_state *state =
     287         528 :                 tevent_req_data(req,
     288             :                 struct winbind_check_password_state);
     289         528 :         NTSTATUS status = NT_STATUS_OK;
     290             : 
     291         528 :         *pauthoritative = state->authoritative;
     292             : 
     293         528 :         if (tevent_req_is_nterror(req, &status)) {
     294         241 :                 tevent_req_received(req);
     295         241 :                 return status;
     296             :         }
     297             : 
     298         287 :         *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
     299             : 
     300         287 :         tevent_req_received(req);
     301         287 :         return NT_STATUS_OK;
     302             : }
     303             : 
     304             : static const struct auth_operations winbind_ops = {
     305             :         .name                   = "winbind",
     306             :         .want_check             = winbind_want_check,
     307             :         .check_password_send    = winbind_check_password_send,
     308             :         .check_password_recv    = winbind_check_password_recv
     309             : };
     310             : 
     311        3776 : _PUBLIC_ NTSTATUS auth4_winbind_init(TALLOC_CTX *ctx)
     312             : {
     313             :         NTSTATUS ret;
     314             : 
     315        3776 :         ret = auth_register(ctx, &winbind_ops);
     316        3776 :         if (!NT_STATUS_IS_OK(ret)) {
     317           0 :                 DEBUG(0,("Failed to register 'winbind' auth backend!\n"));
     318           0 :                 return ret;
     319             :         }
     320             : 
     321        3776 :         return NT_STATUS_OK;
     322             : }

Generated by: LCOV version 1.13