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