Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : async implementation of WINBINDD_GETGRNAM
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 "libcli/security/dom_sid.h"
23 : #include "lib/util/string_wrappers.h"
24 :
25 : struct winbindd_getgrnam_state {
26 : struct tevent_context *ev;
27 : char *name_namespace;
28 : char *name_domain;
29 : char *name_group;
30 : struct dom_sid sid;
31 : const char *domname;
32 : const char *name;
33 : gid_t gid;
34 : struct db_context *members;
35 : };
36 :
37 : static void winbindd_getgrnam_lookupname_done(struct tevent_req *subreq);
38 : static void winbindd_getgrnam_done(struct tevent_req *subreq);
39 :
40 2130 : struct tevent_req *winbindd_getgrnam_send(TALLOC_CTX *mem_ctx,
41 : struct tevent_context *ev,
42 : struct winbindd_cli_state *cli,
43 : struct winbindd_request *request)
44 : {
45 0 : struct tevent_req *req, *subreq;
46 0 : struct winbindd_getgrnam_state *state;
47 0 : char *tmp;
48 0 : NTSTATUS nt_status;
49 0 : bool ok;
50 :
51 2130 : req = tevent_req_create(mem_ctx, &state,
52 : struct winbindd_getgrnam_state);
53 2130 : if (req == NULL) {
54 0 : return NULL;
55 : }
56 2130 : state->ev = ev;
57 :
58 : /* Ensure null termination */
59 2130 : request->data.groupname[sizeof(request->data.groupname)-1]='\0';
60 :
61 2130 : D_NOTICE("[%s (%u)] Winbind external command GETGRNAM start.\n"
62 : "Searching group name '%s'.\n",
63 : cli->client_name,
64 : (unsigned int)cli->pid,
65 : request->data.groupname);
66 :
67 2130 : nt_status = normalize_name_unmap(state, request->data.groupname, &tmp);
68 : /* If we didn't map anything in the above call, just reset the
69 : tmp pointer to the original string */
70 2130 : if (!NT_STATUS_IS_OK(nt_status) &&
71 2130 : !NT_STATUS_EQUAL(nt_status, NT_STATUS_FILE_RENAMED))
72 : {
73 2130 : tmp = request->data.groupname;
74 : }
75 :
76 : /* Parse domain and groupname */
77 :
78 2130 : ok = parse_domain_user(state, tmp,
79 2130 : &state->name_namespace,
80 2130 : &state->name_domain,
81 2130 : &state->name_group);
82 2130 : if (!ok) {
83 0 : DBG_INFO("Could not parse domain user: %s\n", tmp);
84 0 : tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
85 0 : return tevent_req_post(req, ev);
86 : }
87 :
88 : /* if no domain or our local domain and no local tdb group, default to
89 : * our local domain for aliases */
90 :
91 2130 : if ( !*(state->name_domain) || strequal(state->name_domain,
92 : get_global_sam_name()) ) {
93 320 : TALLOC_FREE(state->name_domain);
94 320 : state->name_domain = talloc_strdup(state,
95 : get_global_sam_name());
96 320 : if (tevent_req_nomem(state->name_domain, req)) {
97 0 : return tevent_req_post(req, ev);
98 : }
99 : }
100 :
101 2130 : subreq = wb_lookupname_send(state, ev,
102 2130 : state->name_namespace,
103 2130 : state->name_domain,
104 2130 : state->name_group,
105 : 0);
106 2130 : if (tevent_req_nomem(subreq, req)) {
107 0 : return tevent_req_post(req, ev);
108 : }
109 2130 : tevent_req_set_callback(subreq, winbindd_getgrnam_lookupname_done,
110 : req);
111 2130 : return req;
112 : }
113 :
114 2130 : static void winbindd_getgrnam_lookupname_done(struct tevent_req *subreq)
115 : {
116 2130 : struct tevent_req *req = tevent_req_callback_data(
117 : subreq, struct tevent_req);
118 2130 : struct winbindd_getgrnam_state *state = tevent_req_data(
119 : req, struct winbindd_getgrnam_state);
120 0 : enum lsa_SidType type;
121 0 : NTSTATUS status;
122 :
123 2130 : status = wb_lookupname_recv(subreq, &state->sid, &type);
124 2130 : TALLOC_FREE(subreq);
125 2130 : if (tevent_req_nterror(req, status)) {
126 318 : return;
127 : }
128 :
129 1812 : switch (type) {
130 1812 : case SID_NAME_DOM_GRP:
131 : case SID_NAME_ALIAS:
132 : case SID_NAME_WKN_GRP:
133 : /*
134 : * Also give user types a chance:
135 : * These might be user sids mapped to the ID_TYPE_BOTH,
136 : * and in that case we should construct a group struct.
137 : */
138 : case SID_NAME_USER:
139 : case SID_NAME_COMPUTER:
140 1812 : break;
141 0 : default:
142 0 : tevent_req_nterror(req, NT_STATUS_NO_SUCH_GROUP);
143 0 : return;
144 : }
145 :
146 1812 : subreq = wb_getgrsid_send(state, state->ev, &state->sid,
147 : lp_winbind_expand_groups());
148 1812 : if (tevent_req_nomem(subreq, req)) {
149 0 : return;
150 : }
151 1812 : tevent_req_set_callback(subreq, winbindd_getgrnam_done, req);
152 : }
153 :
154 1812 : static void winbindd_getgrnam_done(struct tevent_req *subreq)
155 : {
156 1812 : struct tevent_req *req = tevent_req_callback_data(
157 : subreq, struct tevent_req);
158 1812 : struct winbindd_getgrnam_state *state = tevent_req_data(
159 : req, struct winbindd_getgrnam_state);
160 0 : NTSTATUS status;
161 :
162 1812 : status = wb_getgrsid_recv(subreq, state, &state->domname, &state->name,
163 : &state->gid, &state->members);
164 1812 : TALLOC_FREE(subreq);
165 1812 : if (tevent_req_nterror(req, status)) {
166 0 : return;
167 : }
168 1812 : tevent_req_done(req);
169 : }
170 :
171 2130 : NTSTATUS winbindd_getgrnam_recv(struct tevent_req *req,
172 : struct winbindd_response *response)
173 : {
174 2130 : struct winbindd_getgrnam_state *state = tevent_req_data(
175 : req, struct winbindd_getgrnam_state);
176 0 : NTSTATUS status;
177 0 : int num_members;
178 0 : char *buf;
179 :
180 2130 : if (tevent_req_is_nterror(req, &status)) {
181 0 : struct dom_sid_buf sidbuf;
182 318 : D_WARNING("Could not convert sid %s: %s\n",
183 : dom_sid_str_buf(&state->sid, &sidbuf),
184 : nt_errstr(status));
185 318 : return status;
186 : }
187 :
188 1812 : if (!fill_grent(talloc_tos(), &response->data.gr, state->domname,
189 : state->name, state->gid)) {
190 0 : D_WARNING("fill_grent failed\n");
191 0 : return NT_STATUS_NO_MEMORY;
192 : }
193 :
194 1812 : status = winbindd_print_groupmembers(state->members, response,
195 : &num_members, &buf);
196 1812 : if (!NT_STATUS_IS_OK(status)) {
197 0 : return status;
198 : }
199 :
200 1812 : response->data.gr.num_gr_mem = (uint32_t)num_members;
201 :
202 : /* Group membership lives at start of extra data */
203 :
204 1812 : response->data.gr.gr_mem_ofs = 0;
205 1812 : response->extra_data.data = buf;
206 1812 : response->length += talloc_get_size(response->extra_data.data);
207 :
208 1812 : D_NOTICE("Winbind external command GETGRNAM end.\n"
209 : "Returning %"PRIu32" member(s).\n",
210 : response->data.gr.num_gr_mem);
211 :
212 1812 : return NT_STATUS_OK;
213 : }
|