Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async getgrsid
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/ndr_winbind_c.h"
23 : #include "../libcli/security/security.h"
24 : #include "lib/dbwrap/dbwrap_rbt.h"
25 :
26 : struct wb_getgrsid_state {
27 : struct tevent_context *ev;
28 : struct dom_sid sid;
29 : int max_nesting;
30 : const char *domname;
31 : const char *name;
32 : enum lsa_SidType type;
33 : gid_t gid;
34 : struct db_context *members;
35 : };
36 :
37 : static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq);
38 : static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq);
39 : static void wb_getgrsid_got_members(struct tevent_req *subreq);
40 :
41 2904 : struct tevent_req *wb_getgrsid_send(TALLOC_CTX *mem_ctx,
42 : struct tevent_context *ev,
43 : const struct dom_sid *group_sid,
44 : int max_nesting)
45 : {
46 : struct tevent_req *req, *subreq;
47 : struct wb_getgrsid_state *state;
48 : struct dom_sid_buf buf;
49 :
50 2904 : req = tevent_req_create(mem_ctx, &state, struct wb_getgrsid_state);
51 2904 : if (req == NULL) {
52 0 : return NULL;
53 : }
54 :
55 2904 : D_INFO("WB command getgrsid start.\nLooking up group SID %s.\n", dom_sid_str_buf(group_sid, &buf));
56 :
57 2904 : sid_copy(&state->sid, group_sid);
58 2904 : state->ev = ev;
59 2904 : state->max_nesting = max_nesting;
60 :
61 2904 : if (dom_sid_in_domain(&global_sid_Unix_Groups, group_sid)) {
62 : /* unmapped Unix groups must be resolved locally */
63 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
64 0 : return tevent_req_post(req, ev);
65 : }
66 :
67 2904 : subreq = wb_lookupsid_send(state, ev, &state->sid);
68 2904 : if (tevent_req_nomem(subreq, req)) {
69 0 : return tevent_req_post(req, ev);
70 : }
71 2904 : tevent_req_set_callback(subreq, wb_getgrsid_lookupsid_done, req);
72 2904 : return req;
73 : }
74 :
75 2904 : static void wb_getgrsid_lookupsid_done(struct tevent_req *subreq)
76 : {
77 2904 : struct tevent_req *req = tevent_req_callback_data(
78 : subreq, struct tevent_req);
79 2904 : struct wb_getgrsid_state *state = tevent_req_data(
80 : req, struct wb_getgrsid_state);
81 : NTSTATUS status;
82 :
83 2904 : status = wb_lookupsid_recv(subreq, state, &state->type,
84 : &state->domname, &state->name);
85 2904 : TALLOC_FREE(subreq);
86 2904 : if (tevent_req_nterror(req, status)) {
87 0 : return;
88 : }
89 :
90 2904 : switch (state->type) {
91 2904 : case SID_NAME_DOM_GRP:
92 : case SID_NAME_ALIAS:
93 : case SID_NAME_WKN_GRP:
94 : /*
95 : * also treat user-type SIDS (they might map to ID_TYPE_BOTH)
96 : */
97 : case SID_NAME_USER:
98 : case SID_NAME_COMPUTER:
99 2904 : break;
100 0 : default:
101 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
102 0 : return;
103 : }
104 :
105 2904 : subreq = wb_sids2xids_send(state, state->ev, &state->sid, 1);
106 2904 : if (tevent_req_nomem(subreq, req)) {
107 0 : return;
108 : }
109 2904 : tevent_req_set_callback(subreq, wb_getgrsid_sid2gid_done, req);
110 : }
111 :
112 2904 : static void wb_getgrsid_sid2gid_done(struct tevent_req *subreq)
113 : {
114 2904 : struct tevent_req *req = tevent_req_callback_data(
115 : subreq, struct tevent_req);
116 2904 : struct wb_getgrsid_state *state = tevent_req_data(
117 : req, struct wb_getgrsid_state);
118 : NTSTATUS status;
119 : struct unixid xids[1];
120 :
121 2904 : status = wb_sids2xids_recv(subreq, xids, ARRAY_SIZE(xids));
122 2904 : TALLOC_FREE(subreq);
123 2904 : if (tevent_req_nterror(req, status)) {
124 10 : return;
125 : }
126 :
127 : /*
128 : * We are filtering further down in sids2xids, but that filtering
129 : * depends on the actual type of the sid handed in (as determined
130 : * by lookupsids). Here we need to filter for the type of object
131 : * actually requested, in this case uid.
132 : */
133 2904 : if (!(xids[0].type == ID_TYPE_GID || xids[0].type == ID_TYPE_BOTH)) {
134 2 : tevent_req_nterror(req, NT_STATUS_NONE_MAPPED);
135 2 : return;
136 : }
137 :
138 2902 : state->gid = (gid_t)xids[0].id;
139 :
140 2902 : if (state->type == SID_NAME_USER || state->type == SID_NAME_COMPUTER) {
141 : /*
142 : * special treatment for a user sid that is
143 : * mapped to ID_TYPE_BOTH:
144 : * create a group with the sid/xid as only member
145 : */
146 : const char *name;
147 :
148 8 : if (xids[0].type != ID_TYPE_BOTH) {
149 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
150 0 : return;
151 : }
152 :
153 8 : state->members = db_open_rbt(state);
154 8 : if (tevent_req_nomem(state->members, req)) {
155 0 : return;
156 : }
157 :
158 8 : name = fill_domain_username_talloc(talloc_tos(),
159 : state->domname,
160 : state->name,
161 : true /* can_assume */);
162 8 : if (tevent_req_nomem(name, req)) {
163 0 : return;
164 : }
165 :
166 8 : status = add_member_to_db(state->members, &state->sid, name);
167 8 : if (!NT_STATUS_IS_OK(status)) {
168 0 : tevent_req_nterror(req, status);
169 0 : return;
170 : }
171 :
172 8 : tevent_req_done(req);
173 8 : return;
174 : }
175 :
176 : /*
177 : * the "regular" case of a group type sid.
178 : */
179 :
180 2894 : subreq = wb_group_members_send(state, state->ev, &state->sid,
181 : state->type, state->max_nesting);
182 2894 : if (tevent_req_nomem(subreq, req)) {
183 0 : return;
184 : }
185 2894 : tevent_req_set_callback(subreq, wb_getgrsid_got_members, req);
186 : }
187 :
188 2894 : static void wb_getgrsid_got_members(struct tevent_req *subreq)
189 : {
190 2894 : struct tevent_req *req = tevent_req_callback_data(
191 : subreq, struct tevent_req);
192 2894 : struct wb_getgrsid_state *state = tevent_req_data(
193 : req, struct wb_getgrsid_state);
194 : NTSTATUS status;
195 :
196 2894 : status = wb_group_members_recv(subreq, state, &state->members);
197 2894 : TALLOC_FREE(subreq);
198 2894 : if (tevent_req_nterror(req, status)) {
199 0 : return;
200 : }
201 2894 : tevent_req_done(req);
202 : }
203 :
204 2904 : NTSTATUS wb_getgrsid_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
205 : const char **domname, const char **name, gid_t *gid,
206 : struct db_context **members)
207 : {
208 2904 : struct wb_getgrsid_state *state = tevent_req_data(
209 : req, struct wb_getgrsid_state);
210 : NTSTATUS status;
211 :
212 2904 : D_INFO("WB command getgrsid end.\n");
213 2904 : if (tevent_req_is_nterror(req, &status)) {
214 2 : D_WARNING("Failed with %s.\n", nt_errstr(status));
215 2 : return status;
216 : }
217 2902 : *domname = talloc_move(mem_ctx, &state->domname);
218 2902 : *name = talloc_move(mem_ctx, &state->name);
219 2902 : *gid = state->gid;
220 2902 : *members = talloc_move(mem_ctx, &state->members);
221 2902 : return NT_STATUS_OK;
222 : }
|