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