s3:winbind: Convert WINBINDD_LIST_GROUPS to the new API
[sfrench/samba-autobuild/.git] / source3 / winbindd / wb_sid2uid.c
1 /*
2    Unix SMB/CIFS implementation.
3    async sid2uid
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 "winbindd.h"
22 #include "librpc/gen_ndr/cli_wbint.h"
23
24 struct wb_sid2uid_state {
25         struct tevent_context *ev;
26         struct dom_sid sid;
27         char *dom_name;
28         uint64 uid64;
29         uid_t uid;
30 };
31
32 static void wb_sid2uid_lookup_done(struct tevent_req *subreq);
33 static void wb_sid2uid_done(struct tevent_req *subreq);
34
35 struct tevent_req *wb_sid2uid_send(TALLOC_CTX *mem_ctx,
36                                    struct tevent_context *ev,
37                                    const struct dom_sid *sid)
38 {
39         struct tevent_req *req, *subreq;
40         struct wb_sid2uid_state *state;
41         bool expired;
42
43         req = tevent_req_create(mem_ctx, &state, struct wb_sid2uid_state);
44         if (req == NULL) {
45                 return NULL;
46         }
47         sid_copy(&state->sid, sid);
48         state->ev = ev;
49
50         if (winbindd_use_idmap_cache()
51             && idmap_cache_find_sid2uid(sid, &state->uid, &expired)) {
52
53                 DEBUG(10, ("idmap_cache_find_sid2uid found %d%s\n",
54                            (int)state->uid, expired ? " (expired)": ""));
55
56                 if (!expired || IS_DOMAIN_OFFLINE(find_our_domain())) {
57                         if (state->uid == -1) {
58                                 tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
59                         } else {
60                                 tevent_req_done(req);
61                         }
62                         return tevent_req_post(req, ev);
63                 }
64         }
65
66         /*
67          * We need to make sure the sid is of the right type to not flood
68          * idmap with wrong entries
69          */
70
71         subreq = wb_lookupsid_send(state, ev, &state->sid);
72         if (tevent_req_nomem(subreq, req)) {
73                 return tevent_req_post(req, ev);
74         }
75         tevent_req_set_callback(subreq, wb_sid2uid_lookup_done, req);
76         return req;
77 }
78
79 static void wb_sid2uid_lookup_done(struct tevent_req *subreq)
80 {
81         struct tevent_req *req = tevent_req_callback_data(
82                 subreq, struct tevent_req);
83         struct wb_sid2uid_state *state = tevent_req_data(
84                 req, struct wb_sid2uid_state);
85         struct winbindd_domain *domain;
86         const char *domname;
87         const char *name;
88         enum lsa_SidType type;
89         NTSTATUS status;
90         struct winbindd_child *child;
91
92         status = wb_lookupsid_recv(subreq, talloc_tos(), &type, &domname,
93                                    &name);
94         if (!NT_STATUS_IS_OK(status)) {
95                 tevent_req_nterror(req, status);
96                 return;
97         }
98
99         if ((type != SID_NAME_USER) && (type != SID_NAME_COMPUTER)) {
100                 DEBUG(5, ("Sid %s is not a user or a computer.\n",
101                           sid_string_dbg(&state->sid)));
102                 /*
103                  * We have to set the cache ourselves here, the child
104                  * which is normally responsible was not queried yet.
105                  */
106                 idmap_cache_set_sid2uid(&state->sid, -1);
107                 tevent_req_nterror(req, NT_STATUS_INVALID_SID);
108                 return;
109         }
110
111         domain = find_domain_from_sid_noinit(&state->sid);
112
113         /*
114          * TODO: Issue a gettrustinfo here in case we don't have "domain" yet?
115          */
116
117         if ((domain != NULL) && domain->have_idmap_config) {
118                 state->dom_name = domain->name;
119         } else {
120                 state->dom_name = NULL;
121         }
122
123         child = idmap_child();
124
125         subreq = rpccli_wbint_Sid2Uid_send(state, state->ev, child->rpccli,
126                                            state->dom_name, &state->sid,
127                                            &state->uid64);
128         if (tevent_req_nomem(subreq, req)) {
129                 return;
130         }
131         tevent_req_set_callback(subreq, wb_sid2uid_done, req);
132 }
133
134 static void wb_sid2uid_done(struct tevent_req *subreq)
135 {
136         struct tevent_req *req = tevent_req_callback_data(
137                 subreq, struct tevent_req);
138         struct wb_sid2uid_state *state = tevent_req_data(
139                 req, struct wb_sid2uid_state);
140         NTSTATUS status, result;
141
142         status = rpccli_wbint_Sid2Uid_recv(subreq, state, &result);
143         TALLOC_FREE(subreq);
144         if (!NT_STATUS_IS_OK(status)) {
145                 tevent_req_nterror(req, status);
146                 return;
147         }
148         if (!NT_STATUS_IS_OK(result)) {
149                 tevent_req_nterror(req, result);
150                 return;
151         }
152
153         state->uid = state->uid64;
154         tevent_req_done(req);
155 }
156
157 NTSTATUS wb_sid2uid_recv(struct tevent_req *req, uid_t *uid)
158 {
159         struct wb_sid2uid_state *state = tevent_req_data(
160                 req, struct wb_sid2uid_state);
161         NTSTATUS status;
162
163         if (tevent_req_is_nterror(req, &status)) {
164                 return status;
165         }
166         *uid = state->uid;
167         return NT_STATUS_OK;
168 }