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