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