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