netapi: let NetGroupAdd_l and NetGroupDel_l call the remote functions.
[samba.git] / source / lib / netapi / group.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi Group Support
4  *  Copyright (C) Guenther Deschner 2008
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
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "lib/netapi/libnetapi.h"
26
27 /****************************************************************
28 ****************************************************************/
29
30 WERROR NetGroupAdd_r(struct libnetapi_ctx *ctx,
31                      struct NetGroupAdd *r)
32 {
33         struct cli_state *cli = NULL;
34         struct rpc_pipe_client *pipe_cli = NULL;
35         NTSTATUS status;
36         WERROR werr;
37         uint32_t resume_handle = 0;
38         uint32_t num_entries = 0;
39         POLICY_HND connect_handle, domain_handle, group_handle;
40         struct samr_SamArray *sam = NULL;
41         const char *domain_name = NULL;
42         struct lsa_String lsa_domain_name, lsa_group_name;
43         struct dom_sid2 *domain_sid = NULL;
44         uint32_t rid = 0;
45         bool domain_found = true;
46         int i;
47         struct GROUP_INFO_0 *info0;
48         struct GROUP_INFO_1 *info1;
49         struct GROUP_INFO_2 *info2;
50         struct GROUP_INFO_3 *info3;
51         union samr_GroupInfo info;
52
53         ZERO_STRUCT(connect_handle);
54         ZERO_STRUCT(domain_handle);
55         ZERO_STRUCT(group_handle);
56
57         if (!r->in.buf) {
58                 return WERR_INVALID_PARAM;
59         }
60
61         switch (r->in.level) {
62                 case 0:
63                         info0 = (struct GROUP_INFO_0 *)r->in.buf;
64                         break;
65                 case 1:
66                         info1 = (struct GROUP_INFO_1 *)r->in.buf;
67                         break;
68                 case 2:
69                         info2 = (struct GROUP_INFO_2 *)r->in.buf;
70                         break;
71                 case 3:
72                         info3 = (struct GROUP_INFO_3 *)r->in.buf;
73                         break;
74                 default:
75                         werr = WERR_UNKNOWN_LEVEL;
76                         goto done;
77         }
78
79         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
80         if (!W_ERROR_IS_OK(werr)) {
81                 goto done;
82         }
83
84         werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli);
85         if (!W_ERROR_IS_OK(werr)) {
86                 goto done;
87         }
88
89         status = rpccli_try_samr_connects(pipe_cli, ctx,
90                                           SAMR_ACCESS_ENUM_DOMAINS |
91                                           SAMR_ACCESS_OPEN_DOMAIN,
92                                           &connect_handle);
93         if (!NT_STATUS_IS_OK(status)) {
94                 werr = ntstatus_to_werror(status);
95                 goto done;
96         }
97
98         status = rpccli_samr_EnumDomains(pipe_cli, ctx,
99                                          &connect_handle,
100                                          &resume_handle,
101                                          &sam,
102                                          0xffffffff,
103                                          &num_entries);
104         if (!NT_STATUS_IS_OK(status)) {
105                 werr = ntstatus_to_werror(status);
106                 goto done;
107         }
108
109         for (i=0; i<num_entries; i++) {
110
111                 domain_name = sam->entries[i].name.string;
112
113                 if (strequal(domain_name, builtin_domain_name())) {
114                         continue;
115                 }
116
117                 domain_found = true;
118                 break;
119         }
120
121         if (!domain_found) {
122                 werr = WERR_NO_SUCH_DOMAIN;
123                 goto done;
124         }
125
126         init_lsa_String(&lsa_domain_name, domain_name);
127
128         status = rpccli_samr_LookupDomain(pipe_cli, ctx,
129                                           &connect_handle,
130                                           &lsa_domain_name,
131                                           &domain_sid);
132         if (!NT_STATUS_IS_OK(status)) {
133                 werr = ntstatus_to_werror(status);
134                 goto done;
135         }
136
137         status = rpccli_samr_OpenDomain(pipe_cli, ctx,
138                                         &connect_handle,
139                                         SAMR_DOMAIN_ACCESS_CREATE_GROUP |
140                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
141                                         domain_sid,
142                                         &domain_handle);
143         if (!NT_STATUS_IS_OK(status)) {
144                 werr = ntstatus_to_werror(status);
145                 goto done;
146         }
147
148         switch (r->in.level) {
149                 case 0:
150                         init_lsa_String(&lsa_group_name, info0->grpi0_name);
151                         break;
152                 case 1:
153                         init_lsa_String(&lsa_group_name, info1->grpi1_name);
154                         break;
155                 case 2:
156                         init_lsa_String(&lsa_group_name, info2->grpi2_name);
157                         break;
158                 case 3:
159                         init_lsa_String(&lsa_group_name, info3->grpi3_name);
160                         break;
161         }
162
163         status = rpccli_samr_CreateDomainGroup(pipe_cli, ctx,
164                                                &domain_handle,
165                                                &lsa_group_name,
166                                                SEC_STD_DELETE |
167                                                SAMR_GROUP_ACCESS_SET_INFO,
168                                                &group_handle,
169                                                &rid);
170
171         if (!NT_STATUS_IS_OK(status)) {
172                 werr = ntstatus_to_werror(status);
173                 goto done;
174         }
175
176         switch (r->in.level) {
177                 case 1:
178                         if (info1->grpi1_comment) {
179                                 init_lsa_String(&info.description,
180                                                 info1->grpi1_comment);
181
182                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
183                                                                   &group_handle,
184                                                                   GROUPINFODESCRIPTION,
185                                                                   &info);
186                         }
187                         break;
188                 case 2:
189                         if (info2->grpi2_comment) {
190                                 init_lsa_String(&info.description,
191                                                 info2->grpi2_comment);
192
193                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
194                                                                   &group_handle,
195                                                                   GROUPINFODESCRIPTION,
196                                                                   &info);
197                                 if (!NT_STATUS_IS_OK(status)) {
198                                         werr = ntstatus_to_werror(status);
199                                         goto failed;
200                                 }
201                         }
202
203                         if (info2->grpi2_attributes != 0) {
204                                 info.attributes.attributes = info2->grpi2_attributes;
205                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
206                                                                   &group_handle,
207                                                                   GROUPINFOATTRIBUTES,
208                                                                   &info);
209
210                         }
211                         break;
212                 case 3:
213                         if (info3->grpi3_comment) {
214                                 init_lsa_String(&info.description,
215                                                 info3->grpi3_comment);
216
217                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
218                                                                   &group_handle,
219                                                                   GROUPINFODESCRIPTION,
220                                                                   &info);
221                                 if (!NT_STATUS_IS_OK(status)) {
222                                         werr = ntstatus_to_werror(status);
223                                         goto failed;
224                                 }
225                         }
226
227                         if (info3->grpi3_attributes != 0) {
228                                 info.attributes.attributes = info3->grpi3_attributes;
229                                 status = rpccli_samr_SetGroupInfo(pipe_cli, ctx,
230                                                                   &group_handle,
231                                                                   GROUPINFOATTRIBUTES,
232                                                                   &info);
233                         }
234                         break;
235                 default:
236                         break;
237         }
238
239         if (!NT_STATUS_IS_OK(status)) {
240                 werr = ntstatus_to_werror(status);
241                 goto failed;
242         }
243
244         werr = WERR_OK;
245         goto done;
246
247  failed:
248         rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
249                                       &group_handle);
250
251  done:
252         if (!cli) {
253                 return werr;
254         }
255
256         if (is_valid_policy_hnd(&group_handle)) {
257                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
258         }
259         if (is_valid_policy_hnd(&domain_handle)) {
260                 rpccli_samr_Close(pipe_cli, ctx, &domain_handle);
261         }
262         if (is_valid_policy_hnd(&connect_handle)) {
263                 rpccli_samr_Close(pipe_cli, ctx, &connect_handle);
264         }
265
266         return werr;
267 }
268
269 /****************************************************************
270 ****************************************************************/
271
272 WERROR NetGroupAdd_l(struct libnetapi_ctx *ctx,
273                      struct NetGroupAdd *r)
274 {
275         return NetGroupAdd_r(ctx, r);
276 }
277
278 /****************************************************************
279 ****************************************************************/
280
281 WERROR NetGroupDel_r(struct libnetapi_ctx *ctx,
282                      struct NetGroupDel *r)
283 {
284         struct cli_state *cli = NULL;
285         struct rpc_pipe_client *pipe_cli = NULL;
286         NTSTATUS status;
287         WERROR werr;
288         uint32_t resume_handle = 0;
289         uint32_t num_entries = 0;
290         POLICY_HND connect_handle, domain_handle, group_handle;
291         struct samr_SamArray *sam = NULL;
292         const char *domain_name = NULL;
293         struct lsa_String lsa_domain_name, lsa_group_name;
294         struct dom_sid2 *domain_sid = NULL;
295         bool domain_found = true;
296         int i;
297
298         struct samr_Ids rids;
299         struct samr_Ids types;
300         union samr_GroupInfo *info = NULL;
301         struct samr_RidTypeArray *rid_array = NULL;
302
303         ZERO_STRUCT(connect_handle);
304         ZERO_STRUCT(domain_handle);
305         ZERO_STRUCT(group_handle);
306
307         if (!r->in.group_name) {
308                 return WERR_INVALID_PARAM;
309         }
310
311         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
312         if (!W_ERROR_IS_OK(werr)) {
313                 goto done;
314         }
315
316         werr = libnetapi_open_pipe(ctx, cli, PI_SAMR, &pipe_cli);
317         if (!W_ERROR_IS_OK(werr)) {
318                 goto done;
319         }
320
321         status = rpccli_try_samr_connects(pipe_cli, ctx,
322                                           SAMR_ACCESS_ENUM_DOMAINS |
323                                           SAMR_ACCESS_OPEN_DOMAIN,
324                                           &connect_handle);
325         if (!NT_STATUS_IS_OK(status)) {
326                 werr = ntstatus_to_werror(status);
327                 goto done;
328         }
329
330         status = rpccli_samr_EnumDomains(pipe_cli, ctx,
331                                          &connect_handle,
332                                          &resume_handle,
333                                          &sam,
334                                          0xffffffff,
335                                          &num_entries);
336         if (!NT_STATUS_IS_OK(status)) {
337                 werr = ntstatus_to_werror(status);
338                 goto done;
339         }
340
341         for (i=0; i<num_entries; i++) {
342
343                 domain_name = sam->entries[i].name.string;
344
345                 if (strequal(domain_name, builtin_domain_name())) {
346                         continue;
347                 }
348
349                 domain_found = true;
350                 break;
351         }
352
353         if (!domain_found) {
354                 werr = WERR_NO_SUCH_DOMAIN;
355                 goto done;
356         }
357
358         init_lsa_String(&lsa_domain_name, domain_name);
359
360         status = rpccli_samr_LookupDomain(pipe_cli, ctx,
361                                           &connect_handle,
362                                           &lsa_domain_name,
363                                           &domain_sid);
364         if (!NT_STATUS_IS_OK(status)) {
365                 werr = ntstatus_to_werror(status);
366                 goto done;
367         }
368
369         status = rpccli_samr_OpenDomain(pipe_cli, ctx,
370                                         &connect_handle,
371                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
372                                         domain_sid,
373                                         &domain_handle);
374         if (!NT_STATUS_IS_OK(status)) {
375                 werr = ntstatus_to_werror(status);
376                 goto done;
377         }
378
379         init_lsa_String(&lsa_group_name, r->in.group_name);
380
381         status = rpccli_samr_LookupNames(pipe_cli, ctx,
382                                          &domain_handle,
383                                          1,
384                                          &lsa_group_name,
385                                          &rids,
386                                          &types);
387         if (!NT_STATUS_IS_OK(status)) {
388                 werr = ntstatus_to_werror(status);
389                 goto done;
390         }
391
392         if (types.ids[0] != SID_NAME_DOM_GRP) {
393                 werr = WERR_INVALID_DATATYPE;
394                 goto done;
395         }
396
397         status = rpccli_samr_OpenGroup(pipe_cli, ctx,
398                                        &domain_handle,
399                                        SEC_STD_DELETE |
400                                        SAMR_GROUP_ACCESS_GET_MEMBERS |
401                                        SAMR_GROUP_ACCESS_REMOVE_MEMBER |
402                                        SAMR_GROUP_ACCESS_ADD_MEMBER |
403                                        SAMR_GROUP_ACCESS_LOOKUP_INFO,
404                                        rids.ids[0],
405                                        &group_handle);
406         if (!NT_STATUS_IS_OK(status)) {
407                 werr = ntstatus_to_werror(status);
408                 goto done;
409         }
410
411         status = rpccli_samr_QueryGroupInfo(pipe_cli, ctx,
412                                             &group_handle,
413                                             GROUPINFOATTRIBUTES,
414                                             &info);
415         if (!NT_STATUS_IS_OK(status)) {
416                 werr = ntstatus_to_werror(status);
417                 goto done;
418         }
419
420         if (!(info->attributes.attributes & SE_GROUP_ENABLED)) {
421                 werr = WERR_ACCESS_DENIED;
422                 goto done;
423         }
424
425         status = rpccli_samr_QueryGroupMember(pipe_cli, ctx,
426                                               &group_handle,
427                                               &rid_array);
428         if (!NT_STATUS_IS_OK(status)) {
429                 werr = ntstatus_to_werror(status);
430                 goto done;
431         }
432
433         {
434         struct lsa_Strings names;
435         struct samr_Ids member_types;
436
437         status = rpccli_samr_LookupRids(pipe_cli, ctx,
438                                         &domain_handle,
439                                         rid_array->count,
440                                         rid_array->rids,
441                                         &names,
442                                         &member_types);
443         if (!NT_STATUS_IS_OK(status)) {
444                 werr = ntstatus_to_werror(status);
445                 goto done;
446         }
447         }
448
449         for (i=0; i < rid_array->count; i++) {
450
451                 status = rpccli_samr_DeleteGroupMember(pipe_cli, ctx,
452                                                        &group_handle,
453                                                        rid_array->rids[i]);
454                 if (!NT_STATUS_IS_OK(status)) {
455                         werr = ntstatus_to_werror(status);
456                         goto done;
457                 }
458         }
459
460         status = rpccli_samr_DeleteDomainGroup(pipe_cli, ctx,
461                                                &group_handle);
462         if (!NT_STATUS_IS_OK(status)) {
463                 werr = ntstatus_to_werror(status);
464                 goto done;
465         }
466
467         ZERO_STRUCT(group_handle);
468
469         werr = WERR_OK;
470
471  done:
472         if (!cli) {
473                 return werr;
474         }
475
476         if (is_valid_policy_hnd(&group_handle)) {
477                 rpccli_samr_Close(pipe_cli, ctx, &group_handle);
478         }
479         if (is_valid_policy_hnd(&domain_handle)) {
480                 rpccli_samr_Close(pipe_cli, ctx, &domain_handle);
481         }
482         if (is_valid_policy_hnd(&connect_handle)) {
483                 rpccli_samr_Close(pipe_cli, ctx, &connect_handle);
484         }
485
486         return werr;
487 }
488
489 /****************************************************************
490 ****************************************************************/
491
492 WERROR NetGroupDel_l(struct libnetapi_ctx *ctx,
493                      struct NetGroupDel *r)
494 {
495         return NetGroupDel_r(ctx, r);
496 }