Fix some warnings due to uint16_t!=-1 always being true
[ira/wip.git] / source3 / utils / net_rpc.c
1 /*
2    Samba Unix/Linux SMB client library
3    Distributed SMB/CIFS Server Management Utility
4    Copyright (C) 2001 Andrew Bartlett (abartlet@samba.org)
5    Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
6    Copyright (C) 2004,2008 Guenther Deschner (gd@samba.org)
7    Copyright (C) 2005 Jeremy Allison (jra@samba.org)
8    Copyright (C) 2006 Jelmer Vernooij (jelmer@samba.org)
9
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 3 of the License, or
13    (at your option) any later version.
14
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
23 #include "includes.h"
24 #include "utils/net.h"
25 #include "../libcli/auth/libcli_auth.h"
26
27 static int net_mode_share;
28 static bool sync_files(struct copy_clistate *cp_clistate, const char *mask);
29
30 /**
31  * @file net_rpc.c
32  *
33  * @brief RPC based subcommands for the 'net' utility.
34  *
35  * This file should contain much of the functionality that used to
36  * be found in rpcclient, execpt that the commands should change
37  * less often, and the fucntionality should be sane (the user is not
38  * expected to know a rid/sid before they conduct an operation etc.)
39  *
40  * @todo Perhaps eventually these should be split out into a number
41  * of files, as this could get quite big.
42  **/
43
44
45 /**
46  * Many of the RPC functions need the domain sid.  This function gets
47  *  it at the start of every run
48  *
49  * @param cli A cli_state already connected to the remote machine
50  *
51  * @return The Domain SID of the remote machine.
52  **/
53
54 NTSTATUS net_get_remote_domain_sid(struct cli_state *cli, TALLOC_CTX *mem_ctx,
55                                    DOM_SID **domain_sid,
56                                    const char **domain_name)
57 {
58         struct rpc_pipe_client *lsa_pipe = NULL;
59         struct policy_handle pol;
60         NTSTATUS result = NT_STATUS_OK;
61         union lsa_PolicyInformation *info = NULL;
62
63         result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
64                                           &lsa_pipe);
65         if (!NT_STATUS_IS_OK(result)) {
66                 d_fprintf(stderr, "Could not initialise lsa pipe\n");
67                 return result;
68         }
69
70         result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, false,
71                                      SEC_FLAG_MAXIMUM_ALLOWED,
72                                      &pol);
73         if (!NT_STATUS_IS_OK(result)) {
74                 d_fprintf(stderr, "open_policy failed: %s\n",
75                           nt_errstr(result));
76                 return result;
77         }
78
79         result = rpccli_lsa_QueryInfoPolicy(lsa_pipe, mem_ctx,
80                                             &pol,
81                                             LSA_POLICY_INFO_ACCOUNT_DOMAIN,
82                                             &info);
83         if (!NT_STATUS_IS_OK(result)) {
84                 d_fprintf(stderr, "lsaquery failed: %s\n",
85                           nt_errstr(result));
86                 return result;
87         }
88
89         *domain_name = info->account_domain.name.string;
90         *domain_sid = info->account_domain.sid;
91
92         rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol);
93         TALLOC_FREE(lsa_pipe);
94
95         return NT_STATUS_OK;
96 }
97
98 /**
99  * Run a single RPC command, from start to finish.
100  *
101  * @param pipe_name the pipe to connect to (usually a PIPE_ constant)
102  * @param conn_flag a NET_FLAG_ combination.  Passed to
103  *                   net_make_ipc_connection.
104  * @param argc  Standard main() style argc.
105  * @param argv  Standard main() style argv. Initial components are already
106  *              stripped.
107  * @return A shell status integer (0 for success).
108  */
109
110 int run_rpc_command(struct net_context *c,
111                         struct cli_state *cli_arg,
112                         const struct ndr_syntax_id *interface,
113                         int conn_flags,
114                         rpc_command_fn fn,
115                         int argc,
116                         const char **argv)
117 {
118         struct cli_state *cli = NULL;
119         struct rpc_pipe_client *pipe_hnd = NULL;
120         TALLOC_CTX *mem_ctx;
121         NTSTATUS nt_status;
122         DOM_SID *domain_sid;
123         const char *domain_name;
124         int ret = -1;
125
126         /* make use of cli_state handed over as an argument, if possible */
127         if (!cli_arg) {
128                 nt_status = net_make_ipc_connection(c, conn_flags, &cli);
129                 if (!NT_STATUS_IS_OK(nt_status)) {
130                         DEBUG(1, ("failed to make ipc connection: %s\n",
131                                   nt_errstr(nt_status)));
132                         return -1;
133                 }
134         } else {
135                 cli = cli_arg;
136         }
137
138         if (!cli) {
139                 return -1;
140         }
141
142         /* Create mem_ctx */
143
144         if (!(mem_ctx = talloc_init("run_rpc_command"))) {
145                 DEBUG(0, ("talloc_init() failed\n"));
146                 goto fail;
147         }
148
149         nt_status = net_get_remote_domain_sid(cli, mem_ctx, &domain_sid,
150                                               &domain_name);
151         if (!NT_STATUS_IS_OK(nt_status)) {
152                 goto fail;
153         }
154
155         if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
156                 if (lp_client_schannel()
157                     && (ndr_syntax_id_equal(interface,
158                                             &ndr_table_netlogon.syntax_id))) {
159                         /* Always try and create an schannel netlogon pipe. */
160                         nt_status = cli_rpc_pipe_open_schannel(
161                                 cli, interface,
162                                 PIPE_AUTH_LEVEL_PRIVACY, domain_name,
163                                 &pipe_hnd);
164                         if (!NT_STATUS_IS_OK(nt_status)) {
165                                 DEBUG(0, ("Could not initialise schannel netlogon pipe. Error was %s\n",
166                                         nt_errstr(nt_status) ));
167                                 goto fail;
168                         }
169                 } else {
170                         if (conn_flags & NET_FLAGS_SEAL) {
171                                 nt_status = cli_rpc_pipe_open_ntlmssp(
172                                         cli, interface,
173                                         PIPE_AUTH_LEVEL_PRIVACY,
174                                         lp_workgroup(), c->opt_user_name,
175                                         c->opt_password, &pipe_hnd);
176                         } else {
177                                 nt_status = cli_rpc_pipe_open_noauth(
178                                         cli, interface,
179                                         &pipe_hnd);
180                         }
181                         if (!NT_STATUS_IS_OK(nt_status)) {
182                                 DEBUG(0, ("Could not initialise pipe %s. Error was %s\n",
183                                         get_pipe_name_from_iface(interface),
184                                         nt_errstr(nt_status) ));
185                                 goto fail;
186                         }
187                 }
188         }
189
190         nt_status = fn(c, domain_sid, domain_name, cli, pipe_hnd, mem_ctx, argc, argv);
191
192         if (!NT_STATUS_IS_OK(nt_status)) {
193                 DEBUG(1, ("rpc command function failed! (%s)\n", nt_errstr(nt_status)));
194         } else {
195                 ret = 0;
196                 DEBUG(5, ("rpc command function succedded\n"));
197         }
198
199         if (!(conn_flags & NET_FLAGS_NO_PIPE)) {
200                 if (pipe_hnd) {
201                         TALLOC_FREE(pipe_hnd);
202                 }
203         }
204
205 fail:
206         /* close the connection only if it was opened here */
207         if (!cli_arg) {
208                 cli_shutdown(cli);
209         }
210
211         talloc_destroy(mem_ctx);
212         return ret;
213 }
214
215 /**
216  * Force a change of the trust acccount password.
217  *
218  * All parameters are provided by the run_rpc_command function, except for
219  * argc, argv which are passed through.
220  *
221  * @param domain_sid The domain sid acquired from the remote server.
222  * @param cli A cli_state connected to the server.
223  * @param mem_ctx Talloc context, destroyed on completion of the function.
224  * @param argc  Standard main() style argc.
225  * @param argv  Standard main() style argv. Initial components are already
226  *              stripped.
227  *
228  * @return Normal NTSTATUS return.
229  **/
230
231 static NTSTATUS rpc_changetrustpw_internals(struct net_context *c,
232                                         const DOM_SID *domain_sid,
233                                         const char *domain_name,
234                                         struct cli_state *cli,
235                                         struct rpc_pipe_client *pipe_hnd,
236                                         TALLOC_CTX *mem_ctx,
237                                         int argc,
238                                         const char **argv)
239 {
240
241         return trust_pw_find_change_and_store_it(pipe_hnd, mem_ctx, c->opt_target_workgroup);
242 }
243
244 /**
245  * Force a change of the trust acccount password.
246  *
247  * @param argc  Standard main() style argc.
248  * @param argv  Standard main() style argv. Initial components are already
249  *              stripped.
250  *
251  * @return A shell status integer (0 for success).
252  **/
253
254 int net_rpc_changetrustpw(struct net_context *c, int argc, const char **argv)
255 {
256         if (c->display_usage) {
257                 d_printf("Usage:\n"
258                          "net rpc changetrustpw\n"
259                          "    Change the machine trust password\n");
260                 return 0;
261         }
262
263         return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id,
264                                NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC,
265                                rpc_changetrustpw_internals,
266                                argc, argv);
267 }
268
269 /**
270  * Join a domain, the old way.
271  *
272  * This uses 'machinename' as the inital password, and changes it.
273  *
274  * The password should be created with 'server manager' or equiv first.
275  *
276  * All parameters are provided by the run_rpc_command function, except for
277  * argc, argv which are passed through.
278  *
279  * @param domain_sid The domain sid acquired from the remote server.
280  * @param cli A cli_state connected to the server.
281  * @param mem_ctx Talloc context, destroyed on completion of the function.
282  * @param argc  Standard main() style argc.
283  * @param argv  Standard main() style argv. Initial components are already
284  *              stripped.
285  *
286  * @return Normal NTSTATUS return.
287  **/
288
289 static NTSTATUS rpc_oldjoin_internals(struct net_context *c,
290                                         const DOM_SID *domain_sid,
291                                         const char *domain_name,
292                                         struct cli_state *cli,
293                                         struct rpc_pipe_client *pipe_hnd,
294                                         TALLOC_CTX *mem_ctx,
295                                         int argc,
296                                         const char **argv)
297 {
298
299         fstring trust_passwd;
300         unsigned char orig_trust_passwd_hash[16];
301         NTSTATUS result;
302         uint32 sec_channel_type;
303
304         result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id,
305                                           &pipe_hnd);
306         if (!NT_STATUS_IS_OK(result)) {
307                 DEBUG(0,("rpc_oldjoin_internals: netlogon pipe open to machine %s failed. "
308                         "error was %s\n",
309                         cli->desthost,
310                         nt_errstr(result) ));
311                 return result;
312         }
313
314         /*
315            check what type of join - if the user want's to join as
316            a BDC, the server must agree that we are a BDC.
317         */
318         if (argc >= 0) {
319                 sec_channel_type = get_sec_channel_type(argv[0]);
320         } else {
321                 sec_channel_type = get_sec_channel_type(NULL);
322         }
323
324         fstrcpy(trust_passwd, global_myname());
325         strlower_m(trust_passwd);
326
327         /*
328          * Machine names can be 15 characters, but the max length on
329          * a password is 14.  --jerry
330          */
331
332         trust_passwd[14] = '\0';
333
334         E_md4hash(trust_passwd, orig_trust_passwd_hash);
335
336         result = trust_pw_change_and_store_it(pipe_hnd, mem_ctx, c->opt_target_workgroup,
337                                               orig_trust_passwd_hash,
338                                               sec_channel_type);
339
340         if (NT_STATUS_IS_OK(result))
341                 printf("Joined domain %s.\n", c->opt_target_workgroup);
342
343
344         if (!secrets_store_domain_sid(c->opt_target_workgroup, domain_sid)) {
345                 DEBUG(0, ("error storing domain sid for %s\n", c->opt_target_workgroup));
346                 result = NT_STATUS_UNSUCCESSFUL;
347         }
348
349         return result;
350 }
351
352 /**
353  * Join a domain, the old way.
354  *
355  * @param argc  Standard main() style argc.
356  * @param argv  Standard main() style argv. Initial components are already
357  *              stripped.
358  *
359  * @return A shell status integer (0 for success).
360  **/
361
362 static int net_rpc_perform_oldjoin(struct net_context *c, int argc, const char **argv)
363 {
364         return run_rpc_command(c, NULL, &ndr_table_netlogon.syntax_id,
365                                NET_FLAGS_NO_PIPE | NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC,
366                                rpc_oldjoin_internals,
367                                argc, argv);
368 }
369
370 /**
371  * Join a domain, the old way.  This function exists to allow
372  * the message to be displayed when oldjoin was explicitly
373  * requested, but not when it was implied by "net rpc join".
374  *
375  * @param argc  Standard main() style argc.
376  * @param argv  Standard main() style argv. Initial components are already
377  *              stripped.
378  *
379  * @return A shell status integer (0 for success).
380  **/
381
382 static int net_rpc_oldjoin(struct net_context *c, int argc, const char **argv)
383 {
384         int rc = -1;
385
386         if (c->display_usage) {
387                 d_printf("Usage:\n"
388                          "net rpc oldjoin\n"
389                          "    Join a domain the old way\n");
390                 return 0;
391         }
392
393         rc = net_rpc_perform_oldjoin(c, argc, argv);
394
395         if (rc) {
396                 d_fprintf(stderr, "Failed to join domain\n");
397         }
398
399         return rc;
400 }
401
402 /**
403  * 'net rpc join' entrypoint.
404  * @param argc  Standard main() style argc.
405  * @param argv  Standard main() style argv. Initial components are already
406  *              stripped
407  *
408  * Main 'net_rpc_join()' (where the admin username/password is used) is
409  * in net_rpc_join.c.
410  * Try to just change the password, but if that doesn't work, use/prompt
411  * for a username/password.
412  **/
413
414 int net_rpc_join(struct net_context *c, int argc, const char **argv)
415 {
416         if (c->display_usage) {
417                 d_printf("Usage:\n"
418                          "net rpc join -U <username>[%%password] <type>\n"
419                          "  Join a domain\n"
420                          "    username\tName of the admin user"
421                          "    password\tPassword of the admin user, will "
422                          "prompt if not specified\n"
423                          "    type\tCan be one of the following:\n"
424                          "\t\tMEMBER\tJoin as member server (default)\n"
425                          "\t\tBDC\tJoin as BDC\n"
426                          "\t\tPDC\tJoin as PDC\n");
427                 return 0;
428         }
429
430         if (lp_server_role() == ROLE_STANDALONE) {
431                 d_printf("cannot join as standalone machine\n");
432                 return -1;
433         }
434
435         if (strlen(global_myname()) > 15) {
436                 d_printf("Our netbios name can be at most 15 chars long, "
437                          "\"%s\" is %u chars long\n",
438                          global_myname(), (unsigned int)strlen(global_myname()));
439                 return -1;
440         }
441
442         if ((net_rpc_perform_oldjoin(c, argc, argv) == 0))
443                 return 0;
444
445         return net_rpc_join_newstyle(c, argc, argv);
446 }
447
448 /**
449  * display info about a rpc domain
450  *
451  * All parameters are provided by the run_rpc_command function, except for
452  * argc, argv which are passed through.
453  *
454  * @param domain_sid The domain sid acquired from the remote server
455  * @param cli A cli_state connected to the server.
456  * @param mem_ctx Talloc context, destroyed on completion of the function.
457  * @param argc  Standard main() style argc.
458  * @param argv  Standard main() style argv. Initial components are already
459  *              stripped.
460  *
461  * @return Normal NTSTATUS return.
462  **/
463
464 NTSTATUS rpc_info_internals(struct net_context *c,
465                         const DOM_SID *domain_sid,
466                         const char *domain_name,
467                         struct cli_state *cli,
468                         struct rpc_pipe_client *pipe_hnd,
469                         TALLOC_CTX *mem_ctx,
470                         int argc,
471                         const char **argv)
472 {
473         struct policy_handle connect_pol, domain_pol;
474         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
475         union samr_DomainInfo *info = NULL;
476         fstring sid_str;
477
478         sid_to_fstring(sid_str, domain_sid);
479
480         /* Get sam policy handle */
481         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
482                                       pipe_hnd->desthost,
483                                       MAXIMUM_ALLOWED_ACCESS,
484                                       &connect_pol);
485         if (!NT_STATUS_IS_OK(result)) {
486                 d_fprintf(stderr, "Could not connect to SAM: %s\n", nt_errstr(result));
487                 goto done;
488         }
489
490         /* Get domain policy handle */
491         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
492                                         &connect_pol,
493                                         MAXIMUM_ALLOWED_ACCESS,
494                                         CONST_DISCARD(struct dom_sid2 *, domain_sid),
495                                         &domain_pol);
496         if (!NT_STATUS_IS_OK(result)) {
497                 d_fprintf(stderr, "Could not open domain: %s\n", nt_errstr(result));
498                 goto done;
499         }
500
501         result = rpccli_samr_QueryDomainInfo(pipe_hnd, mem_ctx,
502                                              &domain_pol,
503                                              2,
504                                              &info);
505         if (NT_STATUS_IS_OK(result)) {
506                 d_printf("Domain Name: %s\n", info->general.domain_name.string);
507                 d_printf("Domain SID: %s\n", sid_str);
508                 d_printf("Sequence number: %llu\n",
509                         (unsigned long long)info->general.sequence_num);
510                 d_printf("Num users: %u\n", info->general.num_users);
511                 d_printf("Num domain groups: %u\n", info->general.num_groups);
512                 d_printf("Num local groups: %u\n", info->general.num_aliases);
513         }
514
515  done:
516         return result;
517 }
518
519 /**
520  * 'net rpc info' entrypoint.
521  * @param argc  Standard main() style argc.
522  * @param argv  Standard main() style argv. Initial components are already
523  *              stripped.
524  **/
525
526 int net_rpc_info(struct net_context *c, int argc, const char **argv)
527 {
528         if (c->display_usage) {
529                 d_printf("Usage:\n"
530                          "net rpc info\n"
531                          "  Display information about the domain\n");
532                 return 0;
533         }
534
535         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id,
536                                NET_FLAGS_PDC, rpc_info_internals,
537                                argc, argv);
538 }
539
540 /**
541  * Fetch domain SID into the local secrets.tdb.
542  *
543  * All parameters are provided by the run_rpc_command function, except for
544  * argc, argv which are passed through.
545  *
546  * @param domain_sid The domain sid acquired from the remote server.
547  * @param cli A cli_state connected to the server.
548  * @param mem_ctx Talloc context, destroyed on completion of the function.
549  * @param argc  Standard main() style argc.
550  * @param argv  Standard main() style argv. Initial components are already
551  *              stripped.
552  *
553  * @return Normal NTSTATUS return.
554  **/
555
556 static NTSTATUS rpc_getsid_internals(struct net_context *c,
557                         const DOM_SID *domain_sid,
558                         const char *domain_name,
559                         struct cli_state *cli,
560                         struct rpc_pipe_client *pipe_hnd,
561                         TALLOC_CTX *mem_ctx,
562                         int argc,
563                         const char **argv)
564 {
565         fstring sid_str;
566
567         sid_to_fstring(sid_str, domain_sid);
568         d_printf("Storing SID %s for Domain %s in secrets.tdb\n",
569                  sid_str, domain_name);
570
571         if (!secrets_store_domain_sid(domain_name, domain_sid)) {
572                 DEBUG(0,("Can't store domain SID\n"));
573                 return NT_STATUS_UNSUCCESSFUL;
574         }
575
576         return NT_STATUS_OK;
577 }
578
579 /**
580  * 'net rpc getsid' entrypoint.
581  * @param argc  Standard main() style argc.
582  * @param argv  Standard main() style argv. Initial components are already
583  *              stripped.
584  **/
585
586 int net_rpc_getsid(struct net_context *c, int argc, const char **argv)
587 {
588         if (c->display_usage) {
589                 d_printf("Usage:\n"
590                          "net rpc getsid\n"
591                          "    Fetch domain SID into local secrets.tdb\n");
592                 return 0;
593         }
594
595         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id,
596                                NET_FLAGS_ANONYMOUS | NET_FLAGS_PDC,
597                                rpc_getsid_internals,
598                                argc, argv);
599 }
600
601 /****************************************************************************/
602
603 /**
604  * Basic usage function for 'net rpc user'.
605  * @param argc  Standard main() style argc.
606  * @param argv  Standard main() style argv. Initial components are already
607  *              stripped.
608  **/
609
610 static int rpc_user_usage(struct net_context *c, int argc, const char **argv)
611 {
612         return net_user_usage(c, argc, argv);
613 }
614
615 /**
616  * Add a new user to a remote RPC server.
617  *
618  * @param argc  Standard main() style argc.
619  * @param argv  Standard main() style argv. Initial components are already
620  *              stripped.
621  *
622  * @return A shell status integer (0 for success).
623  **/
624
625 static int rpc_user_add(struct net_context *c, int argc, const char **argv)
626 {
627         NET_API_STATUS status;
628         struct USER_INFO_1 info1;
629         uint32_t parm_error = 0;
630
631         if (argc < 1 || c->display_usage) {
632                 rpc_user_usage(c, argc, argv);
633                 return 0;
634         }
635
636         ZERO_STRUCT(info1);
637
638         info1.usri1_name = argv[0];
639         if (argc == 2) {
640                 info1.usri1_password = argv[1];
641         }
642
643         status = NetUserAdd(c->opt_host, 1, (uint8_t *)&info1, &parm_error);
644
645         if (status != 0) {
646                 d_fprintf(stderr, "Failed to add user '%s' with: %s.\n",
647                         argv[0], libnetapi_get_error_string(c->netapi_ctx,
648                                                             status));
649                 return -1;
650         } else {
651                 d_printf("Added user '%s'.\n", argv[0]);
652         }
653
654         return 0;
655 }
656
657 /**
658  * Rename a user on a remote RPC server.
659  *
660  * @param argc  Standard main() style argc.
661  * @param argv  Standard main() style argv. Initial components are already
662  *              stripped.
663  *
664  * @return A shell status integer (0 for success).
665  **/
666
667 static int rpc_user_rename(struct net_context *c, int argc, const char **argv)
668 {
669         NET_API_STATUS status;
670         struct USER_INFO_0 u0;
671         uint32_t parm_err = 0;
672
673         if (argc != 2 || c->display_usage) {
674                 rpc_user_usage(c, argc, argv);
675                 return 0;
676         }
677
678         u0.usri0_name = argv[1];
679
680         status = NetUserSetInfo(c->opt_host, argv[0],
681                                 0, (uint8_t *)&u0, &parm_err);
682         if (status) {
683                 d_fprintf(stderr, "Failed to rename user from %s to %s - %s\n",
684                           argv[0], argv[1],
685                           libnetapi_get_error_string(c->netapi_ctx, status));
686         } else {
687                 d_printf("Renamed user from %s to %s\n", argv[0], argv[1]);
688         }
689
690         return status;
691 }
692
693 /**
694  * Delete a user from a remote RPC server.
695  *
696  * @param argc  Standard main() style argc.
697  * @param argv  Standard main() style argv. Initial components are already
698  *              stripped.
699  *
700  * @return A shell status integer (0 for success).
701  **/
702
703 static int rpc_user_delete(struct net_context *c, int argc, const char **argv)
704 {
705         NET_API_STATUS status;
706
707         if (argc < 1 || c->display_usage) {
708                 rpc_user_usage(c, argc, argv);
709                 return 0;
710         }
711
712         status = NetUserDel(c->opt_host, argv[0]);
713
714         if (status != 0) {
715                 d_fprintf(stderr, "Failed to delete user '%s' with: %s.\n",
716                           argv[0],
717                           libnetapi_get_error_string(c->netapi_ctx, status));
718                 return -1;
719         } else {
720                 d_printf("Deleted user '%s'.\n", argv[0]);
721         }
722
723         return 0;
724 }
725
726 /**
727  * Set a user's password on a remote RPC server.
728  *
729  * @param argc  Standard main() style argc.
730  * @param argv  Standard main() style argv. Initial components are already
731  *              stripped.
732  *
733  * @return A shell status integer (0 for success).
734  **/
735
736 static int rpc_user_password(struct net_context *c, int argc, const char **argv)
737 {
738         NET_API_STATUS status;
739         char *prompt = NULL;
740         struct USER_INFO_1003 u1003;
741         uint32_t parm_err = 0;
742
743         if (argc < 1 || c->display_usage) {
744                 rpc_user_usage(c, argc, argv);
745                 return 0;
746         }
747
748         if (argv[1]) {
749                 u1003.usri1003_password = argv[1];
750         } else {
751                 if (asprintf(&prompt, "Enter new password for %s:", argv[0]) == -1) {
752                         return -1;
753                 }
754                 u1003.usri1003_password = getpass(prompt);
755                 SAFE_FREE(prompt);
756         }
757
758         status = NetUserSetInfo(c->opt_host, argv[0], 1003, (uint8_t *)&u1003, &parm_err);
759
760         /* Display results */
761         if (status != 0) {
762                 d_fprintf(stderr, "Failed to set password for '%s' with: %s.\n",
763                         argv[0], libnetapi_get_error_string(c->netapi_ctx,
764                                                             status));
765                 return -1;
766         }
767
768         return 0;
769 }
770
771 /**
772  * List a user's groups from a remote RPC server.
773  *
774  * @param argc  Standard main() style argc.
775  * @param argv  Standard main() style argv. Initial components are already
776  *              stripped.
777  *
778  * @return A shell status integer (0 for success)
779  **/
780
781 static int rpc_user_info(struct net_context *c, int argc, const char **argv)
782
783 {
784         NET_API_STATUS status;
785         struct GROUP_USERS_INFO_0 *u0 = NULL;
786         uint32_t entries_read = 0;
787         uint32_t total_entries = 0;
788         int i;
789
790
791         if (argc < 1 || c->display_usage) {
792                 rpc_user_usage(c, argc, argv);
793                 return 0;
794         }
795
796         status = NetUserGetGroups(c->opt_host,
797                                   argv[0],
798                                   0,
799                                   (uint8_t **)(void *)&u0,
800                                   (uint32_t)-1,
801                                   &entries_read,
802                                   &total_entries);
803         if (status != 0) {
804                 d_fprintf(stderr, "Failed to get groups for '%s' with: %s.\n",
805                         argv[0], libnetapi_get_error_string(c->netapi_ctx,
806                                                             status));
807                 return -1;
808         }
809
810         for (i=0; i < entries_read; i++) {
811                 printf("%s\n", u0->grui0_name);
812                 u0++;
813         }
814
815         return 0;
816 }
817
818 /**
819  * List users on a remote RPC server.
820  *
821  * All parameters are provided by the run_rpc_command function, except for
822  * argc, argv which are passed through.
823  *
824  * @param domain_sid The domain sid acquired from the remote server.
825  * @param cli A cli_state connected to the server.
826  * @param mem_ctx Talloc context, destroyed on completion of the function.
827  * @param argc  Standard main() style argc.
828  * @param argv  Standard main() style argv. Initial components are already
829  *              stripped.
830  *
831  * @return Normal NTSTATUS return.
832  **/
833
834 static int rpc_user_list(struct net_context *c, int argc, const char **argv)
835 {
836         NET_API_STATUS status;
837         uint32_t start_idx=0, num_entries, i, loop_count = 0;
838         struct NET_DISPLAY_USER *info = NULL;
839         void *buffer = NULL;
840
841         /* Query domain users */
842         if (c->opt_long_list_entries)
843                 d_printf("\nUser name             Comment"
844                          "\n-----------------------------\n");
845         do {
846                 uint32_t max_entries, max_size;
847
848                 get_query_dispinfo_params(
849                         loop_count, &max_entries, &max_size);
850
851                 status = NetQueryDisplayInformation(c->opt_host,
852                                                     1,
853                                                     start_idx,
854                                                     max_entries,
855                                                     max_size,
856                                                     &num_entries,
857                                                     &buffer);
858                 if (status != 0 && status != ERROR_MORE_DATA) {
859                         return status;
860                 }
861
862                 info = (struct NET_DISPLAY_USER *)buffer;
863
864                 for (i = 0; i < num_entries; i++) {
865
866                         if (c->opt_long_list_entries)
867                                 printf("%-21.21s %s\n", info->usri1_name,
868                                         info->usri1_comment);
869                         else
870                                 printf("%s\n", info->usri1_name);
871                         info++;
872                 }
873
874                 NetApiBufferFree(buffer);
875
876                 loop_count++;
877                 start_idx += num_entries;
878
879         } while (status == ERROR_MORE_DATA);
880
881         return status;
882 }
883
884 /**
885  * 'net rpc user' entrypoint.
886  * @param argc  Standard main() style argc.
887  * @param argv  Standard main() style argv. Initial components are already
888  *              stripped.
889  **/
890
891 int net_rpc_user(struct net_context *c, int argc, const char **argv)
892 {
893         NET_API_STATUS status;
894
895         struct functable func[] = {
896                 {
897                         "add",
898                         rpc_user_add,
899                         NET_TRANSPORT_RPC,
900                         "Add specified user",
901                         "net rpc user add\n"
902                         "    Add specified user"
903                 },
904                 {
905                         "info",
906                         rpc_user_info,
907                         NET_TRANSPORT_RPC,
908                         "List domain groups of user",
909                         "net rpc user info\n"
910                         "    Lis domain groups of user"
911                 },
912                 {
913                         "delete",
914                         rpc_user_delete,
915                         NET_TRANSPORT_RPC,
916                         "Remove specified user",
917                         "net rpc user delete\n"
918                         "    Remove specified user"
919                 },
920                 {
921                         "password",
922                         rpc_user_password,
923                         NET_TRANSPORT_RPC,
924                         "Change user password",
925                         "net rpc user password\n"
926                         "    Change user password"
927                 },
928                 {
929                         "rename",
930                         rpc_user_rename,
931                         NET_TRANSPORT_RPC,
932                         "Rename specified user",
933                         "net rpc user rename\n"
934                         "    Rename specified user"
935                 },
936                 {NULL, NULL, 0, NULL, NULL}
937         };
938
939         status = libnetapi_init(&c->netapi_ctx);
940         if (status != 0) {
941                 return -1;
942         }
943         libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
944         libnetapi_set_password(c->netapi_ctx, c->opt_password);
945         if (c->opt_kerberos) {
946                 libnetapi_set_use_kerberos(c->netapi_ctx);
947         }
948
949         if (argc == 0) {
950                 if (c->display_usage) {
951                         d_printf("Usage:\n");
952                         d_printf("net rpc user\n"
953                                  "    List all users\n");
954                         net_display_usage_from_functable(func);
955                         return 0;
956                 }
957
958                 return rpc_user_list(c, argc, argv);
959         }
960
961         return net_run_function(c, argc, argv, "net rpc user", func);
962 }
963
964 static NTSTATUS rpc_sh_user_list(struct net_context *c,
965                                  TALLOC_CTX *mem_ctx,
966                                  struct rpc_sh_ctx *ctx,
967                                  struct rpc_pipe_client *pipe_hnd,
968                                  int argc, const char **argv)
969 {
970         return werror_to_ntstatus(W_ERROR(rpc_user_list(c, argc, argv)));
971 }
972
973 static NTSTATUS rpc_sh_user_info(struct net_context *c,
974                                  TALLOC_CTX *mem_ctx,
975                                  struct rpc_sh_ctx *ctx,
976                                  struct rpc_pipe_client *pipe_hnd,
977                                  int argc, const char **argv)
978 {
979         return werror_to_ntstatus(W_ERROR(rpc_user_info(c, argc, argv)));
980 }
981
982 static NTSTATUS rpc_sh_handle_user(struct net_context *c,
983                                    TALLOC_CTX *mem_ctx,
984                                    struct rpc_sh_ctx *ctx,
985                                    struct rpc_pipe_client *pipe_hnd,
986                                    int argc, const char **argv,
987                                    NTSTATUS (*fn)(
988                                            struct net_context *c,
989                                            TALLOC_CTX *mem_ctx,
990                                            struct rpc_sh_ctx *ctx,
991                                            struct rpc_pipe_client *pipe_hnd,
992                                            struct policy_handle *user_hnd,
993                                            int argc, const char **argv))
994 {
995         struct policy_handle connect_pol, domain_pol, user_pol;
996         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
997         DOM_SID sid;
998         uint32 rid;
999         enum lsa_SidType type;
1000
1001         if (argc == 0) {
1002                 d_fprintf(stderr, "usage: %s <username>\n", ctx->whoami);
1003                 return NT_STATUS_INVALID_PARAMETER;
1004         }
1005
1006         ZERO_STRUCT(connect_pol);
1007         ZERO_STRUCT(domain_pol);
1008         ZERO_STRUCT(user_pol);
1009
1010         result = net_rpc_lookup_name(c, mem_ctx, rpc_pipe_np_smb_conn(pipe_hnd),
1011                                      argv[0], NULL, NULL, &sid, &type);
1012         if (!NT_STATUS_IS_OK(result)) {
1013                 d_fprintf(stderr, "Could not lookup %s: %s\n", argv[0],
1014                           nt_errstr(result));
1015                 goto done;
1016         }
1017
1018         if (type != SID_NAME_USER) {
1019                 d_fprintf(stderr, "%s is a %s, not a user\n", argv[0],
1020                           sid_type_lookup(type));
1021                 result = NT_STATUS_NO_SUCH_USER;
1022                 goto done;
1023         }
1024
1025         if (!sid_peek_check_rid(ctx->domain_sid, &sid, &rid)) {
1026                 d_fprintf(stderr, "%s is not in our domain\n", argv[0]);
1027                 result = NT_STATUS_NO_SUCH_USER;
1028                 goto done;
1029         }
1030
1031         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1032                                       pipe_hnd->desthost,
1033                                       MAXIMUM_ALLOWED_ACCESS,
1034                                       &connect_pol);
1035         if (!NT_STATUS_IS_OK(result)) {
1036                 goto done;
1037         }
1038
1039         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1040                                         &connect_pol,
1041                                         MAXIMUM_ALLOWED_ACCESS,
1042                                         ctx->domain_sid,
1043                                         &domain_pol);
1044         if (!NT_STATUS_IS_OK(result)) {
1045                 goto done;
1046         }
1047
1048         result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1049                                       &domain_pol,
1050                                       MAXIMUM_ALLOWED_ACCESS,
1051                                       rid,
1052                                       &user_pol);
1053         if (!NT_STATUS_IS_OK(result)) {
1054                 goto done;
1055         }
1056
1057         result = fn(c, mem_ctx, ctx, pipe_hnd, &user_pol, argc-1, argv+1);
1058
1059  done:
1060         if (is_valid_policy_hnd(&user_pol)) {
1061                 rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1062         }
1063         if (is_valid_policy_hnd(&domain_pol)) {
1064                 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
1065         }
1066         if (is_valid_policy_hnd(&connect_pol)) {
1067                 rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
1068         }
1069         return result;
1070 }
1071
1072 static NTSTATUS rpc_sh_user_show_internals(struct net_context *c,
1073                                            TALLOC_CTX *mem_ctx,
1074                                            struct rpc_sh_ctx *ctx,
1075                                            struct rpc_pipe_client *pipe_hnd,
1076                                            struct policy_handle *user_hnd,
1077                                            int argc, const char **argv)
1078 {
1079         NTSTATUS result;
1080         union samr_UserInfo *info = NULL;
1081
1082         if (argc != 0) {
1083                 d_fprintf(stderr, "usage: %s show <username>\n", ctx->whoami);
1084                 return NT_STATUS_INVALID_PARAMETER;
1085         }
1086
1087         result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1088                                            user_hnd,
1089                                            21,
1090                                            &info);
1091         if (!NT_STATUS_IS_OK(result)) {
1092                 return result;
1093         }
1094
1095         d_printf("user rid: %d, group rid: %d\n",
1096                 info->info21.rid,
1097                 info->info21.primary_gid);
1098
1099         return result;
1100 }
1101
1102 static NTSTATUS rpc_sh_user_show(struct net_context *c,
1103                                  TALLOC_CTX *mem_ctx,
1104                                  struct rpc_sh_ctx *ctx,
1105                                  struct rpc_pipe_client *pipe_hnd,
1106                                  int argc, const char **argv)
1107 {
1108         return rpc_sh_handle_user(c, mem_ctx, ctx, pipe_hnd, argc, argv,
1109                                   rpc_sh_user_show_internals);
1110 }
1111
1112 #define FETCHSTR(name, rec) \
1113 do { if (strequal(ctx->thiscmd, name)) { \
1114         oldval = talloc_strdup(mem_ctx, info->info21.rec.string); } \
1115 } while (0);
1116
1117 #define SETSTR(name, rec, flag) \
1118 do { if (strequal(ctx->thiscmd, name)) { \
1119         init_lsa_String(&(info->info21.rec), argv[0]); \
1120         info->info21.fields_present |= SAMR_FIELD_##flag; } \
1121 } while (0);
1122
1123 static NTSTATUS rpc_sh_user_str_edit_internals(struct net_context *c,
1124                                                TALLOC_CTX *mem_ctx,
1125                                                struct rpc_sh_ctx *ctx,
1126                                                struct rpc_pipe_client *pipe_hnd,
1127                                                struct policy_handle *user_hnd,
1128                                                int argc, const char **argv)
1129 {
1130         NTSTATUS result;
1131         const char *username;
1132         const char *oldval = "";
1133         union samr_UserInfo *info = NULL;
1134
1135         if (argc > 1) {
1136                 d_fprintf(stderr, "usage: %s <username> [new value|NULL]\n",
1137                           ctx->whoami);
1138                 return NT_STATUS_INVALID_PARAMETER;
1139         }
1140
1141         result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1142                                            user_hnd,
1143                                            21,
1144                                            &info);
1145         if (!NT_STATUS_IS_OK(result)) {
1146                 return result;
1147         }
1148
1149         username = talloc_strdup(mem_ctx, info->info21.account_name.string);
1150
1151         FETCHSTR("fullname", full_name);
1152         FETCHSTR("homedir", home_directory);
1153         FETCHSTR("homedrive", home_drive);
1154         FETCHSTR("logonscript", logon_script);
1155         FETCHSTR("profilepath", profile_path);
1156         FETCHSTR("description", description);
1157
1158         if (argc == 0) {
1159                 d_printf("%s's %s: [%s]\n", username, ctx->thiscmd, oldval);
1160                 goto done;
1161         }
1162
1163         if (strcmp(argv[0], "NULL") == 0) {
1164                 argv[0] = "";
1165         }
1166
1167         ZERO_STRUCT(info->info21);
1168
1169         SETSTR("fullname", full_name, FULL_NAME);
1170         SETSTR("homedir", home_directory, HOME_DIRECTORY);
1171         SETSTR("homedrive", home_drive, HOME_DRIVE);
1172         SETSTR("logonscript", logon_script, LOGON_SCRIPT);
1173         SETSTR("profilepath", profile_path, PROFILE_PATH);
1174         SETSTR("description", description, DESCRIPTION);
1175
1176         result = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1177                                          user_hnd,
1178                                          21,
1179                                          info);
1180
1181         d_printf("Set %s's %s from [%s] to [%s]\n", username,
1182                  ctx->thiscmd, oldval, argv[0]);
1183
1184  done:
1185
1186         return result;
1187 }
1188
1189 #define HANDLEFLG(name, rec) \
1190 do { if (strequal(ctx->thiscmd, name)) { \
1191         oldval = (oldflags & ACB_##rec) ? "yes" : "no"; \
1192         if (newval) { \
1193                 newflags = oldflags | ACB_##rec; \
1194         } else { \
1195                 newflags = oldflags & ~ACB_##rec; \
1196         } } } while (0);
1197
1198 static NTSTATUS rpc_sh_user_str_edit(struct net_context *c,
1199                                      TALLOC_CTX *mem_ctx,
1200                                      struct rpc_sh_ctx *ctx,
1201                                      struct rpc_pipe_client *pipe_hnd,
1202                                      int argc, const char **argv)
1203 {
1204         return rpc_sh_handle_user(c, mem_ctx, ctx, pipe_hnd, argc, argv,
1205                                   rpc_sh_user_str_edit_internals);
1206 }
1207
1208 static NTSTATUS rpc_sh_user_flag_edit_internals(struct net_context *c,
1209                                                 TALLOC_CTX *mem_ctx,
1210                                                 struct rpc_sh_ctx *ctx,
1211                                                 struct rpc_pipe_client *pipe_hnd,
1212                                                 struct policy_handle *user_hnd,
1213                                                 int argc, const char **argv)
1214 {
1215         NTSTATUS result;
1216         const char *username;
1217         const char *oldval = "unknown";
1218         uint32 oldflags, newflags;
1219         bool newval;
1220         union samr_UserInfo *info = NULL;
1221
1222         if ((argc > 1) ||
1223             ((argc == 1) && !strequal(argv[0], "yes") &&
1224              !strequal(argv[0], "no"))) {
1225                 d_fprintf(stderr, "usage: %s <username> [yes|no]\n",
1226                           ctx->whoami);
1227                 return NT_STATUS_INVALID_PARAMETER;
1228         }
1229
1230         newval = strequal(argv[0], "yes");
1231
1232         result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1233                                            user_hnd,
1234                                            21,
1235                                            &info);
1236         if (!NT_STATUS_IS_OK(result)) {
1237                 return result;
1238         }
1239
1240         username = talloc_strdup(mem_ctx, info->info21.account_name.string);
1241         oldflags = info->info21.acct_flags;
1242         newflags = info->info21.acct_flags;
1243
1244         HANDLEFLG("disabled", DISABLED);
1245         HANDLEFLG("pwnotreq", PWNOTREQ);
1246         HANDLEFLG("autolock", AUTOLOCK);
1247         HANDLEFLG("pwnoexp", PWNOEXP);
1248
1249         if (argc == 0) {
1250                 d_printf("%s's %s flag: %s\n", username, ctx->thiscmd, oldval);
1251                 goto done;
1252         }
1253
1254         ZERO_STRUCT(info->info21);
1255
1256         info->info21.acct_flags = newflags;
1257         info->info21.fields_present = SAMR_FIELD_ACCT_FLAGS;
1258
1259         result = rpccli_samr_SetUserInfo(pipe_hnd, mem_ctx,
1260                                          user_hnd,
1261                                          21,
1262                                          info);
1263
1264         if (NT_STATUS_IS_OK(result)) {
1265                 d_printf("Set %s's %s flag from [%s] to [%s]\n", username,
1266                          ctx->thiscmd, oldval, argv[0]);
1267         }
1268
1269  done:
1270
1271         return result;
1272 }
1273
1274 static NTSTATUS rpc_sh_user_flag_edit(struct net_context *c,
1275                                       TALLOC_CTX *mem_ctx,
1276                                       struct rpc_sh_ctx *ctx,
1277                                       struct rpc_pipe_client *pipe_hnd,
1278                                       int argc, const char **argv)
1279 {
1280         return rpc_sh_handle_user(c, mem_ctx, ctx, pipe_hnd, argc, argv,
1281                                   rpc_sh_user_flag_edit_internals);
1282 }
1283
1284 struct rpc_sh_cmd *net_rpc_user_edit_cmds(struct net_context *c,
1285                                           TALLOC_CTX *mem_ctx,
1286                                           struct rpc_sh_ctx *ctx)
1287 {
1288         static struct rpc_sh_cmd cmds[] = {
1289
1290                 { "fullname", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
1291                   "Show/Set a user's full name" },
1292
1293                 { "homedir", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
1294                   "Show/Set a user's home directory" },
1295
1296                 { "homedrive", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
1297                   "Show/Set a user's home drive" },
1298
1299                 { "logonscript", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
1300                   "Show/Set a user's logon script" },
1301
1302                 { "profilepath", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
1303                   "Show/Set a user's profile path" },
1304
1305                 { "description", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_str_edit,
1306                   "Show/Set a user's description" },
1307
1308                 { "disabled", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
1309                   "Show/Set whether a user is disabled" },
1310
1311                 { "autolock", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
1312                   "Show/Set whether a user locked out" },
1313
1314                 { "pwnotreq", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
1315                   "Show/Set whether a user does not need a password" },
1316
1317                 { "pwnoexp", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_flag_edit,
1318                   "Show/Set whether a user's password does not expire" },
1319
1320                 { NULL, NULL, 0, NULL, NULL }
1321         };
1322
1323         return cmds;
1324 }
1325
1326 struct rpc_sh_cmd *net_rpc_user_cmds(struct net_context *c,
1327                                      TALLOC_CTX *mem_ctx,
1328                                      struct rpc_sh_ctx *ctx)
1329 {
1330         static struct rpc_sh_cmd cmds[] = {
1331
1332                 { "list", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_list,
1333                   "List available users" },
1334
1335                 { "info", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_info,
1336                   "List the domain groups a user is member of" },
1337
1338                 { "show", NULL, &ndr_table_samr.syntax_id, rpc_sh_user_show,
1339                   "Show info about a user" },
1340
1341                 { "edit", net_rpc_user_edit_cmds, 0, NULL,
1342                   "Show/Modify a user's fields" },
1343
1344                 { NULL, NULL, 0, NULL, NULL }
1345         };
1346
1347         return cmds;
1348 }
1349
1350 /****************************************************************************/
1351
1352 /**
1353  * Basic usage function for 'net rpc group'.
1354  * @param argc  Standard main() style argc.
1355  * @param argv  Standard main() style argv. Initial components are already
1356  *              stripped.
1357  **/
1358
1359 static int rpc_group_usage(struct net_context *c, int argc, const char **argv)
1360 {
1361         return net_group_usage(c, argc, argv);
1362 }
1363
1364 /**
1365  * Delete group on a remote RPC server.
1366  *
1367  * All parameters are provided by the run_rpc_command function, except for
1368  * argc, argv which are passed through.
1369  *
1370  * @param domain_sid The domain sid acquired from the remote server.
1371  * @param cli A cli_state connected to the server.
1372  * @param mem_ctx Talloc context, destroyed on completion of the function.
1373  * @param argc  Standard main() style argc.
1374  * @param argv  Standard main() style argv. Initial components are already
1375  *              stripped.
1376  *
1377  * @return Normal NTSTATUS return.
1378  **/
1379
1380 static NTSTATUS rpc_group_delete_internals(struct net_context *c,
1381                                         const DOM_SID *domain_sid,
1382                                         const char *domain_name,
1383                                         struct cli_state *cli,
1384                                         struct rpc_pipe_client *pipe_hnd,
1385                                         TALLOC_CTX *mem_ctx,
1386                                         int argc,
1387                                         const char **argv)
1388 {
1389         struct policy_handle connect_pol, domain_pol, group_pol, user_pol;
1390         bool group_is_primary = false;
1391         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1392         uint32_t group_rid;
1393         struct samr_RidTypeArray *rids = NULL;
1394         /* char **names; */
1395         int i;
1396         /* struct samr_RidWithAttribute *user_gids; */
1397
1398         struct samr_Ids group_rids, name_types;
1399         struct lsa_String lsa_acct_name;
1400         union samr_UserInfo *info = NULL;
1401
1402         if (argc < 1 || c->display_usage) {
1403                 rpc_group_usage(c, argc,argv);
1404                 return NT_STATUS_OK; /* ok? */
1405         }
1406
1407         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1408                                       pipe_hnd->desthost,
1409                                       MAXIMUM_ALLOWED_ACCESS,
1410                                       &connect_pol);
1411
1412         if (!NT_STATUS_IS_OK(result)) {
1413                 d_fprintf(stderr, "Request samr_Connect2 failed\n");
1414                 goto done;
1415         }
1416
1417         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1418                                         &connect_pol,
1419                                         MAXIMUM_ALLOWED_ACCESS,
1420                                         CONST_DISCARD(struct dom_sid2 *, domain_sid),
1421                                         &domain_pol);
1422
1423         if (!NT_STATUS_IS_OK(result)) {
1424                 d_fprintf(stderr, "Request open_domain failed\n");
1425                 goto done;
1426         }
1427
1428         init_lsa_String(&lsa_acct_name, argv[0]);
1429
1430         result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1431                                          &domain_pol,
1432                                          1,
1433                                          &lsa_acct_name,
1434                                          &group_rids,
1435                                          &name_types);
1436         if (!NT_STATUS_IS_OK(result)) {
1437                 d_fprintf(stderr, "Lookup of '%s' failed\n",argv[0]);
1438                 goto done;
1439         }
1440
1441         switch (name_types.ids[0])
1442         {
1443         case SID_NAME_DOM_GRP:
1444                 result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
1445                                                &domain_pol,
1446                                                MAXIMUM_ALLOWED_ACCESS,
1447                                                group_rids.ids[0],
1448                                                &group_pol);
1449                 if (!NT_STATUS_IS_OK(result)) {
1450                         d_fprintf(stderr, "Request open_group failed");
1451                         goto done;
1452                 }
1453
1454                 group_rid = group_rids.ids[0];
1455
1456                 result = rpccli_samr_QueryGroupMember(pipe_hnd, mem_ctx,
1457                                                       &group_pol,
1458                                                       &rids);
1459
1460                 if (!NT_STATUS_IS_OK(result)) {
1461                         d_fprintf(stderr, "Unable to query group members of %s",argv[0]);
1462                         goto done;
1463                 }
1464
1465                 if (c->opt_verbose) {
1466                         d_printf("Domain Group %s (rid: %d) has %d members\n",
1467                                 argv[0],group_rid, rids->count);
1468                 }
1469
1470                 /* Check if group is anyone's primary group */
1471                 for (i = 0; i < rids->count; i++)
1472                 {
1473                         result = rpccli_samr_OpenUser(pipe_hnd, mem_ctx,
1474                                                       &domain_pol,
1475                                                       MAXIMUM_ALLOWED_ACCESS,
1476                                                       rids->rids[i],
1477                                                       &user_pol);
1478
1479                         if (!NT_STATUS_IS_OK(result)) {
1480                                 d_fprintf(stderr, "Unable to open group member %d\n",
1481                                         rids->rids[i]);
1482                                 goto done;
1483                         }
1484
1485                         result = rpccli_samr_QueryUserInfo(pipe_hnd, mem_ctx,
1486                                                            &user_pol,
1487                                                            21,
1488                                                            &info);
1489
1490                         if (!NT_STATUS_IS_OK(result)) {
1491                                 d_fprintf(stderr, "Unable to lookup userinfo for group member %d\n",
1492                                         rids->rids[i]);
1493                                 goto done;
1494                         }
1495
1496                         if (info->info21.primary_gid == group_rid) {
1497                                 if (c->opt_verbose) {
1498                                         d_printf("Group is primary group of %s\n",
1499                                                 info->info21.account_name.string);
1500                                 }
1501                                 group_is_primary = true;
1502                         }
1503
1504                         rpccli_samr_Close(pipe_hnd, mem_ctx, &user_pol);
1505                 }
1506
1507                 if (group_is_primary) {
1508                         d_fprintf(stderr, "Unable to delete group because some "
1509                                  "of it's members have it as primary group\n");
1510                         result = NT_STATUS_MEMBERS_PRIMARY_GROUP;
1511                         goto done;
1512                 }
1513
1514                 /* remove all group members */
1515                 for (i = 0; i < rids->count; i++)
1516                 {
1517                         if (c->opt_verbose)
1518                                 d_printf("Remove group member %d...",
1519                                         rids->rids[i]);
1520                         result = rpccli_samr_DeleteGroupMember(pipe_hnd, mem_ctx,
1521                                                                &group_pol,
1522                                                                rids->rids[i]);
1523
1524                         if (NT_STATUS_IS_OK(result)) {
1525                                 if (c->opt_verbose)
1526                                         d_printf("ok\n");
1527                         } else {
1528                                 if (c->opt_verbose)
1529                                         d_printf("failed\n");
1530                                 goto done;
1531                         }
1532                 }
1533
1534                 result = rpccli_samr_DeleteDomainGroup(pipe_hnd, mem_ctx,
1535                                                        &group_pol);
1536
1537                 break;
1538         /* removing a local group is easier... */
1539         case SID_NAME_ALIAS:
1540                 result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
1541                                                &domain_pol,
1542                                                MAXIMUM_ALLOWED_ACCESS,
1543                                                group_rids.ids[0],
1544                                                &group_pol);
1545
1546                 if (!NT_STATUS_IS_OK(result)) {
1547                         d_fprintf(stderr, "Request open_alias failed\n");
1548                         goto done;
1549                 }
1550
1551                 result = rpccli_samr_DeleteDomAlias(pipe_hnd, mem_ctx,
1552                                                     &group_pol);
1553                 break;
1554         default:
1555                 d_fprintf(stderr, "%s is of type %s. This command is only for deleting local or global groups\n",
1556                         argv[0],sid_type_lookup(name_types.ids[0]));
1557                 result = NT_STATUS_UNSUCCESSFUL;
1558                 goto done;
1559         }
1560
1561         if (NT_STATUS_IS_OK(result)) {
1562                 if (c->opt_verbose)
1563                         d_printf("Deleted %s '%s'\n",sid_type_lookup(name_types.ids[0]),argv[0]);
1564         } else {
1565                 d_fprintf(stderr, "Deleting of %s failed: %s\n",argv[0],
1566                         get_friendly_nt_error_msg(result));
1567         }
1568
1569  done:
1570         return result;
1571
1572 }
1573
1574 static int rpc_group_delete(struct net_context *c, int argc, const char **argv)
1575 {
1576         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
1577                                rpc_group_delete_internals, argc,argv);
1578 }
1579
1580 static int rpc_group_add_internals(struct net_context *c, int argc, const char **argv)
1581 {
1582         NET_API_STATUS status;
1583         struct GROUP_INFO_1 info1;
1584         uint32_t parm_error = 0;
1585
1586         if (argc != 1 || c->display_usage) {
1587                 rpc_group_usage(c, argc, argv);
1588                 return 0;
1589         }
1590
1591         ZERO_STRUCT(info1);
1592
1593         info1.grpi1_name = argv[0];
1594         if (c->opt_comment && strlen(c->opt_comment) > 0) {
1595                 info1.grpi1_comment = c->opt_comment;
1596         }
1597
1598         status = NetGroupAdd(c->opt_host, 1, (uint8_t *)&info1, &parm_error);
1599
1600         if (status != 0) {
1601                 d_fprintf(stderr, "Failed to add group '%s' with: %s.\n",
1602                         argv[0], libnetapi_get_error_string(c->netapi_ctx,
1603                                                             status));
1604                 return -1;
1605         } else {
1606                 d_printf("Added group '%s'.\n", argv[0]);
1607         }
1608
1609         return 0;
1610 }
1611
1612 static int rpc_alias_add_internals(struct net_context *c, int argc, const char **argv)
1613 {
1614         NET_API_STATUS status;
1615         struct LOCALGROUP_INFO_1 info1;
1616         uint32_t parm_error = 0;
1617
1618         if (argc != 1 || c->display_usage) {
1619                 rpc_group_usage(c, argc, argv);
1620                 return 0;
1621         }
1622
1623         ZERO_STRUCT(info1);
1624
1625         info1.lgrpi1_name = argv[0];
1626         if (c->opt_comment && strlen(c->opt_comment) > 0) {
1627                 info1.lgrpi1_comment = c->opt_comment;
1628         }
1629
1630         status = NetLocalGroupAdd(c->opt_host, 1, (uint8_t *)&info1, &parm_error);
1631
1632         if (status != 0) {
1633                 d_fprintf(stderr, "Failed to add alias '%s' with: %s.\n",
1634                         argv[0], libnetapi_get_error_string(c->netapi_ctx,
1635                                                             status));
1636                 return -1;
1637         } else {
1638                 d_printf("Added alias '%s'.\n", argv[0]);
1639         }
1640
1641         return 0;
1642 }
1643
1644 static int rpc_group_add(struct net_context *c, int argc, const char **argv)
1645 {
1646         if (c->opt_localgroup)
1647                 return rpc_alias_add_internals(c, argc, argv);
1648
1649         return rpc_group_add_internals(c, argc, argv);
1650 }
1651
1652 static NTSTATUS get_sid_from_name(struct cli_state *cli,
1653                                 TALLOC_CTX *mem_ctx,
1654                                 const char *name,
1655                                 DOM_SID *sid,
1656                                 enum lsa_SidType *type)
1657 {
1658         DOM_SID *sids = NULL;
1659         enum lsa_SidType *types = NULL;
1660         struct rpc_pipe_client *pipe_hnd = NULL;
1661         struct policy_handle lsa_pol;
1662         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
1663
1664         result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id,
1665                                           &pipe_hnd);
1666         if (!NT_STATUS_IS_OK(result)) {
1667                 goto done;
1668         }
1669
1670         result = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, false,
1671                                      SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
1672
1673         if (!NT_STATUS_IS_OK(result)) {
1674                 goto done;
1675         }
1676
1677         result = rpccli_lsa_lookup_names(pipe_hnd, mem_ctx, &lsa_pol, 1,
1678                                       &name, NULL, 1, &sids, &types);
1679
1680         if (NT_STATUS_IS_OK(result)) {
1681                 sid_copy(sid, &sids[0]);
1682                 *type = types[0];
1683         }
1684
1685         rpccli_lsa_Close(pipe_hnd, mem_ctx, &lsa_pol);
1686
1687  done:
1688         if (pipe_hnd) {
1689                 TALLOC_FREE(pipe_hnd);
1690         }
1691
1692         if (!NT_STATUS_IS_OK(result) && (StrnCaseCmp(name, "S-", 2) == 0)) {
1693
1694                 /* Try as S-1-5-whatever */
1695
1696                 DOM_SID tmp_sid;
1697
1698                 if (string_to_sid(&tmp_sid, name)) {
1699                         sid_copy(sid, &tmp_sid);
1700                         *type = SID_NAME_UNKNOWN;
1701                         result = NT_STATUS_OK;
1702                 }
1703         }
1704
1705         return result;
1706 }
1707
1708 static NTSTATUS rpc_add_groupmem(struct rpc_pipe_client *pipe_hnd,
1709                                 TALLOC_CTX *mem_ctx,
1710                                 const DOM_SID *group_sid,
1711                                 const char *member)
1712 {
1713         struct policy_handle connect_pol, domain_pol;
1714         NTSTATUS result;
1715         uint32 group_rid;
1716         struct policy_handle group_pol;
1717
1718         struct samr_Ids rids, rid_types;
1719         struct lsa_String lsa_acct_name;
1720
1721         DOM_SID sid;
1722
1723         sid_copy(&sid, group_sid);
1724
1725         if (!sid_split_rid(&sid, &group_rid)) {
1726                 return NT_STATUS_UNSUCCESSFUL;
1727         }
1728
1729         /* Get sam policy handle */
1730         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1731                                       pipe_hnd->desthost,
1732                                       MAXIMUM_ALLOWED_ACCESS,
1733                                       &connect_pol);
1734         if (!NT_STATUS_IS_OK(result)) {
1735                 return result;
1736         }
1737
1738         /* Get domain policy handle */
1739         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1740                                         &connect_pol,
1741                                         MAXIMUM_ALLOWED_ACCESS,
1742                                         &sid,
1743                                         &domain_pol);
1744         if (!NT_STATUS_IS_OK(result)) {
1745                 return result;
1746         }
1747
1748         init_lsa_String(&lsa_acct_name, member);
1749
1750         result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1751                                          &domain_pol,
1752                                          1,
1753                                          &lsa_acct_name,
1754                                          &rids,
1755                                          &rid_types);
1756
1757         if (!NT_STATUS_IS_OK(result)) {
1758                 d_fprintf(stderr, "Could not lookup up group member %s\n", member);
1759                 goto done;
1760         }
1761
1762         result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
1763                                        &domain_pol,
1764                                        MAXIMUM_ALLOWED_ACCESS,
1765                                        group_rid,
1766                                        &group_pol);
1767
1768         if (!NT_STATUS_IS_OK(result)) {
1769                 goto done;
1770         }
1771
1772         result = rpccli_samr_AddGroupMember(pipe_hnd, mem_ctx,
1773                                             &group_pol,
1774                                             rids.ids[0],
1775                                             0x0005); /* unknown flags */
1776
1777  done:
1778         rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
1779         return result;
1780 }
1781
1782 static NTSTATUS rpc_add_aliasmem(struct rpc_pipe_client *pipe_hnd,
1783                                 TALLOC_CTX *mem_ctx,
1784                                 const DOM_SID *alias_sid,
1785                                 const char *member)
1786 {
1787         struct policy_handle connect_pol, domain_pol;
1788         NTSTATUS result;
1789         uint32 alias_rid;
1790         struct policy_handle alias_pol;
1791
1792         DOM_SID member_sid;
1793         enum lsa_SidType member_type;
1794
1795         DOM_SID sid;
1796
1797         sid_copy(&sid, alias_sid);
1798
1799         if (!sid_split_rid(&sid, &alias_rid)) {
1800                 return NT_STATUS_UNSUCCESSFUL;
1801         }
1802
1803         result = get_sid_from_name(rpc_pipe_np_smb_conn(pipe_hnd), mem_ctx,
1804                                    member, &member_sid, &member_type);
1805
1806         if (!NT_STATUS_IS_OK(result)) {
1807                 d_fprintf(stderr, "Could not lookup up group member %s\n", member);
1808                 return result;
1809         }
1810
1811         /* Get sam policy handle */
1812         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1813                                       pipe_hnd->desthost,
1814                                       MAXIMUM_ALLOWED_ACCESS,
1815                                       &connect_pol);
1816         if (!NT_STATUS_IS_OK(result)) {
1817                 goto done;
1818         }
1819
1820         /* Get domain policy handle */
1821         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1822                                         &connect_pol,
1823                                         MAXIMUM_ALLOWED_ACCESS,
1824                                         &sid,
1825                                         &domain_pol);
1826         if (!NT_STATUS_IS_OK(result)) {
1827                 goto done;
1828         }
1829
1830         result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
1831                                        &domain_pol,
1832                                        MAXIMUM_ALLOWED_ACCESS,
1833                                        alias_rid,
1834                                        &alias_pol);
1835
1836         if (!NT_STATUS_IS_OK(result)) {
1837                 return result;
1838         }
1839
1840         result = rpccli_samr_AddAliasMember(pipe_hnd, mem_ctx,
1841                                             &alias_pol,
1842                                             &member_sid);
1843
1844         if (!NT_STATUS_IS_OK(result)) {
1845                 return result;
1846         }
1847
1848  done:
1849         rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
1850         return result;
1851 }
1852
1853 static NTSTATUS rpc_group_addmem_internals(struct net_context *c,
1854                                         const DOM_SID *domain_sid,
1855                                         const char *domain_name,
1856                                         struct cli_state *cli,
1857                                         struct rpc_pipe_client *pipe_hnd,
1858                                         TALLOC_CTX *mem_ctx,
1859                                         int argc,
1860                                         const char **argv)
1861 {
1862         DOM_SID group_sid;
1863         enum lsa_SidType group_type;
1864
1865         if (argc != 2 || c->display_usage) {
1866                 d_printf("Usage:\n"
1867                          "net rpc group addmem <group> <member>\n"
1868                          "  Add a member to a group\n"
1869                          "    group\tGroup to add member to\n"
1870                          "    member\tMember to add to group\n");
1871                 return NT_STATUS_UNSUCCESSFUL;
1872         }
1873
1874         if (!NT_STATUS_IS_OK(get_sid_from_name(cli, mem_ctx, argv[0],
1875                                                &group_sid, &group_type))) {
1876                 d_fprintf(stderr, "Could not lookup group name %s\n", argv[0]);
1877                 return NT_STATUS_UNSUCCESSFUL;
1878         }
1879
1880         if (group_type == SID_NAME_DOM_GRP) {
1881                 NTSTATUS result = rpc_add_groupmem(pipe_hnd, mem_ctx,
1882                                                    &group_sid, argv[1]);
1883
1884                 if (!NT_STATUS_IS_OK(result)) {
1885                         d_fprintf(stderr, "Could not add %s to %s: %s\n",
1886                                  argv[1], argv[0], nt_errstr(result));
1887                 }
1888                 return result;
1889         }
1890
1891         if (group_type == SID_NAME_ALIAS) {
1892                 NTSTATUS result = rpc_add_aliasmem(pipe_hnd, mem_ctx,
1893                                                    &group_sid, argv[1]);
1894
1895                 if (!NT_STATUS_IS_OK(result)) {
1896                         d_fprintf(stderr, "Could not add %s to %s: %s\n",
1897                                  argv[1], argv[0], nt_errstr(result));
1898                 }
1899                 return result;
1900         }
1901
1902         d_fprintf(stderr, "Can only add members to global or local groups "
1903                  "which %s is not\n", argv[0]);
1904
1905         return NT_STATUS_UNSUCCESSFUL;
1906 }
1907
1908 static int rpc_group_addmem(struct net_context *c, int argc, const char **argv)
1909 {
1910         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
1911                                rpc_group_addmem_internals,
1912                                argc, argv);
1913 }
1914
1915 static NTSTATUS rpc_del_groupmem(struct net_context *c,
1916                                 struct rpc_pipe_client *pipe_hnd,
1917                                 TALLOC_CTX *mem_ctx,
1918                                 const DOM_SID *group_sid,
1919                                 const char *member)
1920 {
1921         struct policy_handle connect_pol, domain_pol;
1922         NTSTATUS result;
1923         uint32 group_rid;
1924         struct policy_handle group_pol;
1925
1926         struct samr_Ids rids, rid_types;
1927         struct lsa_String lsa_acct_name;
1928
1929         DOM_SID sid;
1930
1931         sid_copy(&sid, group_sid);
1932
1933         if (!sid_split_rid(&sid, &group_rid))
1934                 return NT_STATUS_UNSUCCESSFUL;
1935
1936         /* Get sam policy handle */
1937         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
1938                                       pipe_hnd->desthost,
1939                                       MAXIMUM_ALLOWED_ACCESS,
1940                                       &connect_pol);
1941         if (!NT_STATUS_IS_OK(result))
1942                 return result;
1943
1944         /* Get domain policy handle */
1945         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
1946                                         &connect_pol,
1947                                         MAXIMUM_ALLOWED_ACCESS,
1948                                         &sid,
1949                                         &domain_pol);
1950         if (!NT_STATUS_IS_OK(result))
1951                 return result;
1952
1953         init_lsa_String(&lsa_acct_name, member);
1954
1955         result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
1956                                          &domain_pol,
1957                                          1,
1958                                          &lsa_acct_name,
1959                                          &rids,
1960                                          &rid_types);
1961         if (!NT_STATUS_IS_OK(result)) {
1962                 d_fprintf(stderr, "Could not lookup up group member %s\n", member);
1963                 goto done;
1964         }
1965
1966         result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
1967                                        &domain_pol,
1968                                        MAXIMUM_ALLOWED_ACCESS,
1969                                        group_rid,
1970                                        &group_pol);
1971
1972         if (!NT_STATUS_IS_OK(result))
1973                 goto done;
1974
1975         result = rpccli_samr_DeleteGroupMember(pipe_hnd, mem_ctx,
1976                                                &group_pol,
1977                                                rids.ids[0]);
1978
1979  done:
1980         rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
1981         return result;
1982 }
1983
1984 static NTSTATUS rpc_del_aliasmem(struct rpc_pipe_client *pipe_hnd,
1985                                 TALLOC_CTX *mem_ctx,
1986                                 const DOM_SID *alias_sid,
1987                                 const char *member)
1988 {
1989         struct policy_handle connect_pol, domain_pol;
1990         NTSTATUS result;
1991         uint32 alias_rid;
1992         struct policy_handle alias_pol;
1993
1994         DOM_SID member_sid;
1995         enum lsa_SidType member_type;
1996
1997         DOM_SID sid;
1998
1999         sid_copy(&sid, alias_sid);
2000
2001         if (!sid_split_rid(&sid, &alias_rid))
2002                 return NT_STATUS_UNSUCCESSFUL;
2003
2004         result = get_sid_from_name(rpc_pipe_np_smb_conn(pipe_hnd), mem_ctx,
2005                                    member, &member_sid, &member_type);
2006
2007         if (!NT_STATUS_IS_OK(result)) {
2008                 d_fprintf(stderr, "Could not lookup up group member %s\n", member);
2009                 return result;
2010         }
2011
2012         /* Get sam policy handle */
2013         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
2014                                       pipe_hnd->desthost,
2015                                       MAXIMUM_ALLOWED_ACCESS,
2016                                       &connect_pol);
2017         if (!NT_STATUS_IS_OK(result)) {
2018                 goto done;
2019         }
2020
2021         /* Get domain policy handle */
2022         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
2023                                         &connect_pol,
2024                                         MAXIMUM_ALLOWED_ACCESS,
2025                                         &sid,
2026                                         &domain_pol);
2027         if (!NT_STATUS_IS_OK(result)) {
2028                 goto done;
2029         }
2030
2031         result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
2032                                        &domain_pol,
2033                                        MAXIMUM_ALLOWED_ACCESS,
2034                                        alias_rid,
2035                                        &alias_pol);
2036
2037         if (!NT_STATUS_IS_OK(result))
2038                 return result;
2039
2040         result = rpccli_samr_DeleteAliasMember(pipe_hnd, mem_ctx,
2041                                                &alias_pol,
2042                                                &member_sid);
2043
2044         if (!NT_STATUS_IS_OK(result))
2045                 return result;
2046
2047  done:
2048         rpccli_samr_Close(pipe_hnd, mem_ctx, &connect_pol);
2049         return result;
2050 }
2051
2052 static NTSTATUS rpc_group_delmem_internals(struct net_context *c,
2053                                         const DOM_SID *domain_sid,
2054                                         const char *domain_name,
2055                                         struct cli_state *cli,
2056                                         struct rpc_pipe_client *pipe_hnd,
2057                                         TALLOC_CTX *mem_ctx,
2058                                         int argc,
2059                                         const char **argv)
2060 {
2061         DOM_SID group_sid;
2062         enum lsa_SidType group_type;
2063
2064         if (argc != 2 || c->display_usage) {
2065                 d_printf("Usage:\n"
2066                          "net rpc group delmem <group> <member>\n"
2067                          "  Delete a member from a group\n"
2068                          "    group\tGroup to delete member from\n"
2069                          "    member\tMember to delete from group\n");
2070                 return NT_STATUS_UNSUCCESSFUL;
2071         }
2072
2073         if (!NT_STATUS_IS_OK(get_sid_from_name(cli, mem_ctx, argv[0],
2074                                                &group_sid, &group_type))) {
2075                 d_fprintf(stderr, "Could not lookup group name %s\n", argv[0]);
2076                 return NT_STATUS_UNSUCCESSFUL;
2077         }
2078
2079         if (group_type == SID_NAME_DOM_GRP) {
2080                 NTSTATUS result = rpc_del_groupmem(c, pipe_hnd, mem_ctx,
2081                                                    &group_sid, argv[1]);
2082
2083                 if (!NT_STATUS_IS_OK(result)) {
2084                         d_fprintf(stderr, "Could not del %s from %s: %s\n",
2085                                  argv[1], argv[0], nt_errstr(result));
2086                 }
2087                 return result;
2088         }
2089
2090         if (group_type == SID_NAME_ALIAS) {
2091                 NTSTATUS result = rpc_del_aliasmem(pipe_hnd, mem_ctx,
2092                                                    &group_sid, argv[1]);
2093
2094                 if (!NT_STATUS_IS_OK(result)) {
2095                         d_fprintf(stderr, "Could not del %s from %s: %s\n",
2096                                  argv[1], argv[0], nt_errstr(result));
2097                 }
2098                 return result;
2099         }
2100
2101         d_fprintf(stderr, "Can only delete members from global or local groups "
2102                  "which %s is not\n", argv[0]);
2103
2104         return NT_STATUS_UNSUCCESSFUL;
2105 }
2106
2107 static int rpc_group_delmem(struct net_context *c, int argc, const char **argv)
2108 {
2109         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
2110                                rpc_group_delmem_internals,
2111                                argc, argv);
2112 }
2113
2114 /**
2115  * List groups on a remote RPC server.
2116  *
2117  * All parameters are provided by the run_rpc_command function, except for
2118  * argc, argv which are passes through.
2119  *
2120  * @param domain_sid The domain sid acquired from the remote server.
2121  * @param cli A cli_state connected to the server.
2122  * @param mem_ctx Talloc context, destroyed on completion of the function.
2123  * @param argc  Standard main() style argc.
2124  * @param argv  Standard main() style argv. Initial components are already
2125  *              stripped.
2126  *
2127  * @return Normal NTSTATUS return.
2128  **/
2129
2130 static NTSTATUS rpc_group_list_internals(struct net_context *c,
2131                                         const DOM_SID *domain_sid,
2132                                         const char *domain_name,
2133                                         struct cli_state *cli,
2134                                         struct rpc_pipe_client *pipe_hnd,
2135                                         TALLOC_CTX *mem_ctx,
2136                                         int argc,
2137                                         const char **argv)
2138 {
2139         struct policy_handle connect_pol, domain_pol;
2140         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
2141         uint32 start_idx=0, max_entries=250, num_entries, i, loop_count = 0;
2142         struct samr_SamArray *groups = NULL;
2143         bool global = false;
2144         bool local = false;
2145         bool builtin = false;
2146
2147         if (c->display_usage) {
2148                 d_printf("Usage:\n"
2149                          "net rpc group list [global] [local] [builtin]\n"
2150                          "  List groups on RPC server\n"
2151                          "    global\tList global groups\n"
2152                          "    local\tList local groups\n"
2153                          "    builtin\tList builtin groups\n"
2154                          "    If none of global, local or builtin is "
2155                          "specified, all three options are considered set\n");
2156                 return NT_STATUS_OK;
2157         }
2158
2159         if (argc == 0) {
2160                 global = true;
2161                 local = true;
2162                 builtin = true;
2163         }
2164
2165         for (i=0; i<argc; i++) {
2166                 if (strequal(argv[i], "global"))
2167                         global = true;
2168
2169                 if (strequal(argv[i], "local"))
2170                         local = true;
2171
2172                 if (strequal(argv[i], "builtin"))
2173                         builtin = true;
2174         }
2175
2176         /* Get sam policy handle */
2177
2178         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
2179                                       pipe_hnd->desthost,
2180                                       MAXIMUM_ALLOWED_ACCESS,
2181                                       &connect_pol);
2182         if (!NT_STATUS_IS_OK(result)) {
2183                 goto done;
2184         }
2185
2186         /* Get domain policy handle */
2187
2188         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
2189                                         &connect_pol,
2190                                         MAXIMUM_ALLOWED_ACCESS,
2191                                         CONST_DISCARD(struct dom_sid2 *, domain_sid),
2192                                         &domain_pol);
2193         if (!NT_STATUS_IS_OK(result)) {
2194                 goto done;
2195         }
2196
2197         /* Query domain groups */
2198         if (c->opt_long_list_entries)
2199                 d_printf("\nGroup name            Comment"
2200                          "\n-----------------------------\n");
2201         do {
2202                 uint32_t max_size, total_size, returned_size;
2203                 union samr_DispInfo info;
2204
2205                 if (!global) break;
2206
2207                 get_query_dispinfo_params(
2208                         loop_count, &max_entries, &max_size);
2209
2210                 result = rpccli_samr_QueryDisplayInfo(pipe_hnd, mem_ctx,
2211                                                       &domain_pol,
2212                                                       3,
2213                                                       start_idx,
2214                                                       max_entries,
2215                                                       max_size,
2216                                                       &total_size,
2217                                                       &returned_size,
2218                                                       &info);
2219                 num_entries = info.info3.count;
2220                 start_idx += info.info3.count;
2221
2222                 if (!NT_STATUS_IS_OK(result) &&
2223                     !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
2224                         break;
2225
2226                 for (i = 0; i < num_entries; i++) {
2227
2228                         const char *group = NULL;
2229                         const char *desc = NULL;
2230
2231                         group = info.info3.entries[i].account_name.string;
2232                         desc = info.info3.entries[i].description.string;
2233
2234                         if (c->opt_long_list_entries)
2235                                 printf("%-21.21s %-50.50s\n",
2236                                        group, desc);
2237                         else
2238                                 printf("%s\n", group);
2239                 }
2240         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
2241         /* query domain aliases */
2242         start_idx = 0;
2243         do {
2244                 if (!local) break;
2245
2246                 result = rpccli_samr_EnumDomainAliases(pipe_hnd, mem_ctx,
2247                                                        &domain_pol,
2248                                                        &start_idx,
2249                                                        &groups,
2250                                                        0xffff,
2251                                                        &num_entries);
2252                 if (!NT_STATUS_IS_OK(result) &&
2253                     !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
2254                         break;
2255
2256                 for (i = 0; i < num_entries; i++) {
2257
2258                         const char *description = NULL;
2259
2260                         if (c->opt_long_list_entries) {
2261
2262                                 struct policy_handle alias_pol;
2263                                 union samr_AliasInfo *info = NULL;
2264
2265                                 if ((NT_STATUS_IS_OK(rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
2266                                                                            &domain_pol,
2267                                                                            0x8,
2268                                                                            groups->entries[i].idx,
2269                                                                            &alias_pol))) &&
2270                                     (NT_STATUS_IS_OK(rpccli_samr_QueryAliasInfo(pipe_hnd, mem_ctx,
2271                                                                                 &alias_pol,
2272                                                                                 3,
2273                                                                                 &info))) &&
2274                                     (NT_STATUS_IS_OK(rpccli_samr_Close(pipe_hnd, mem_ctx,
2275                                                                     &alias_pol)))) {
2276                                         description = info->description.string;
2277                                 }
2278                         }
2279
2280                         if (description != NULL) {
2281                                 printf("%-21.21s %-50.50s\n",
2282                                        groups->entries[i].name.string,
2283                                        description);
2284                         } else {
2285                                 printf("%s\n", groups->entries[i].name.string);
2286                         }
2287                 }
2288         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
2289         rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
2290         /* Get builtin policy handle */
2291
2292         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
2293                                         &connect_pol,
2294                                         MAXIMUM_ALLOWED_ACCESS,
2295                                         CONST_DISCARD(struct dom_sid2 *, &global_sid_Builtin),
2296                                         &domain_pol);
2297         if (!NT_STATUS_IS_OK(result)) {
2298                 goto done;
2299         }
2300         /* query builtin aliases */
2301         start_idx = 0;
2302         do {
2303                 if (!builtin) break;
2304
2305                 result = rpccli_samr_EnumDomainAliases(pipe_hnd, mem_ctx,
2306                                                        &domain_pol,
2307                                                        &start_idx,
2308                                                        &groups,
2309                                                        max_entries,
2310                                                        &num_entries);
2311                 if (!NT_STATUS_IS_OK(result) &&
2312                     !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES))
2313                         break;
2314
2315                 for (i = 0; i < num_entries; i++) {
2316
2317                         const char *description = NULL;
2318
2319                         if (c->opt_long_list_entries) {
2320
2321                                 struct policy_handle alias_pol;
2322                                 union samr_AliasInfo *info = NULL;
2323
2324                                 if ((NT_STATUS_IS_OK(rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
2325                                                                            &domain_pol,
2326                                                                            0x8,
2327                                                                            groups->entries[i].idx,
2328                                                                            &alias_pol))) &&
2329                                     (NT_STATUS_IS_OK(rpccli_samr_QueryAliasInfo(pipe_hnd, mem_ctx,
2330                                                                                 &alias_pol,
2331                                                                                 3,
2332                                                                                 &info))) &&
2333                                     (NT_STATUS_IS_OK(rpccli_samr_Close(pipe_hnd, mem_ctx,
2334                                                                     &alias_pol)))) {
2335                                         description = info->description.string;
2336                                 }
2337                         }
2338
2339                         if (description != NULL) {
2340                                 printf("%-21.21s %-50.50s\n",
2341                                        groups->entries[i].name.string,
2342                                        description);
2343                         } else {
2344                                 printf("%s\n", groups->entries[i].name.string);
2345                         }
2346                 }
2347         } while (NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
2348
2349  done:
2350         return result;
2351 }
2352
2353 static int rpc_group_list(struct net_context *c, int argc, const char **argv)
2354 {
2355         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
2356                                rpc_group_list_internals,
2357                                argc, argv);
2358 }
2359
2360 static NTSTATUS rpc_list_group_members(struct net_context *c,
2361                                         struct rpc_pipe_client *pipe_hnd,
2362                                         TALLOC_CTX *mem_ctx,
2363                                         const char *domain_name,
2364                                         const DOM_SID *domain_sid,
2365                                         struct policy_handle *domain_pol,
2366                                         uint32 rid)
2367 {
2368         NTSTATUS result;
2369         struct policy_handle group_pol;
2370         uint32 num_members, *group_rids;
2371         int i;
2372         struct samr_RidTypeArray *rids = NULL;
2373         struct lsa_Strings names;
2374         struct samr_Ids types;
2375
2376         fstring sid_str;
2377         sid_to_fstring(sid_str, domain_sid);
2378
2379         result = rpccli_samr_OpenGroup(pipe_hnd, mem_ctx,
2380                                        domain_pol,
2381                                        MAXIMUM_ALLOWED_ACCESS,
2382                                        rid,
2383                                        &group_pol);
2384
2385         if (!NT_STATUS_IS_OK(result))
2386                 return result;
2387
2388         result = rpccli_samr_QueryGroupMember(pipe_hnd, mem_ctx,
2389                                               &group_pol,
2390                                               &rids);
2391
2392         if (!NT_STATUS_IS_OK(result))
2393                 return result;
2394
2395         num_members = rids->count;
2396         group_rids = rids->rids;
2397
2398         while (num_members > 0) {
2399                 int this_time = 512;
2400
2401                 if (num_members < this_time)
2402                         this_time = num_members;
2403
2404                 result = rpccli_samr_LookupRids(pipe_hnd, mem_ctx,
2405                                                 domain_pol,
2406                                                 this_time,
2407                                                 group_rids,
2408                                                 &names,
2409                                                 &types);
2410
2411                 if (!NT_STATUS_IS_OK(result))
2412                         return result;
2413
2414                 /* We only have users as members, but make the output
2415                    the same as the output of alias members */
2416
2417                 for (i = 0; i < this_time; i++) {
2418
2419                         if (c->opt_long_list_entries) {
2420                                 printf("%s-%d %s\\%s %d\n", sid_str,
2421                                        group_rids[i], domain_name,
2422                                        names.names[i].string,
2423                                        SID_NAME_USER);
2424                         } else {
2425                                 printf("%s\\%s\n", domain_name,
2426                                         names.names[i].string);
2427                         }
2428                 }
2429
2430                 num_members -= this_time;
2431                 group_rids += 512;
2432         }
2433
2434         return NT_STATUS_OK;
2435 }
2436
2437 static NTSTATUS rpc_list_alias_members(struct net_context *c,
2438                                         struct rpc_pipe_client *pipe_hnd,
2439                                         TALLOC_CTX *mem_ctx,
2440                                         struct policy_handle *domain_pol,
2441                                         uint32 rid)
2442 {
2443         NTSTATUS result;
2444         struct rpc_pipe_client *lsa_pipe;
2445         struct policy_handle alias_pol, lsa_pol;
2446         uint32 num_members;
2447         DOM_SID *alias_sids;
2448         char **domains;
2449         char **names;
2450         enum lsa_SidType *types;
2451         int i;
2452         struct lsa_SidArray sid_array;
2453
2454         result = rpccli_samr_OpenAlias(pipe_hnd, mem_ctx,
2455                                        domain_pol,
2456                                        MAXIMUM_ALLOWED_ACCESS,
2457                                        rid,
2458                                        &alias_pol);
2459
2460         if (!NT_STATUS_IS_OK(result))
2461                 return result;
2462
2463         result = rpccli_samr_GetMembersInAlias(pipe_hnd, mem_ctx,
2464                                                &alias_pol,
2465                                                &sid_array);
2466
2467         if (!NT_STATUS_IS_OK(result)) {
2468                 d_fprintf(stderr, "Couldn't list alias members\n");
2469                 return result;
2470         }
2471
2472         num_members = sid_array.num_sids;
2473
2474         if (num_members == 0) {
2475                 return NT_STATUS_OK;
2476         }
2477
2478         result = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(pipe_hnd),
2479                                           &ndr_table_lsarpc.syntax_id,
2480                                           &lsa_pipe);
2481         if (!NT_STATUS_IS_OK(result)) {
2482                 d_fprintf(stderr, "Couldn't open LSA pipe. Error was %s\n",
2483                         nt_errstr(result) );
2484                 return result;
2485         }
2486
2487         result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, true,
2488                                      SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol);
2489
2490         if (!NT_STATUS_IS_OK(result)) {
2491                 d_fprintf(stderr, "Couldn't open LSA policy handle\n");
2492                 TALLOC_FREE(lsa_pipe);
2493                 return result;
2494         }
2495
2496         alias_sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, num_members);
2497         if (!alias_sids) {
2498                 d_fprintf(stderr, "Out of memory\n");
2499                 TALLOC_FREE(lsa_pipe);
2500                 return NT_STATUS_NO_MEMORY;
2501         }
2502
2503         for (i=0; i<num_members; i++) {
2504                 sid_copy(&alias_sids[i], sid_array.sids[i].sid);
2505         }
2506
2507         result = rpccli_lsa_lookup_sids(lsa_pipe, mem_ctx, &lsa_pol,
2508                                      num_members,  alias_sids,
2509                                      &domains, &names, &types);
2510
2511         if (!NT_STATUS_IS_OK(result) &&
2512             !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED)) {
2513                 d_fprintf(stderr, "Couldn't lookup SIDs\n");
2514                 TALLOC_FREE(lsa_pipe);
2515                 return result;
2516         }
2517
2518         for (i = 0; i < num_members; i++) {
2519                 fstring sid_str;
2520                 sid_to_fstring(sid_str, &alias_sids[i]);
2521
2522                 if (c->opt_long_list_entries) {
2523                         printf("%s %s\\%s %d\n", sid_str,
2524                                domains[i] ? domains[i] : "*unknown*",
2525                                names[i] ? names[i] : "*unknown*", types[i]);
2526                 } else {
2527                         if (domains[i])
2528                                 printf("%s\\%s\n", domains[i], names[i]);
2529                         else
2530                                 printf("%s\n", sid_str);
2531                 }
2532         }
2533
2534         TALLOC_FREE(lsa_pipe);
2535         return NT_STATUS_OK;
2536 }
2537
2538 static NTSTATUS rpc_group_members_internals(struct net_context *c,
2539                                         const DOM_SID *domain_sid,
2540                                         const char *domain_name,
2541                                         struct cli_state *cli,
2542                                         struct rpc_pipe_client *pipe_hnd,
2543                                         TALLOC_CTX *mem_ctx,
2544                                         int argc,
2545                                         const char **argv)
2546 {
2547         NTSTATUS result;
2548         struct policy_handle connect_pol, domain_pol;
2549         struct samr_Ids rids, rid_types;
2550         struct lsa_String lsa_acct_name;
2551
2552         /* Get sam policy handle */
2553
2554         result = rpccli_samr_Connect2(pipe_hnd, mem_ctx,
2555                                       pipe_hnd->desthost,
2556                                       MAXIMUM_ALLOWED_ACCESS,
2557                                       &connect_pol);
2558
2559         if (!NT_STATUS_IS_OK(result))
2560                 return result;
2561
2562         /* Get domain policy handle */
2563
2564         result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
2565                                         &connect_pol,
2566                                         MAXIMUM_ALLOWED_ACCESS,
2567                                         CONST_DISCARD(struct dom_sid2 *, domain_sid),
2568                                         &domain_pol);
2569
2570         if (!NT_STATUS_IS_OK(result))
2571                 return result;
2572
2573         init_lsa_String(&lsa_acct_name, argv[0]); /* sure? */
2574
2575         result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
2576                                          &domain_pol,
2577                                          1,
2578                                          &lsa_acct_name,
2579                                          &rids,
2580                                          &rid_types);
2581
2582         if (!NT_STATUS_IS_OK(result)) {
2583
2584                 /* Ok, did not find it in the global sam, try with builtin */
2585
2586                 DOM_SID sid_Builtin;
2587
2588                 rpccli_samr_Close(pipe_hnd, mem_ctx, &domain_pol);
2589
2590                 sid_copy(&sid_Builtin, &global_sid_Builtin);
2591
2592                 result = rpccli_samr_OpenDomain(pipe_hnd, mem_ctx,
2593                                                 &connect_pol,
2594                                                 MAXIMUM_ALLOWED_ACCESS,
2595                                                 &sid_Builtin,
2596                                                 &domain_pol);
2597
2598                 if (!NT_STATUS_IS_OK(result)) {
2599                         d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
2600                         return result;
2601                 }
2602
2603                 result = rpccli_samr_LookupNames(pipe_hnd, mem_ctx,
2604                                                  &domain_pol,
2605                                                  1,
2606                                                  &lsa_acct_name,
2607                                                  &rids,
2608                                                  &rid_types);
2609
2610                 if (!NT_STATUS_IS_OK(result)) {
2611                         d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
2612                         return result;
2613                 }
2614         }
2615
2616         if (rids.count != 1) {
2617                 d_fprintf(stderr, "Couldn't find group %s\n", argv[0]);
2618                 return result;
2619         }
2620
2621         if (rid_types.ids[0] == SID_NAME_DOM_GRP) {
2622                 return rpc_list_group_members(c, pipe_hnd, mem_ctx, domain_name,
2623                                               domain_sid, &domain_pol,
2624                                               rids.ids[0]);
2625         }
2626
2627         if (rid_types.ids[0] == SID_NAME_ALIAS) {
2628                 return rpc_list_alias_members(c, pipe_hnd, mem_ctx, &domain_pol,
2629                                               rids.ids[0]);
2630         }
2631
2632         return NT_STATUS_NO_SUCH_GROUP;
2633 }
2634
2635 static int rpc_group_members(struct net_context *c, int argc, const char **argv)
2636 {
2637         if (argc != 1 || c->display_usage) {
2638                 return rpc_group_usage(c, argc, argv);
2639         }
2640
2641         return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
2642                                rpc_group_members_internals,
2643                                argc, argv);
2644 }
2645
2646 static int rpc_group_rename_internals(struct net_context *c, int argc, const char **argv)
2647 {
2648         NET_API_STATUS status;
2649         struct GROUP_INFO_0 g0;
2650         uint32_t parm_err;
2651
2652         if (argc != 2) {
2653                 d_printf("Usage: 'net rpc group rename group newname'\n");
2654                 return -1;
2655         }
2656
2657         g0.grpi0_name = argv[1];
2658
2659         status = NetGroupSetInfo(c->opt_host,
2660                                  argv[0],
2661                                  0,
2662                                  (uint8_t *)&g0,
2663                                  &parm_err);
2664
2665         if (status != 0) {
2666                 d_fprintf(stderr, "Renaming group %s failed with: %s\n",
2667                         argv[0], libnetapi_get_error_string(c->netapi_ctx,
2668                         status));
2669                 return -1;
2670         }
2671
2672         return 0;
2673 }
2674
2675 static int rpc_group_rename(struct net_context *c, int argc, const char **argv)
2676 {
2677         if (argc != 2 || c->display_usage) {
2678                 return rpc_group_usage(c, argc, argv);
2679         }
2680
2681         return rpc_group_rename_internals(c, argc, argv);
2682 }
2683
2684 /**
2685  * 'net rpc group' entrypoint.
2686  * @param argc  Standard main() style argc.
2687  * @param argv  Standard main() style argv. Initial components are already
2688  *              stripped.
2689  **/
2690
2691 int net_rpc_group(struct net_context *c, int argc, const char **argv)
2692 {
2693         NET_API_STATUS status;
2694
2695         struct functable func[] = {
2696                 {
2697                         "add",
2698                         rpc_group_add,
2699                         NET_TRANSPORT_RPC,
2700                         "Create specified group",
2701                         "net rpc group add\n"
2702                         "    Create specified group"
2703                 },
2704                 {
2705                         "delete",
2706                         rpc_group_delete,
2707                         NET_TRANSPORT_RPC,
2708                         "Delete specified group",
2709                         "net rpc group delete\n"
2710                         "    Delete specified group"
2711                 },
2712                 {
2713                         "addmem",
2714                         rpc_group_addmem,
2715                         NET_TRANSPORT_RPC,
2716                         "Add member to group",
2717                         "net rpc group addmem\n"
2718                         "    Add member to group"
2719                 },
2720                 {
2721                         "delmem",
2722                         rpc_group_delmem,
2723                         NET_TRANSPORT_RPC,
2724                         "Remove member from group",
2725                         "net rpc group delmem\n"
2726                         "    Remove member from group"
2727                 },
2728                 {
2729                         "list",
2730                         rpc_group_list,
2731                         NET_TRANSPORT_RPC,
2732                         "List groups",
2733                         "net rpc group list\n"
2734                         "    List groups"
2735                 },
2736                 {
2737                         "members",
2738                         rpc_group_members,
2739                         NET_TRANSPORT_RPC,
2740                         "List group members",
2741                         "net rpc group members\n"
2742                         "    List group members"
2743                 },
2744                 {
2745                         "rename",
2746                         rpc_group_rename,
2747                         NET_TRANSPORT_RPC,
2748                         "Rename group",
2749                         "net rpc group rename\n"
2750                         "    Rename group"
2751                 },
2752                 {NULL, NULL, 0, NULL, NULL}
2753         };
2754
2755         status = libnetapi_init(&c->netapi_ctx);
2756         if (status != 0) {
2757                 return -1;
2758         }
2759         libnetapi_set_username(c->netapi_ctx, c->opt_user_name);
2760         libnetapi_set_password(c->netapi_ctx, c->opt_password);
2761         if (c->opt_kerberos) {
2762                 libnetapi_set_use_kerberos(c->netapi_ctx);
2763         }
2764
2765         if (argc == 0) {
2766                 if (c->display_usage) {
2767                         d_printf("Usage:\n");
2768                         d_printf("net rpc group\n"
2769                                  "    Alias for net rpc group list global local "
2770                                  "builtin\n");
2771                         net_display_usage_from_functable(func);
2772                         return 0;
2773                 }
2774
2775                 return run_rpc_command(c, NULL, &ndr_table_samr.syntax_id, 0,
2776                                        rpc_group_list_internals,
2777                                        argc, argv);
2778         }
2779
2780         return net_run_function(c, argc, argv, "net rpc group", func);
2781 }
2782
2783 /****************************************************************************/
2784
2785 static int rpc_share_usage(struct net_context *c, int argc, const char **argv)
2786 {
2787         return net_share_usage(c, argc, argv);
2788 }
2789
2790 /**
2791  * Add a share on a remote RPC server.
2792  *
2793  * @param argc  Standard main() style argc.
2794  * @param argv  Standard main() style argv. Initial components are already
2795  *              stripped.
2796  *
2797  * @return A shell status integer (0 for success).
2798  **/
2799
2800 static int rpc_share_add(struct net_context *c, int argc, const char **argv)
2801 {
2802         NET_API_STATUS status;
2803         char *sharename;
2804         char *path;
2805         uint32 type = STYPE_DISKTREE; /* only allow disk shares to be added */
2806         uint32 num_users=0, perms=0;
2807         char *password=NULL; /* don't allow a share password */
2808         struct SHARE_INFO_2 i2;
2809         uint32_t parm_error = 0;
2810
2811         if ((argc < 1) || !strchr(argv[0], '=') || c->display_usage) {
2812                 return rpc_share_usage(c, argc, argv);
2813         }
2814
2815         if ((sharename = talloc_strdup(c, argv[0])) == NULL) {
2816                 return -1;
2817         }
2818
2819         path = strchr(sharename, '=');
2820         if (!path) {
2821                 return -1;
2822         }
2823
2824         *path++ = '\0';
2825
2826         i2.shi2_netname         = sharename;
2827         i2.shi2_type            = type;
2828         i2.shi2_remark          = c->opt_comment;
2829         i2.shi2_permissions     = perms;
2830         i2.shi2_max_uses        = c->opt_maxusers;
2831         i2.shi2_current_uses    = num_users;
2832         i2.shi2_path            = path;
2833         i2.shi2_passwd          = password;
2834
2835         status = NetShareAdd(c->opt_host,
2836                              2,
2837                              (uint8_t *)&i2,
2838                              &parm_error);
2839         if (status != 0) {
2840                 printf("NetShareAdd failed with: %s\n",
2841                         libnetapi_get_error_string(c->netapi_ctx, status));
2842         }
2843
2844         return status;
2845 }
2846
2847 /**
2848  * Delete a share on a remote RPC server.
2849  *
2850  * @param domain_sid The domain sid acquired from the remote server.
2851  * @param argc  Standard main() style argc.
2852  * @param argv  Standard main() style argv. Initial components are already
2853  *              stripped.
2854  *
2855  * @return A shell status integer (0 for success).
2856  **/
2857 static int rpc_share_delete(struct net_context *c, int argc, const char **argv)
2858 {
2859         if (argc < 1 || c->display_usage) {
2860                 return rpc_share_usage(c, argc, argv);
2861         }
2862
2863         return NetShareDel(c->opt_host, argv[0], 0);
2864 }
2865
2866 /**
2867  * Formatted print of share info
2868  *
2869  * @param r  pointer to SHARE_INFO_1 to format
2870  **/
2871
2872 static void display_share_info_1(struct net_context *c,
2873                                  struct SHARE_INFO_1 *r)
2874 {
2875         if (c->opt_long_list_entries) {
2876                 d_printf("%-12s %-8.8s %-50s\n",
2877                          r->shi1_netname,
2878                          net_share_type_str(r->shi1_type & ~(STYPE_TEMPORARY|STYPE_HIDDEN)),
2879                          r->shi1_remark);
2880         } else {
2881                 d_printf("%s\n", r->shi1_netname);
2882         }
2883 }
2884
2885 static WERROR get_share_info(struct net_context *c,
2886                              struct rpc_pipe_client *pipe_hnd,
2887                              TALLOC_CTX *mem_ctx,
2888                              uint32 level,
2889                              int argc,
2890                              const char **argv,
2891                              struct srvsvc_NetShareInfoCtr *info_ctr)
2892 {
2893         WERROR result;
2894         NTSTATUS status;
2895         union srvsvc_NetShareInfo info;
2896
2897         /* no specific share requested, enumerate all */
2898         if (argc == 0) {
2899
2900                 uint32_t preferred_len = 0xffffffff;
2901                 uint32_t total_entries = 0;
2902                 uint32_t resume_handle = 0;
2903
2904                 info_ctr->level = level;
2905
2906                 status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, mem_ctx,
2907                                                        pipe_hnd->desthost,
2908                                                        info_ctr,
2909                                                        preferred_len,
2910                                                        &total_entries,
2911                                                        &resume_handle,
2912                                                        &result);
2913                 return result;
2914         }
2915
2916         /* request just one share */
2917         status = rpccli_srvsvc_NetShareGetInfo(pipe_hnd, mem_ctx,
2918                                                pipe_hnd->desthost,
2919                                                argv[0],
2920                                                level,
2921                                                &info,
2922                                                &result);
2923
2924         if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) {
2925                 goto done;
2926         }
2927
2928         /* construct ctr */
2929         ZERO_STRUCTP(info_ctr);
2930
2931         info_ctr->level = level;
2932
2933         switch (level) {
2934         case 1:
2935         {
2936                 struct srvsvc_NetShareCtr1 *ctr1;
2937
2938                 ctr1 = TALLOC_ZERO_P(mem_ctx, struct srvsvc_NetShareCtr1);
2939                 W_ERROR_HAVE_NO_MEMORY(ctr1);
2940
2941                 ctr1->count = 1;
2942                 ctr1->array = info.info1;
2943
2944                 info_ctr->ctr.ctr1 = ctr1;
2945         }
2946         case 2:
2947         {
2948                 struct srvsvc_NetShareCtr2 *ctr2;
2949
2950                 ctr2 = TALLOC_ZERO_P(mem_ctx, struct srvsvc_NetShareCtr2);
2951                 W_ERROR_HAVE_NO_MEMORY(ctr2);
2952
2953                 ctr2->count = 1;
2954                 ctr2->array = info.info2;
2955
2956                 info_ctr->ctr.ctr2 = ctr2;
2957         }
2958         case 502:
2959         {
2960                 struct srvsvc_NetShareCtr502 *ctr502;
2961
2962                 ctr502 = TALLOC_ZERO_P(mem_ctx, struct srvsvc_NetShareCtr502);
2963                 W_ERROR_HAVE_NO_MEMORY(ctr502);
2964
2965                 ctr502->count = 1;
2966                 ctr502->array = info.info502;
2967
2968                 info_ctr->ctr.ctr502 = ctr502;
2969         }
2970         } /* switch */
2971 done:
2972         return result;
2973 }
2974
2975 /***
2976  * 'net rpc share list' entrypoint.
2977  * @param argc  Standard main() style argc.
2978  * @param argv  Standard main() style argv. Initial components are already
2979  *              stripped.
2980  **/
2981 static int rpc_share_list(struct net_context *c, int argc, const char **argv)
2982 {
2983         NET_API_STATUS status;
2984         struct SHARE_INFO_1 *i1 = NULL;
2985         uint32_t entries_read = 0;
2986         uint32_t total_entries = 0;
2987         uint32_t resume_handle = 0;
2988         uint32_t i, level = 1;
2989
2990         if (c->display_usage) {
2991                 d_printf("Usage\n"
2992                          "net rpc share list\n"
2993                          "    List shares on remote server\n");
2994                 return 0;
2995         }
2996
2997         status = NetShareEnum(c->opt_host,
2998                               level,
2999                               (uint8_t **)(void *)&i1,
3000                               (uint32_t)-1,
3001                               &entries_read,
3002                               &total_entries,
3003                               &resume_handle);
3004         if (status != 0) {
3005                 goto done;
3006         }
3007
3008         /* Display results */
3009
3010         if (c->opt_long_list_entries) {
3011                 d_printf(
3012         "\nEnumerating shared resources (exports) on remote server:\n\n"
3013         "\nShare name   Type     Description\n"
3014         "----------   ----     -----------\n");
3015         }
3016         for (i = 0; i < entries_read; i++)
3017                 display_share_info_1(c, &i1[i]);
3018  done:
3019         return status;
3020 }
3021
3022 static bool check_share_availability(struct cli_state *cli, const char *netname)
3023 {
3024         if (!NT_STATUS_IS_OK(cli_tcon_andx(cli, netname, "A:", "", 0))) {
3025                 d_printf("skipping   [%s]: not a file share.\n", netname);
3026                 return false;
3027         }
3028
3029         if (!cli_tdis(cli))
3030                 return false;
3031
3032         return true;
3033 }
3034
3035 static bool check_share_sanity(struct net_context *c, struct cli_state *cli,
3036                                const char *netname, uint32 type)
3037 {
3038         /* only support disk shares */
3039         if (! ( type == STYPE_DISKTREE || type == (STYPE_DISKTREE | STYPE_HIDDEN)) ) {
3040                 printf("share [%s] is not a diskshare (type: %x)\n", netname, type);
3041                 return false;
3042         }
3043
3044         /* skip builtin shares */
3045         /* FIXME: should print$ be added too ? */
3046         if (strequal(netname,"IPC$") || strequal(netname,"ADMIN$") ||
3047             strequal(netname,"global"))
3048                 return false;
3049
3050         if (c->opt_exclude && in_list(netname, c->opt_exclude, false)) {
3051                 printf("excluding  [%s]\n", netname);
3052                 return false;
3053         }
3054
3055         return check_share_availability(cli, netname);
3056 }
3057
3058 /**
3059  * Migrate shares from a remote RPC server to the local RPC server.
3060  *
3061  * All parameters are provided by the run_rpc_command function, except for
3062  * argc, argv which are passed through.
3063  *
3064  * @param domain_sid The domain sid acquired from the remote server.
3065  * @param cli A cli_state connected to the server.
3066  * @param mem_ctx Talloc context, destroyed on completion of the function.
3067  * @param argc  Standard main() style argc.
3068  * @param argv  Standard main() style argv. Initial components are already
3069  *              stripped.
3070  *
3071  * @return Normal NTSTATUS return.
3072  **/
3073
3074 static NTSTATUS rpc_share_migrate_shares_internals(struct net_context *c,
3075                                                 const DOM_SID *domain_sid,
3076                                                 const char *domain_name,
3077                                                 struct cli_state *cli,
3078                                                 struct rpc_pipe_client *pipe_hnd,
3079                                                 TALLOC_CTX *mem_ctx,
3080                                                 int argc,
3081                                                 const char **argv)
3082 {
3083         WERROR result;
3084         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
3085         struct srvsvc_NetShareInfoCtr ctr_src;
3086         uint32 i;
3087         struct rpc_pipe_client *srvsvc_pipe = NULL;
3088         struct cli_state *cli_dst = NULL;
3089         uint32 level = 502; /* includes secdesc */
3090         uint32_t parm_error = 0;
3091
3092         result = get_share_info(c, pipe_hnd, mem_ctx, level, argc, argv,
3093                                 &ctr_src);
3094         if (!W_ERROR_IS_OK(result))
3095                 goto done;
3096
3097         /* connect destination PI_SRVSVC */
3098         nt_status = connect_dst_pipe(c, &cli_dst, &srvsvc_pipe,
3099                                      &ndr_table_srvsvc.syntax_id);
3100         if (!NT_STATUS_IS_OK(nt_status))
3101                 return nt_status;
3102
3103
310