LCOV - code coverage report
Current view: top level - source3/winbindd - wb_queryuser.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 164 249 65.9 %
Date: 2024-05-31 13:13:24 Functions: 8 9 88.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    async queryuser
       4             :    Copyright (C) Volker Lendecke 2009
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "util/debug.h"
      22             : #include "winbindd.h"
      23             : #include "librpc/gen_ndr/ndr_winbind_c.h"
      24             : #include "../libcli/security/security.h"
      25             : #include "libsmb/samlogon_cache.h"
      26             : #include "librpc/gen_ndr/ndr_winbind.h"
      27             : 
      28             : struct wb_queryuser_state {
      29             :         struct tevent_context *ev;
      30             :         struct wbint_userinfo *info;
      31             :         const struct wb_parent_idmap_config *idmap_cfg;
      32             :         bool tried_dclookup;
      33             : };
      34             : 
      35             : static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq);
      36             : static void wb_queryuser_got_uid(struct tevent_req *subreq);
      37             : static void wb_queryuser_got_domain(struct tevent_req *subreq);
      38             : static void wb_queryuser_got_dc(struct tevent_req *subreq);
      39             : static void wb_queryuser_got_gid(struct tevent_req *subreq);
      40             : static void wb_queryuser_got_group_name(struct tevent_req *subreq);
      41             : static void wb_queryuser_done(struct tevent_req *subreq);
      42             : 
      43       91096 : struct tevent_req *wb_queryuser_send(TALLOC_CTX *mem_ctx,
      44             :                                      struct tevent_context *ev,
      45             :                                      const struct dom_sid *user_sid)
      46             : {
      47           0 :         struct tevent_req *req, *subreq;
      48           0 :         struct wb_queryuser_state *state;
      49           0 :         struct wbint_userinfo *info;
      50           0 :         struct dom_sid_buf buf;
      51             : 
      52       91096 :         req = tevent_req_create(mem_ctx, &state, struct wb_queryuser_state);
      53       91096 :         if (req == NULL) {
      54           0 :                 return NULL;
      55             :         }
      56       91096 :         D_INFO("WB command queryuser start.\nQuery user sid %s\n",
      57             :                dom_sid_str_buf(user_sid, &buf));
      58       91096 :         state->ev = ev;
      59             : 
      60       91096 :         state->info = talloc_zero(state, struct wbint_userinfo);
      61       91096 :         if (tevent_req_nomem(state->info, req)) {
      62           0 :                 return tevent_req_post(req, ev);
      63             :         }
      64       91096 :         info = state->info;
      65             : 
      66       91096 :         info->primary_gid = (gid_t)-1;
      67             : 
      68       91096 :         sid_copy(&info->user_sid, user_sid);
      69             : 
      70       91096 :         subreq = wb_parent_idmap_setup_send(state, state->ev);
      71       91096 :         if (tevent_req_nomem(subreq, req)) {
      72           0 :                 return tevent_req_post(req, ev);
      73             :         }
      74       91096 :         tevent_req_set_callback(subreq, wb_queryuser_idmap_setup_done, req);
      75       91096 :         return req;
      76             : }
      77             : 
      78       91096 : static void wb_queryuser_idmap_setup_done(struct tevent_req *subreq)
      79             : {
      80       91096 :         struct tevent_req *req = tevent_req_callback_data(
      81             :                 subreq, struct tevent_req);
      82       91096 :         struct wb_queryuser_state *state = tevent_req_data(
      83             :                 req, struct wb_queryuser_state);
      84           0 :         NTSTATUS status;
      85           0 :         struct dom_sid_buf buf;
      86             : 
      87       91096 :         status = wb_parent_idmap_setup_recv(subreq, &state->idmap_cfg);
      88       91096 :         TALLOC_FREE(subreq);
      89       91096 :         if (tevent_req_nterror(req, status)) {
      90           0 :                 D_WARNING("wb_parent_idmap_setup_recv() failed with %s.\n",
      91             :                           nt_errstr(status));
      92           0 :                 return;
      93             :         }
      94             : 
      95       91096 :         D_DEBUG("Convert the user SID %s to XID.\n",
      96             :                 dom_sid_str_buf(&state->info->user_sid, &buf));
      97       91096 :         subreq = wb_sids2xids_send(
      98       91096 :                 state, state->ev, &state->info->user_sid, 1);
      99       91096 :         if (tevent_req_nomem(subreq, req)) {
     100           0 :                 return;
     101             :         }
     102       91096 :         tevent_req_set_callback(subreq, wb_queryuser_got_uid, req);
     103       91096 :         return;
     104             : }
     105             : 
     106       91096 : static void wb_queryuser_got_uid(struct tevent_req *subreq)
     107             : {
     108       91096 :         struct tevent_req *req = tevent_req_callback_data(
     109             :                 subreq, struct tevent_req);
     110       91096 :         struct wb_queryuser_state *state = tevent_req_data(
     111             :                 req, struct wb_queryuser_state);
     112       91096 :         struct wbint_userinfo *info = state->info;
     113           0 :         struct netr_SamInfo3 *info3;
     114       91096 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     115           0 :         struct unixid xid;
     116       91096 :         uint32_t user_rid = 0;
     117           0 :         NTSTATUS status;
     118           0 :         struct dom_sid_buf buf, buf1;
     119             : 
     120       91096 :         status = wb_sids2xids_recv(subreq, &xid, 1);
     121       91096 :         TALLOC_FREE(subreq);
     122       91096 :         if (tevent_req_nterror(req, status)) {
     123           0 :                 D_WARNING("wb_sids2xids_recv() failed with %s.\n",
     124             :                           nt_errstr(status));
     125        7778 :                 return;
     126             :         }
     127             : 
     128       91096 :         if ((xid.type != ID_TYPE_UID) && (xid.type != ID_TYPE_BOTH)) {
     129          48 :                 D_WARNING("XID type is %d, should be ID_TYPE_UID or ID_TYPE_BOTH.\n",
     130             :                           xid.type);
     131          48 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     132          48 :                 return;
     133             :         }
     134             : 
     135       91048 :         D_DEBUG("Received XID %"PRIu32" for SID %s.\n",
     136             :                 xid.id,
     137             :                 dom_sid_str_buf(&info->user_sid, &buf1));
     138       91048 :         info->uid = xid.id;
     139             : 
     140             :         /*
     141             :          * Default the group sid to "Domain Users" in the user's
     142             :          * domain. The samlogon cache or the query_user call later on
     143             :          * can override this.
     144             :          * TODO: There is still missing functionality to set the correct group
     145             :          * sid using samlogon cache (needs to use S4USelf).
     146             :          * Once this is done, remove the workaround in test_membership_user() in
     147             :          * source4/torture/local/nss_tests.c
     148             :          */
     149       91048 :         sid_copy(&info->group_sid, &info->user_sid);
     150       91048 :         sid_split_rid(&info->group_sid, &user_rid);
     151       91048 :         sid_append_rid(&info->group_sid,
     152       91048 :                        user_rid == DOMAIN_RID_GUEST ? DOMAIN_RID_GUESTS
     153             :                                                     : DOMAIN_RID_USERS);
     154             : 
     155       91048 :         D_DEBUG("Preconfigured 'Domain Users' RID %u was used to create group SID %s from user SID %s.\n",
     156             :                 DOMAIN_RID_USERS,
     157             :                 dom_sid_str_buf(&info->group_sid, &buf),
     158             :                 dom_sid_str_buf(&info->user_sid, &buf1));
     159             : 
     160       91048 :         info->homedir = talloc_strdup(info, lp_template_homedir());
     161       91048 :         D_DEBUG("Setting 'homedir' to the template '%s'.\n", info->homedir);
     162       91048 :         if (tevent_req_nomem(info->homedir, req)) {
     163           0 :                 return;
     164             :         }
     165             : 
     166       91048 :         info->shell = talloc_strdup(info, lp_template_shell());
     167       91048 :         D_DEBUG("Setting 'shell' to the template '%s'.\n", info->shell);
     168       91048 :         if (tevent_req_nomem(info->shell, req)) {
     169           0 :                 return;
     170             :         }
     171             : 
     172       91048 :         info3 = netsamlogon_cache_get(state, &info->user_sid);
     173       91048 :         if (info3 != NULL) {
     174       83318 :                 D_DEBUG("Filling data received from netsamlogon_cache\n");
     175       83318 :                 sid_compose(&info->group_sid, info3->base.domain_sid,
     176             :                             info3->base.primary_gid);
     177       83318 :                 info->acct_name = talloc_move(
     178             :                         info, &info3->base.account_name.string);
     179       83318 :                 info->full_name = talloc_move(
     180             :                         info, &info3->base.full_name.string);
     181             : 
     182       83318 :                 info->domain_name = talloc_move(
     183             :                         state, &info3->base.logon_domain.string);
     184             : 
     185       83318 :                 TALLOC_FREE(info3);
     186             :         }
     187             : 
     188       91048 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info);
     189       91048 :         if (info->domain_name == NULL) {
     190        7730 :                 D_DEBUG("Domain name is empty, calling wb_lookupsid_send() to get it.\n");
     191        7730 :                 subreq = wb_lookupsid_send(state, state->ev, &info->user_sid);
     192        7730 :                 if (tevent_req_nomem(subreq, req)) {
     193           0 :                         return;
     194             :                 }
     195        7730 :                 tevent_req_set_callback(subreq, wb_queryuser_got_domain, req);
     196        7730 :                 return;
     197             :         }
     198             : 
     199             :         /*
     200             :          * Note wb_sids2xids_send/recv was called before,
     201             :          * so we're sure that wb_parent_idmap_setup_send/recv
     202             :          * was already called.
     203             :          */
     204       83318 :         child_binding_handle = idmap_child_handle();
     205       83318 :         D_DEBUG("Domain name is set, calling dcerpc_wbint_GetNssInfo_send()\n");
     206       83318 :         subreq = dcerpc_wbint_GetNssInfo_send(
     207             :                 state, state->ev, child_binding_handle, info);
     208       83318 :         if (tevent_req_nomem(subreq, req)) {
     209           0 :                 return;
     210             :         }
     211       83318 :         tevent_req_set_callback(subreq, wb_queryuser_done, req);
     212             : }
     213             : 
     214        7730 : static void wb_queryuser_got_domain(struct tevent_req *subreq)
     215             : {
     216        7730 :         struct tevent_req *req = tevent_req_callback_data(
     217             :                 subreq, struct tevent_req);
     218        7730 :         struct wb_queryuser_state *state = tevent_req_data(
     219             :                 req, struct wb_queryuser_state);
     220        7730 :         struct wbint_userinfo *info = state->info;
     221           0 :         enum lsa_SidType type;
     222        7730 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     223           0 :         NTSTATUS status;
     224             : 
     225        7730 :         status = wb_lookupsid_recv(subreq, state, &type,
     226             :                                    &info->domain_name, &info->acct_name);
     227        7730 :         TALLOC_FREE(subreq);
     228        7730 :         if (tevent_req_nterror(req, status)) {
     229           0 :                 D_WARNING("wb_lookupsid_recv failed with %s.\n",
     230             :                           nt_errstr(status));
     231           0 :                 return;
     232             :         }
     233             : 
     234        7730 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info);
     235        7730 :         switch (type) {
     236        7722 :         case SID_NAME_USER:
     237             :         case SID_NAME_COMPUTER:
     238             :                 /*
     239             :                  * user case: we only need the account name from lookup_sids
     240             :                  */
     241        7722 :                 break;
     242           8 :         case SID_NAME_DOM_GRP:
     243             :         case SID_NAME_ALIAS:
     244             :         case SID_NAME_WKN_GRP:
     245             :                 /*
     246             :                  * also treat group-type SIDs (they might map to ID_TYPE_BOTH)
     247             :                  */
     248           8 :                 sid_copy(&info->group_sid, &info->user_sid);
     249           8 :                 break;
     250           0 :         default:
     251           0 :                 D_WARNING("Unknown type:%d, return NT_STATUS_NO_SUCH_USER.\n",
     252             :                           type);
     253           0 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     254           0 :                 return;
     255             :         }
     256             : 
     257             :         /*
     258             :          * Note wb_sids2xids_send/recv was called before,
     259             :          * so we're sure that wb_parent_idmap_setup_send/recv
     260             :          * was already called.
     261             :          */
     262        7730 :         child_binding_handle = idmap_child_handle();
     263        7730 :         D_DEBUG("About to call dcerpc_wbint_GetNssInfo_send()\n");
     264        7730 :         subreq = dcerpc_wbint_GetNssInfo_send(
     265             :                 state, state->ev, child_binding_handle, info);
     266        7730 :         if (tevent_req_nomem(subreq, req)) {
     267           0 :                 return;
     268             :         }
     269        7730 :         tevent_req_set_callback(subreq, wb_queryuser_done, req);
     270             : }
     271             : 
     272       91048 : static void wb_queryuser_done(struct tevent_req *subreq)
     273             : {
     274       91048 :         struct tevent_req *req = tevent_req_callback_data(
     275             :                 subreq, struct tevent_req);
     276       91048 :         struct wb_queryuser_state *state = tevent_req_data(
     277             :                 req, struct wb_queryuser_state);
     278       91048 :         struct wbint_userinfo *info = state->info;
     279           0 :         NTSTATUS status, result;
     280       91048 :         bool need_group_name = false;
     281       91048 :         const char *tmpl = NULL;
     282             : 
     283       91048 :         status = dcerpc_wbint_GetNssInfo_recv(subreq, info, &result);
     284       91048 :         TALLOC_FREE(subreq);
     285       91048 :         if (tevent_req_nterror(req, status)) {
     286           0 :                 D_WARNING("GetNssInfo failed with %s.\n", nt_errstr(status));
     287       91046 :                 return;
     288             :         }
     289             : 
     290       91048 :         if (NT_STATUS_EQUAL(result, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND) &&
     291           0 :             !state->tried_dclookup) {
     292           0 :                 D_DEBUG("GetNssInfo got DOMAIN_CONTROLLER_NOT_FOUND, calling wb_dsgetdcname_send()\n");
     293           0 :                 subreq = wb_dsgetdcname_send(
     294           0 :                         state, state->ev, state->info->domain_name, NULL, NULL,
     295             :                         DS_RETURN_DNS_NAME);
     296           0 :                 if (tevent_req_nomem(subreq, req)) {
     297           0 :                         return;
     298             :                 }
     299           0 :                 tevent_req_set_callback(subreq, wb_queryuser_got_dc, req);
     300           0 :                 return;
     301             :         }
     302             : 
     303             :         /*
     304             :          * Ignore failure in "result" here. We'll try to fill in stuff
     305             :          * that misses further down.
     306             :          */
     307             : 
     308       91048 :         if (state->info->primary_gid == (gid_t)-1) {
     309       91046 :                 D_DEBUG("Calling wb_sids2xids_send() to resolve primary gid.\n");
     310       91046 :                 subreq = wb_sids2xids_send(
     311       91046 :                         state, state->ev, &info->group_sid, 1);
     312       91046 :                 if (tevent_req_nomem(subreq, req)) {
     313           0 :                         return;
     314             :                 }
     315       91046 :                 tevent_req_set_callback(subreq, wb_queryuser_got_gid, req);
     316       91046 :                 return;
     317             :         }
     318             : 
     319           2 :         tmpl = lp_template_homedir();
     320           2 :         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
     321           0 :                 need_group_name = true;
     322             :         }
     323           2 :         tmpl = lp_template_shell();
     324           2 :         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
     325           0 :                 need_group_name = true;
     326             :         }
     327             : 
     328           2 :         if (need_group_name && state->info->primary_group_name == NULL) {
     329           0 :                 D_DEBUG("Calling wb_lookupsid_send() to resolve primary group name.\n");
     330           0 :                 subreq = wb_lookupsid_send(state, state->ev, &info->group_sid);
     331           0 :                 if (tevent_req_nomem(subreq, req)) {
     332           0 :                         return;
     333             :                 }
     334           0 :                 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
     335             :                                         req);
     336           0 :                 return;
     337             :         }
     338             : 
     339           2 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info);
     340           2 :         tevent_req_done(req);
     341             : }
     342             : 
     343           0 : static void wb_queryuser_got_dc(struct tevent_req *subreq)
     344             : {
     345           0 :         struct tevent_req *req = tevent_req_callback_data(
     346             :                 subreq, struct tevent_req);
     347           0 :         struct wb_queryuser_state *state = tevent_req_data(
     348             :                 req, struct wb_queryuser_state);
     349           0 :         struct wbint_userinfo *info = state->info;
     350           0 :         struct netr_DsRGetDCNameInfo *dcinfo;
     351           0 :         struct dcerpc_binding_handle *child_binding_handle = NULL;
     352           0 :         NTSTATUS status;
     353             : 
     354           0 :         status = wb_dsgetdcname_recv(subreq, state, &dcinfo);
     355           0 :         TALLOC_FREE(subreq);
     356           0 :         if (tevent_req_nterror(req, status)) {
     357           0 :                 D_WARNING("wb_dsgetdcname_recv() failed with %s.\n",
     358             :                           nt_errstr(status));
     359           0 :                 return;
     360             :         }
     361             : 
     362           0 :         state->tried_dclookup = true;
     363             : 
     364           0 :         D_DEBUG("Got DC name, calling wb_dsgetdcname_gencache_set().\n");
     365           0 :         status = wb_dsgetdcname_gencache_set(info->domain_name, dcinfo);
     366           0 :         if (tevent_req_nterror(req, status)) {
     367           0 :                 D_WARNING("wb_dsgetdcname_gencache_set() failed with %s.\n",
     368             :                           nt_errstr(status));
     369           0 :                 return;
     370             :         }
     371           0 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info);
     372             : 
     373             :         /*
     374             :          * Note wb_sids2xids_send/recv was called before,
     375             :          * so we're sure that wb_parent_idmap_setup_send/recv
     376             :          * was already called.
     377             :          */
     378           0 :         child_binding_handle = idmap_child_handle();
     379           0 :         subreq = dcerpc_wbint_GetNssInfo_send(
     380             :                 state, state->ev, child_binding_handle, info);
     381           0 :         if (tevent_req_nomem(subreq, req)) {
     382           0 :                 return;
     383             :         }
     384           0 :         tevent_req_set_callback(subreq, wb_queryuser_done, req);
     385             : }
     386             : 
     387       91046 : static void wb_queryuser_got_gid(struct tevent_req *subreq)
     388             : {
     389       91046 :         struct tevent_req *req = tevent_req_callback_data(
     390             :                 subreq, struct tevent_req);
     391       91046 :         struct wb_queryuser_state *state = tevent_req_data(
     392             :                 req, struct wb_queryuser_state);
     393           0 :         struct unixid xid;
     394           0 :         NTSTATUS status;
     395       91046 :         bool need_group_name = false;
     396       91046 :         const char *tmpl = NULL;
     397           0 :         struct dom_sid_buf buf;
     398             : 
     399       91046 :         status = wb_sids2xids_recv(subreq, &xid, 1);
     400       91046 :         TALLOC_FREE(subreq);
     401       91046 :         if (tevent_req_nterror(req, status)) {
     402           0 :                 D_WARNING("wb_sids2xids_recv() failed with %s.\n",
     403             :                           nt_errstr(status));
     404        2092 :                 return;
     405             :         }
     406             : 
     407       91046 :         D_DEBUG("Got XID %"PRIu32" with type %d.\n", xid.id, xid.type);
     408       91046 :         if ((xid.type != ID_TYPE_GID) && (xid.type != ID_TYPE_BOTH)) {
     409         108 :                 D_WARNING("Returning NT_STATUS_NO_SUCH_USER\n"
     410             :                           "xid.type must be ID_TYPE_UID or ID_TYPE_BOTH.\n");
     411         108 :                 tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
     412         108 :                 return;
     413             :         }
     414             : 
     415       90938 :         state->info->primary_gid = xid.id;
     416             : 
     417       90938 :         tmpl = lp_template_homedir();
     418       90938 :         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
     419        1984 :                 need_group_name = true;
     420             :         }
     421       90938 :         tmpl = lp_template_shell();
     422       90938 :         if(strstr_m(tmpl, "%g") || strstr_m(tmpl, "%G")) {
     423           0 :                 need_group_name = true;
     424             :         }
     425             : 
     426       90938 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_DEBUG, wbint_userinfo, state->info);
     427             : 
     428       90938 :         if (need_group_name && state->info->primary_group_name == NULL) {
     429        1984 :                 D_DEBUG("Calling wb_lookupsid_send for group SID %s.\n",
     430             :                           dom_sid_str_buf(&state->info->group_sid, &buf));
     431        1984 :                 subreq = wb_lookupsid_send(state, state->ev,
     432        1984 :                                            &state->info->group_sid);
     433        1984 :                 if (tevent_req_nomem(subreq, req)) {
     434           0 :                         return;
     435             :                 }
     436        1984 :                 tevent_req_set_callback(subreq, wb_queryuser_got_group_name,
     437             :                                         req);
     438        1984 :                 return;
     439             :         }
     440             : 
     441       88954 :         D_DEBUG("No need to lookup primary group name. Request is done!\n");
     442       88954 :         tevent_req_done(req);
     443             : }
     444             : 
     445        1984 : static void wb_queryuser_got_group_name(struct tevent_req *subreq)
     446             : {
     447        1984 :         struct tevent_req *req = tevent_req_callback_data(
     448             :                 subreq, struct tevent_req);
     449        1984 :         struct wb_queryuser_state *state = tevent_req_data(
     450             :                 req, struct wb_queryuser_state);
     451           0 :         enum lsa_SidType type;
     452           0 :         NTSTATUS status;
     453           0 :         const char *domain_name;
     454             : 
     455        1984 :         status = wb_lookupsid_recv(subreq, state->info, &type, &domain_name,
     456        1984 :                                    &state->info->primary_group_name);
     457        1984 :         TALLOC_FREE(subreq);
     458        1984 :         if (tevent_req_nterror(req, status)) {
     459           0 :                 D_WARNING("wb_lookupsid_recv() failed with %s.\n",
     460             :                           nt_errstr(status));
     461           0 :                 return;
     462             :         }
     463        1984 :         tevent_req_done(req);
     464             : }
     465             : 
     466       91096 : NTSTATUS wb_queryuser_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     467             :                            struct wbint_userinfo **pinfo)
     468             : {
     469       91096 :         struct wb_queryuser_state *state = tevent_req_data(
     470             :                 req, struct wb_queryuser_state);
     471           0 :         NTSTATUS status;
     472             : 
     473       91096 :         D_INFO("WB command queryuser end.\n");
     474       91096 :         NDR_PRINT_DEBUG_LEVEL(DBGLVL_INFO, wbint_userinfo, state->info);
     475       91096 :         if (tevent_req_is_nterror(req, &status)) {
     476         156 :                 return status;
     477             :         }
     478       90940 :         *pinfo = talloc_move(mem_ctx, &state->info);
     479       90940 :         return NT_STATUS_OK;
     480             : }

Generated by: LCOV version 1.14