LCOV - code coverage report
Current view: top level - source4/auth/ntlm - auth_winbind.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 123 143 86.0 %
Date: 2024-02-28 12:06:22 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Winbind authentication mechanism
       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        1142 : 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        1142 :         if (!user_info->mapped.account_name || !*user_info->mapped.account_name) {
      48          14 :                 return NT_STATUS_NOT_IMPLEMENTED;
      49             :         }
      50             : 
      51             :         /* TODO: maybe limit the user scope to remote users only */
      52        1128 :         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        1128 : 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        1128 :         struct tevent_req *req = NULL;
      75        1128 :         struct winbind_check_password_state *state = NULL;
      76           6 :         NTSTATUS status;
      77           6 :         struct dcerpc_binding_handle *irpc_handle;
      78           6 :         const struct auth_usersupplied_info *user_info_new;
      79           6 :         struct netr_IdentityInfo *identity_info;
      80           6 :         struct imessaging_context *msg_ctx;
      81        1128 :         struct tevent_req *subreq = NULL;
      82             : 
      83        1128 :         req = tevent_req_create(mem_ctx, &state,
      84             :                                 struct winbind_check_password_state);
      85        1128 :         if (req == NULL) {
      86           0 :                 return NULL;
      87             :         }
      88        1128 :         state->ctx = ctx;
      89        1128 :         state->user_info = user_info;
      90        1128 :         state->authoritative = true;
      91             : 
      92        1128 :         msg_ctx = imessaging_client_init(state, ctx->auth_ctx->lp_ctx, ev);
      93        1128 :         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        1128 :         irpc_handle = irpc_binding_handle_by_name(state, msg_ctx,
     100             :                                                   "winbind_server",
     101             :                                                   &ndr_table_winbind);
     102        1128 :         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        1128 :         dcerpc_binding_handle_set_timeout(irpc_handle, 120);
     119             : 
     120        1128 :         if (user_info->flags & USER_INFO_INTERACTIVE_LOGON) {
     121           0 :                 struct netr_PasswordInfo *password_info;
     122             : 
     123         120 :                 status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_HASH,
     124             :                                            user_info, &user_info_new);
     125         120 :                 if (tevent_req_nterror(req, status)) {
     126           0 :                         return tevent_req_post(req, ev);
     127             :                 }
     128         120 :                 user_info = user_info_new;
     129             : 
     130         120 :                 password_info = talloc_zero(state, struct netr_PasswordInfo);
     131         120 :                 if (tevent_req_nomem(password_info, req)) {
     132           0 :                         return tevent_req_post(req, ev);
     133             :                 }
     134             : 
     135         120 :                 password_info->lmpassword = *user_info->password.hash.lanman;
     136         120 :                 password_info->ntpassword = *user_info->password.hash.nt;
     137             : 
     138         120 :                 identity_info = &password_info->identity_info;
     139         120 :                 state->req.in.logon_level    = 1;
     140         120 :                 state->req.in.logon.password= password_info;
     141             :         } else {
     142           6 :                 struct netr_NetworkInfo *network_info;
     143           6 :                 uint8_t chal[8];
     144             : 
     145        1008 :                 status = encrypt_user_info(state, ctx->auth_ctx, AUTH_PASSWORD_RESPONSE,
     146             :                                            user_info, &user_info_new);
     147        1008 :                 if (tevent_req_nterror(req, status)) {
     148           0 :                         return tevent_req_post(req, ev);
     149             :                 }
     150        1008 :                 user_info = user_info_new;
     151             : 
     152        1008 :                 network_info = talloc_zero(state, struct netr_NetworkInfo);
     153        1008 :                 if (tevent_req_nomem(network_info, req)) {
     154           0 :                         return tevent_req_post(req, ev);
     155             :                 }
     156             : 
     157        1008 :                 status = auth_get_challenge(ctx->auth_ctx, chal);
     158        1008 :                 if (tevent_req_nterror(req, status)) {
     159           0 :                         return tevent_req_post(req, ev);
     160             :                 }
     161             : 
     162        1008 :                 memcpy(network_info->challenge, chal, sizeof(network_info->challenge));
     163             : 
     164        1008 :                 network_info->nt.length = user_info->password.response.nt.length;
     165        1008 :                 network_info->nt.data        = user_info->password.response.nt.data;
     166             : 
     167        1008 :                 network_info->lm.length = user_info->password.response.lanman.length;
     168        1008 :                 network_info->lm.data        = user_info->password.response.lanman.data;
     169             : 
     170        1008 :                 identity_info = &network_info->identity_info;
     171        1008 :                 state->req.in.logon_level    = 2;
     172        1008 :                 state->req.in.logon.network = network_info;
     173             :         }
     174             : 
     175        1128 :         identity_info->domain_name.string    = user_info->client.domain_name;
     176        1128 :         identity_info->parameter_control     = user_info->logon_parameters; /* see MSV1_0_* */
     177        1128 :         identity_info->logon_id                      = user_info->logon_id;
     178        1128 :         identity_info->account_name.string   = user_info->client.account_name;
     179        1128 :         identity_info->workstation.string    = user_info->workstation_name;
     180             : 
     181        1128 :         state->req.in.validation_level = 6;
     182             : 
     183        1128 :         subreq = dcerpc_winbind_SamLogon_r_send(state, ev, irpc_handle,
     184        1122 :                                                 &state->req);
     185        1128 :         if (tevent_req_nomem(subreq, req)) {
     186           0 :                 return tevent_req_post(req, ev);
     187             :         }
     188        1128 :         tevent_req_set_callback(subreq,
     189             :                                 winbind_check_password_done,
     190             :                                 req);
     191             : 
     192        1128 :         return req;
     193             : }
     194             : 
     195        1128 : static void winbind_check_password_done(struct tevent_req *subreq)
     196             : {
     197           6 :         struct tevent_req *req =
     198        1128 :                 tevent_req_callback_data(subreq,
     199             :                 struct tevent_req);
     200           6 :         struct winbind_check_password_state *state =
     201        1128 :                 tevent_req_data(req,
     202             :                 struct winbind_check_password_state);
     203        1128 :         struct auth_method_context *ctx = state->ctx;
     204        1128 :         const struct auth_usersupplied_info *user_info = state->user_info;
     205        1128 :         struct ldb_dn *domain_dn = NULL;
     206        1128 :         const char *nt4_domain = NULL;
     207        1128 :         const char *nt4_account = NULL;
     208        1128 :         struct ldb_message *msg = NULL;
     209           6 :         NTSTATUS status;
     210             : 
     211        1128 :         status = dcerpc_winbind_SamLogon_r_recv(subreq, state);
     212        1128 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     213           0 :                 status = NT_STATUS_NO_LOGON_SERVERS;
     214             :         }
     215        1128 :         TALLOC_FREE(subreq);
     216        1128 :         if (tevent_req_nterror(req, status)) {
     217         839 :                 return;
     218             :         }
     219             : 
     220        1126 :         status = state->req.out.result;
     221        1126 :         if (!NT_STATUS_IS_OK(status)) {
     222         837 :                 if (!state->req.out.authoritative) {
     223         768 :                         state->authoritative = false;
     224             :                 }
     225         837 :                 tevent_req_nterror(req, status);
     226         837 :                 return;
     227             :         }
     228             : 
     229         289 :         status = make_user_info_dc_netlogon_validation(state,
     230         289 :                                                       user_info->client.account_name,
     231         289 :                                                       state->req.in.validation_level,
     232         289 :                                                       &state->req.out.validation,
     233             :                                                       true, /* This user was authenticated */
     234             :                                                       &state->user_info_dc);
     235         289 :         if (tevent_req_nterror(req, status)) {
     236           0 :                 return;
     237             :         }
     238             : 
     239         289 :         nt4_domain = state->user_info_dc->info->domain_name;
     240         289 :         nt4_account = state->user_info_dc->info->account_name;
     241             : 
     242         289 :         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         289 :         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         123 :                         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         289 :         status = authsam_update_user_info_dc(state->user_info_dc,
     272         289 :                                              ctx->auth_ctx->sam_ctx,
     273             :                                              state->user_info_dc);
     274         289 :         if (tevent_req_nterror(req, status)) {
     275           0 :                 return;
     276             :         }
     277             : 
     278         289 :         tevent_req_done(req);
     279             : }
     280             : 
     281        1128 : 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             :                                             const struct authn_audit_info **client_audit_info,
     285             :                                             const struct authn_audit_info **server_audit_info,
     286             :                                             bool *pauthoritative)
     287             : {
     288           6 :         struct winbind_check_password_state *state =
     289        1128 :                 tevent_req_data(req,
     290             :                 struct winbind_check_password_state);
     291        1128 :         NTSTATUS status = NT_STATUS_OK;
     292             : 
     293        1128 :         *pauthoritative = state->authoritative;
     294        1128 :         *client_audit_info = NULL;
     295        1128 :         *server_audit_info = NULL;
     296             : 
     297        1128 :         if (tevent_req_is_nterror(req, &status)) {
     298         839 :                 tevent_req_received(req);
     299         839 :                 return status;
     300             :         }
     301             : 
     302         289 :         *user_info_dc = talloc_move(mem_ctx, &state->user_info_dc);
     303             : 
     304         289 :         tevent_req_received(req);
     305         289 :         return NT_STATUS_OK;
     306             : }
     307             : 
     308             : static const struct auth_operations winbind_ops = {
     309             :         .name                   = "winbind",
     310             :         .want_check             = winbind_want_check,
     311             :         .check_password_send    = winbind_check_password_send,
     312             :         .check_password_recv    = winbind_check_password_recv
     313             : };
     314             : 
     315        9500 : _PUBLIC_ NTSTATUS auth4_winbind_init(TALLOC_CTX *ctx)
     316             : {
     317         837 :         NTSTATUS ret;
     318             : 
     319        9500 :         ret = auth_register(ctx, &winbind_ops);
     320        9500 :         if (!NT_STATUS_IS_OK(ret)) {
     321           0 :                 DEBUG(0,("Failed to register 'winbind' auth backend!\n"));
     322           0 :                 return ret;
     323             :         }
     324             : 
     325        9500 :         return NT_STATUS_OK;
     326             : }

Generated by: LCOV version 1.14