r23779: Change from v2 or later to v3 or later.
[nivanova/samba-autobuild/.git] / source3 / rpcclient / cmd_samr.c
index 34c6fc35abda4ad5bfc0108622df695bec5016db..a29fe1c3d5c19654c2e33a899dceb9967cfe1b3c 100644 (file)
@@ -9,7 +9,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
 
 extern DOM_SID domain_sid;
 
+/****************************************************************************
+ display sam_user_info_7 structure
+ ****************************************************************************/
+static void display_sam_user_info_7(SAM_USER_INFO_7 *usr)
+{
+       fstring temp;
+
+       unistr2_to_ascii(temp, &usr->uni_name, sizeof(temp)-1);
+       printf("\tUser Name   :\t%s\n", temp);
+}
+
+/****************************************************************************
+ display sam_user_info_9 structure
+ ****************************************************************************/
+static void display_sam_user_info_9(SAM_USER_INFO_9 *usr)
+{
+       printf("\tPrimary group RID   :\tox%x\n", usr->rid_group);
+}
+
+/****************************************************************************
+ display sam_user_info_16 structure
+ ****************************************************************************/
+static void display_sam_user_info_16(SAM_USER_INFO_16 *usr)
+{
+       printf("\tAcct Flags   :\tox%x\n", usr->acb_info);
+}
+
 /****************************************************************************
  display sam_user_info_21 structure
  ****************************************************************************/
@@ -58,32 +85,32 @@ static void display_sam_user_info_21(SAM_USER_INFO_21 *usr)
        unistr2_to_ascii(temp, &usr->uni_workstations, sizeof(temp)-1);
        printf("\tWorkstations:\t%s\n", temp);
        
-       unistr2_to_ascii(temp, &usr->uni_unknown_str, sizeof(temp)-1);
+       unistr2_to_ascii(temp, &usr->uni_comment, sizeof(temp)-1);
        printf("\tUnknown Str :\t%s\n", temp);
        
        unistr2_to_ascii(temp, &usr->uni_munged_dial, sizeof(temp)-1);
        printf("\tRemote Dial :\t%s\n", temp);
        
        printf("\tLogon Time               :\t%s\n", 
-              http_timestring(nt_time_to_unix(&usr->logon_time)));
+              http_timestring(nt_time_to_unix(usr->logon_time)));
        printf("\tLogoff Time              :\t%s\n", 
-              http_timestring(nt_time_to_unix(&usr->logoff_time)));
+              http_timestring(nt_time_to_unix(usr->logoff_time)));
        printf("\tKickoff Time             :\t%s\n", 
-              http_timestring(nt_time_to_unix(&usr->kickoff_time)));
+              http_timestring(nt_time_to_unix(usr->kickoff_time)));
        printf("\tPassword last set Time   :\t%s\n", 
-              http_timestring(nt_time_to_unix(&usr->pass_last_set_time)));
+              http_timestring(nt_time_to_unix(usr->pass_last_set_time)));
        printf("\tPassword can change Time :\t%s\n", 
-              http_timestring(nt_time_to_unix(&usr->pass_can_change_time)));
+              http_timestring(nt_time_to_unix(usr->pass_can_change_time)));
        printf("\tPassword must change Time:\t%s\n", 
-              http_timestring(nt_time_to_unix(&usr->pass_must_change_time)));
+              http_timestring(nt_time_to_unix(usr->pass_must_change_time)));
        
        printf("\tunknown_2[0..31]...\n"); /* user passwords? */
        
        printf("\tuser_rid :\t0x%x\n"  , usr->user_rid ); /* User ID */
        printf("\tgroup_rid:\t0x%x\n"  , usr->group_rid); /* Group ID */
-       printf("\tacb_info :\t0x%04x\n", usr->acb_info ); /* Account Control Info */
+       printf("\tacb_info :\t0x%08x\n", usr->acb_info ); /* Account Control Info */
        
-       printf("\tunknown_3:\t0x%08x\n", usr->unknown_3); /* 0x00ff ffff */
+       printf("\tfields_present:\t0x%08x\n", usr->fields_present); /* 0x00ff ffff */
        printf("\tlogon_divs:\t%d\n", usr->logon_divs); /* 0x0000 00a8 which is 168 which is num hrs in a week */
        printf("\tbad_password_count:\t0x%08x\n", usr->bad_password_count);
        printf("\tlogon_count:\t0x%08x\n", usr->logon_count);
@@ -95,52 +122,38 @@ static void display_sam_user_info_21(SAM_USER_INFO_21 *usr)
        }
 }
 
-static const char *display_time(NTTIME nttime)
-{
-       static fstring string;
-
-       float high;
-       float low;
-       int sec;
-       int days, hours, mins, secs;
-
-       if (nttime.high==0 && nttime.low==0)
-               return "Now";
-
-       if (nttime.high==0x80000000 && nttime.low==0)
-               return "Never";
-
-       high = 65536;   
-       high = high/10000;
-       high = high*65536;
-       high = high/1000;
-       high = high * (~nttime.high);
-
-       low = ~nttime.low;      
-       low = low/(1000*1000*10);
 
-       sec=high+low;
-
-       days=sec/(60*60*24);
-       hours=(sec - (days*60*60*24)) / (60*60);
-       mins=(sec - (days*60*60*24) - (hours*60*60) ) / 60;
-       secs=sec - (days*60*60*24) - (hours*60*60) - (mins*60);
-
-       fstr_sprintf(string, "%u days, %u hours, %u minutes, %u seconds", days, hours, mins, secs);
-       return (string);
+static void display_password_properties(uint32 password_properties) 
+{
+       printf("password_properties: 0x%08x\n", password_properties);
+               
+       if (password_properties & DOMAIN_PASSWORD_COMPLEX)
+               printf("\tDOMAIN_PASSWORD_COMPLEX\n");
+                       
+       if (password_properties & DOMAIN_PASSWORD_NO_ANON_CHANGE)
+               printf("\tDOMAIN_PASSWORD_NO_ANON_CHANGE\n");
+                       
+       if (password_properties & DOMAIN_PASSWORD_NO_CLEAR_CHANGE)
+               printf("\tDOMAIN_PASSWORD_NO_CLEAR_CHANGE\n");
+                       
+       if (password_properties & DOMAIN_LOCKOUT_ADMINS)
+               printf("\tDOMAIN_LOCKOUT_ADMINS\n");
+                       
+       if (password_properties & DOMAIN_PASSWORD_STORE_CLEARTEXT)
+               printf("\tDOMAIN_PASSWORD_STORE_CLEARTEXT\n");
+                       
+       if (password_properties & DOMAIN_REFUSE_PASSWORD_CHANGE)
+               printf("\tDOMAIN_REFUSE_PASSWORD_CHANGE\n");
 }
 
 static void display_sam_unk_info_1(SAM_UNK_INFO_1 *info1)
 {
        
-       printf("Minimum password length:                     %d\n", info1->min_length_password);
-       printf("Password uniqueness (remember x passwords):  %d\n", info1->password_history);
-       printf("flag:                                        ");
-       if(info1->flag&&2==2) printf("users must open a session to change password ");
-       printf("\n");
-
-       printf("password expire in:                          %s\n", display_time(info1->expire));
-       printf("Min password age (allow changing in x days): %s\n", display_time(info1->min_passwordage));
+       printf("Minimum password length:\t\t\t%d\n", info1->min_length_password);
+       printf("Password uniqueness (remember x passwords):\t%d\n", info1->password_history);
+       display_password_properties(info1->password_properties);
+       printf("password expire in:\t\t\t\t%s\n", display_time(info1->expire));
+       printf("Min password age (allow changing in x days):\t%s\n", display_time(info1->min_passwordage));
 }
 
 static void display_sam_unk_info_2(SAM_UNK_INFO_2 *info2)
@@ -148,26 +161,90 @@ static void display_sam_unk_info_2(SAM_UNK_INFO_2 *info2)
        fstring name;
 
        unistr2_to_ascii(name, &info2->uni_domain, sizeof(name) - 1); 
-       printf("Domain:\t%s\n", name);
+       printf("Domain:\t\t%s\n", name);
 
        unistr2_to_ascii(name, &info2->uni_server, sizeof(name) - 1); 
-       printf("Server:\t%s\n", name);
+       printf("Server:\t\t%s\n", name);
+
+       unistr2_to_ascii(name, &info2->uni_comment, sizeof(name) - 1); 
+       printf("Comment:\t%s\n", name);
 
        printf("Total Users:\t%d\n", info2->num_domain_usrs);
        printf("Total Groups:\t%d\n", info2->num_domain_grps);
        printf("Total Aliases:\t%d\n", info2->num_local_grps);
        
-       printf("Sequence No:\t%d\n", info2->seq_num);
-       
-       printf("Unknown 0:\t0x%x\n", info2->unknown_0);
-       printf("Unknown 1:\t0x%x\n", info2->unknown_1);
-       printf("Unknown 2:\t0x%x\n", info2->unknown_2);
-       printf("Unknown 3:\t0x%x\n", info2->unknown_3);
+       printf("Sequence No:\t%llu\n", (unsigned long long)info2->seq_num);
+
+       printf("Force Logoff:\t%d\n", (int)nt_time_to_unix_abs(&info2->logout));
+
        printf("Unknown 4:\t0x%x\n", info2->unknown_4);
-       printf("Unknown 5:\t0x%x\n", info2->unknown_5);
+       printf("Server Role:\t%s\n", server_role_str(info2->server_role));
        printf("Unknown 6:\t0x%x\n", info2->unknown_6);
 }
 
+static void display_sam_unk_info_3(SAM_UNK_INFO_3 *info3)
+{
+       printf("Force Logoff:\t%d\n", (int)nt_time_to_unix_abs(&info3->logout));
+}
+
+static void display_sam_unk_info_4(SAM_UNK_INFO_4 *info4)
+{
+       fstring name;
+
+       unistr2_to_ascii(name, &info4->uni_comment, sizeof(name) - 1); 
+       printf("Comment:\t%s\n", name);
+}
+
+static void display_sam_unk_info_5(SAM_UNK_INFO_5 *info5)
+{
+       fstring name;
+
+       unistr2_to_ascii(name, &info5->uni_domain, sizeof(name) - 1); 
+       printf("Domain:\t\t%s\n", name);
+}
+
+static void display_sam_unk_info_6(SAM_UNK_INFO_6 *info6)
+{
+       fstring name;
+
+       unistr2_to_ascii(name, &info6->uni_server, sizeof(name) - 1); 
+       printf("Server:\t\t%s\n", name);
+}
+
+static void display_sam_unk_info_7(SAM_UNK_INFO_7 *info7)
+{
+       printf("Server Role:\t%s\n", server_role_str(info7->server_role));
+}
+
+static void display_sam_unk_info_8(SAM_UNK_INFO_8 *info8)
+{
+       printf("Sequence No:\t%llu\n", (unsigned long long)info8->seq_num);
+       printf("Domain Create Time:\t%s\n", 
+               http_timestring(nt_time_to_unix(info8->domain_create_time)));
+}
+
+static void display_sam_unk_info_9(SAM_UNK_INFO_9 *info9)
+{
+       printf("unknown:\t%d (0x%08x)\n", info9->unknown, info9->unknown);
+}
+
+static void display_sam_unk_info_12(SAM_UNK_INFO_12 *info12)
+{
+       printf("Bad password lockout duration:               %s\n", display_time(info12->duration));
+       printf("Reset Lockout after:                         %s\n", display_time(info12->reset_count));
+       printf("Lockout after bad attempts:                  %d\n", info12->bad_attempt_lockout);
+}
+
+static void display_sam_unk_info_13(SAM_UNK_INFO_13 *info13)
+{
+       printf("Sequence No:\t%llu\n", (unsigned long long)info13->seq_num);
+       printf("Domain Create Time:\t%s\n", 
+               http_timestring(nt_time_to_unix(info13->domain_create_time)));
+       printf("Unknown1:\t%d\n", info13->unknown1);
+       printf("Unknown2:\t%d\n", info13->unknown2);
+
+}
+
 static void display_sam_info_1(SAM_ENTRY1 *e1, SAM_STR1 *s1)
 {
        fstring tmp;
@@ -247,14 +324,14 @@ static void display_sam_info_5(SAM_ENTRY5 *e5, SAM_STR5 *s5)
 /****************************************************************************
  Try samr_connect4 first, then samr_conenct if it fails
  ****************************************************************************/
-static NTSTATUS try_samr_connects(struct cli_state *cli, TALLOC_CTX *mem_ctx, 
+static NTSTATUS try_samr_connects(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, 
                                  uint32 access_mask, POLICY_HND *connect_pol)
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        
-       result = cli_samr_connect4(cli, mem_ctx, access_mask, connect_pol);
+       result = rpccli_samr_connect4(cli, mem_ctx, access_mask, connect_pol);
        if (!NT_STATUS_IS_OK(result)) {
-               result = cli_samr_connect(cli, mem_ctx, access_mask,
+               result = rpccli_samr_connect(cli, mem_ctx, access_mask,
                                          connect_pol);
        }
        return result;
@@ -263,7 +340,7 @@ static NTSTATUS try_samr_connects(struct cli_state *cli, TALLOC_CTX *mem_ctx,
 /**********************************************************************
  * Query user information 
  */
-static NTSTATUS cmd_samr_query_user(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_user(struct rpc_pipe_client *cli, 
                                     TALLOC_CTX *mem_ctx,
                                     int argc, const char **argv) 
 {
@@ -273,7 +350,7 @@ static NTSTATUS cmd_samr_query_user(struct cli_state *cli,
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
        SAM_USERINFO_CTR *user_ctr;
        fstring server;
-       uint32 user_rid;
+       uint32 user_rid = 0;
        
        if ((argc < 2) || (argc > 4)) {
                printf("Usage: %s rid [info level] [access mask] \n", argv[0]);
@@ -289,7 +366,7 @@ static NTSTATUS cmd_samr_query_user(struct cli_state *cli,
                sscanf(argv[3], "%x", &access_mask);
        
 
-       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->cli->desthost);
        strupper_m(server);
        
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
@@ -298,29 +375,70 @@ static NTSTATUS cmd_samr_query_user(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      MAXIMUM_ALLOWED_ACCESS,
                                      &domain_sid, &domain_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_open_user(cli, mem_ctx, &domain_pol,
                                    access_mask,
                                    user_rid, &user_pol);
 
+       if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER) &&
+           (user_rid == 0)) {
+
+               /* Probably this was a user name, try lookupnames */
+               uint32 num_rids;
+               uint32 *rids, *types;
+               
+               result = rpccli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+                                                 1000, 1, &argv[1],
+                                                 &num_rids, &rids,
+                                                 &types);
+
+               if (NT_STATUS_IS_OK(result)) {
+                       result = rpccli_samr_open_user(cli, mem_ctx,
+                                                      &domain_pol,
+                                                      access_mask,
+                                                      rids[0], &user_pol);
+               }
+       }
+
+
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
        ZERO_STRUCT(user_ctr);
 
-       result = cli_samr_query_userinfo(cli, mem_ctx, &user_pol, 
+       result = rpccli_samr_query_userinfo(cli, mem_ctx, &user_pol, 
                                         info_level, &user_ctr);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       display_sam_user_info_21(user_ctr->info.id21);
+       switch (user_ctr->switch_value) {
+       case 7:
+               display_sam_user_info_7(user_ctr->info.id7);
+               break;
+       case 9:
+               display_sam_user_info_9(user_ctr->info.id9);
+               break;
+       case 16:
+               display_sam_user_info_16(user_ctr->info.id16);
+               break;
+       case 21:
+               display_sam_user_info_21(user_ctr->info.id21);
+               break;
+       default:
+               printf("Unsupported infolevel: %d\n", info_level);
+               break;
+       }
+
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
 
 done:
        return result;
@@ -337,10 +455,31 @@ static void display_group_info1(GROUP_INFO1 *info1)
        printf("\tGroup Name:\t%s\n", temp);
        unistr2_to_ascii(temp, &info1->uni_acct_desc, sizeof(temp)-1);
        printf("\tDescription:\t%s\n", temp);
-       printf("\tunk1:%d\n", info1->unknown_1);
+       printf("\tGroup Attribute:%d\n", info1->group_attr);
        printf("\tNum Members:%d\n", info1->num_members);
 }
 
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info2(GROUP_INFO2 *info2)
+{
+       fstring name;
+
+       unistr2_to_ascii(name, &info2->uni_acct_name, sizeof(name)-1);
+       printf("\tGroup Description:%s\n", name);
+}
+
+
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info3(GROUP_INFO3 *info3)
+{
+       printf("\tGroup Attribute:%d\n", info3->group_attr);
+}
+
+
 /****************************************************************************
  display group info
  ****************************************************************************/
@@ -352,27 +491,50 @@ static void display_group_info4(GROUP_INFO4 *info4)
        printf("\tGroup Description:%s\n", desc);
 }
 
+/****************************************************************************
+ display group info
+ ****************************************************************************/
+static void display_group_info5(GROUP_INFO5 *info5)
+{
+       fstring temp;
+
+       unistr2_to_ascii(temp, &info5->uni_acct_name, sizeof(temp)-1);
+       printf("\tGroup Name:\t%s\n", temp);
+       unistr2_to_ascii(temp, &info5->uni_acct_desc, sizeof(temp)-1);
+       printf("\tDescription:\t%s\n", temp);
+       printf("\tGroup Attribute:%d\n", info5->group_attr);
+       printf("\tNum Members:%d\n", info5->num_members);
+}
+
 /****************************************************************************
  display sam sync structure
  ****************************************************************************/
 static void display_group_info_ctr(GROUP_INFO_CTR *ctr)
 {
        switch (ctr->switch_value1) {
-           case 1: {
-                   display_group_info1(&ctr->group.info1);
-                   break;
-           }
-           case 4: {
-                   display_group_info4(&ctr->group.info4);
-                   break;
-           }
+               case 1:
+                       display_group_info1(&ctr->group.info1);
+                       break;
+               case 2:
+                       display_group_info2(&ctr->group.info2);
+                       break;
+               case 3:
+                       display_group_info3(&ctr->group.info3);
+                       break;
+               case 4:
+                       display_group_info4(&ctr->group.info4);
+                       break;
+               case 5:
+                       display_group_info5(&ctr->group.info5);
+                       break;
+
        }
 }
 
 /***********************************************************************
  * Query group information 
  */
-static NTSTATUS cmd_samr_query_group(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_group(struct rpc_pipe_client *cli, 
                                      TALLOC_CTX *mem_ctx,
                                      int argc, const char **argv) 
 {
@@ -397,7 +559,7 @@ static NTSTATUS cmd_samr_query_group(struct cli_state *cli,
        if (argc > 3)
                sscanf(argv[3], "%x", &access_mask);
 
-       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->cli->desthost);
        strupper_m(server);
 
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
@@ -406,21 +568,21 @@ static NTSTATUS cmd_samr_query_group(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      MAXIMUM_ALLOWED_ACCESS,
                                      &domain_sid, &domain_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_group(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_open_group(cli, mem_ctx, &domain_pol,
                                     access_mask,
                                     group_rid, &group_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_query_groupinfo(cli, mem_ctx, &group_pol, 
+       result = rpccli_samr_query_groupinfo(cli, mem_ctx, &group_pol, 
                                          info_level, &group_ctr);
        if (!NT_STATUS_IS_OK(result)) {
                goto done;
@@ -428,13 +590,16 @@ static NTSTATUS cmd_samr_query_group(struct cli_state *cli,
 
        display_group_info_ctr(group_ctr);
 
+       rpccli_samr_close(cli, mem_ctx, &group_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
 done:
        return result;
 }
 
 /* Query groups a user is a member of */
 
-static NTSTATUS cmd_samr_query_usergroups(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_usergroups(struct rpc_pipe_client *cli, 
                                           TALLOC_CTX *mem_ctx,
                                           int argc, const char **argv) 
 {
@@ -459,7 +624,7 @@ static NTSTATUS cmd_samr_query_usergroups(struct cli_state *cli,
        if (argc > 2)
                sscanf(argv[2], "%x", &access_mask);
 
-       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->cli->desthost);
        strupper_m(server);
                
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
@@ -468,21 +633,21 @@ static NTSTATUS cmd_samr_query_usergroups(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      MAXIMUM_ALLOWED_ACCESS,
                                      &domain_sid, &domain_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_open_user(cli, mem_ctx, &domain_pol,
                                    access_mask,
                                    user_rid, &user_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_query_usergroups(cli, mem_ctx, &user_pol,
+       result = rpccli_samr_query_usergroups(cli, mem_ctx, &user_pol,
                                           &num_groups, &user_gids);
 
        if (!NT_STATUS_IS_OK(result))
@@ -493,39 +658,62 @@ static NTSTATUS cmd_samr_query_usergroups(struct cli_state *cli,
                       user_gids[i].g_rid, user_gids[i].attr);
        }
 
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
        return result;
 }
 
 /* Query aliases a user is a member of */
 
-static NTSTATUS cmd_samr_query_useraliases(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_useraliases(struct rpc_pipe_client *cli, 
                                           TALLOC_CTX *mem_ctx,
                                           int argc, const char **argv) 
 {
        POLICY_HND              connect_pol, domain_pol;
        NTSTATUS                result = NT_STATUS_UNSUCCESSFUL;
-       uint32                  user_rid, num_aliases, *alias_rids;
+       DOM_SID                *sids;
+       size_t                     num_sids;
+       uint32                  num_aliases, *alias_rids;
        uint32                  access_mask = MAXIMUM_ALLOWED_ACCESS;
        int                     i;
        fstring                 server;
-       DOM_SID                 tmp_sid;
-       DOM_SID2                sid;
-       DOM_SID global_sid_Builtin;
+       DOM_SID2               *sid2;
 
-       string_to_sid(&global_sid_Builtin, "S-1-5-32");
+       if (argc < 3) {
+               printf("Usage: %s builtin|domain sid1 sid2 ...\n", argv[0]);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
-       if ((argc < 3) || (argc > 4)) {
-               printf("Usage: %s builtin|domain rid [access mask]\n", argv[0]);
-               return NT_STATUS_OK;
+       sids = NULL;
+       num_sids = 0;
+
+       for (i=2; i<argc; i++) {
+               DOM_SID tmp_sid;
+               if (!string_to_sid(&tmp_sid, argv[i])) {
+                       printf("%s is not a legal SID\n", argv[i]);
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+               if (!add_sid_to_array(mem_ctx, &tmp_sid, &sids, &num_sids)) {
+                       return NT_STATUS_NO_MEMORY;
+               }
        }
 
-       sscanf(argv[2], "%i", &user_rid);
-       
-       if (argc > 3)
-               sscanf(argv[3], "%x", &access_mask);
+       if (num_sids) {
+               sid2 = TALLOC_ARRAY(mem_ctx, DOM_SID2, num_sids);
+               if (sid2 == NULL)
+                       return NT_STATUS_NO_MEMORY;
+       } else {
+               sid2 = NULL;
+       }
+
+       for (i=0; i<num_sids; i++) {
+               sid_copy(&sid2[i].sid, &sids[i]);
+               sid2[i].num_auths = sid2[i].sid.num_auths;
+       }
 
-       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->cli->desthost);
        strupper_m(server);
                
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
@@ -535,24 +723,25 @@ static NTSTATUS cmd_samr_query_useraliases(struct cli_state *cli,
                goto done;
 
        if (StrCaseCmp(argv[1], "domain")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              access_mask,
                                              &domain_sid, &domain_pol);
        else if (StrCaseCmp(argv[1], "builtin")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              access_mask,
-                                             &global_sid_Builtin, &domain_pol);
-       else
-               return NT_STATUS_OK;
+                                             &global_sid_Builtin,
+                                             &domain_pol);
+       else {
+               printf("Usage: %s builtin|domain sid1 sid2 ...\n", argv[0]);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       sid_copy(&tmp_sid, &domain_sid);
-       sid_append_rid(&tmp_sid, user_rid);
-       init_dom_sid2(&sid, &tmp_sid);
-
-       result = cli_samr_query_useraliases(cli, mem_ctx, &domain_pol, 1, &sid, &num_aliases, &alias_rids);
+       result = rpccli_samr_query_useraliases(cli, mem_ctx, &domain_pol,
+                                           num_sids, sid2,
+                                           &num_aliases, &alias_rids);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
@@ -561,13 +750,15 @@ static NTSTATUS cmd_samr_query_useraliases(struct cli_state *cli,
                printf("\tgroup rid:[0x%x]\n", alias_rids[i]);
        }
 
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
        return result;
 }
 
 /* Query members of a group */
 
-static NTSTATUS cmd_samr_query_groupmem(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_groupmem(struct rpc_pipe_client *cli, 
                                         TALLOC_CTX *mem_ctx,
                                         int argc, const char **argv) 
 {
@@ -577,6 +768,7 @@ static NTSTATUS cmd_samr_query_groupmem(struct cli_state *cli,
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
        int i;
        fstring                 server;
+       unsigned int old_timeout;
        
        if ((argc < 2) || (argc > 3)) {
                printf("Usage: %s rid [access mask]\n", argv[0]);
@@ -588,7 +780,7 @@ static NTSTATUS cmd_samr_query_groupmem(struct cli_state *cli,
        if (argc > 2)
                sscanf(argv[2], "%x", &access_mask);
 
-       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->cli->desthost);
        strupper_m(server);
 
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
@@ -597,24 +789,29 @@ static NTSTATUS cmd_samr_query_groupmem(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      MAXIMUM_ALLOWED_ACCESS,
                                      &domain_sid, &domain_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_group(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_open_group(cli, mem_ctx, &domain_pol,
                                     access_mask,
                                     group_rid, &group_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_query_groupmem(cli, mem_ctx, &group_pol,
+       /* Make sure to wait for our DC's reply */
+       old_timeout = cli_set_timeout(cli->cli, MAX(cli->cli->timeout,30000)); /* 30 seconds. */
+
+       result = rpccli_samr_query_groupmem(cli, mem_ctx, &group_pol,
                                         &num_members, &group_rids,
                                         &group_attrs);
 
+       cli_set_timeout(cli->cli, old_timeout);
+
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
@@ -623,13 +820,16 @@ static NTSTATUS cmd_samr_query_groupmem(struct cli_state *cli,
                       group_attrs[i]);
        }
 
+       rpccli_samr_close(cli, mem_ctx, &group_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
        return result;
 }
 
 /* Enumerate domain users */
 
-static NTSTATUS cmd_samr_enum_dom_users(struct cli_state *cli, 
+static NTSTATUS cmd_samr_enum_dom_users(struct rpc_pipe_client *cli, 
                                        TALLOC_CTX *mem_ctx,
                                        int argc, const char **argv) 
 {
@@ -639,17 +839,20 @@ static NTSTATUS cmd_samr_enum_dom_users(struct cli_state *cli,
        char **dom_users;
        uint32 *dom_rids;
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
-       uint16 acb_mask = ACB_NORMAL;
+       uint32 acb_mask = ACB_NORMAL;
        BOOL got_connect_pol = False, got_domain_pol = False;
 
-       if ((argc < 1) || (argc > 2)) {
-               printf("Usage: %s [access_mask]\n", argv[0]);
+       if ((argc < 1) || (argc > 3)) {
+               printf("Usage: %s [access_mask] [acb_mask]\n", argv[0]);
                return NT_STATUS_OK;
        }
        
        if (argc > 1)
                sscanf(argv[1], "%x", &access_mask);
 
+       if (argc > 2)
+               sscanf(argv[2], "%x", &acb_mask);
+
        /* Get sam policy handle */
 
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
@@ -662,7 +865,7 @@ static NTSTATUS cmd_samr_enum_dom_users(struct cli_state *cli,
 
        /* Get domain policy handle */
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      access_mask,
                                      &domain_sid, &domain_pol);
 
@@ -677,7 +880,7 @@ static NTSTATUS cmd_samr_enum_dom_users(struct cli_state *cli,
        size = 0xffff;
 
        do {
-               result = cli_samr_enum_dom_users(
+               result = rpccli_samr_enum_dom_users(
                        cli, mem_ctx, &domain_pol, &start_idx, acb_mask,
                        size, &dom_users, &dom_rids, &num_dom_users);
 
@@ -693,17 +896,17 @@ static NTSTATUS cmd_samr_enum_dom_users(struct cli_state *cli,
 
  done:
        if (got_domain_pol)
-               cli_samr_close(cli, mem_ctx, &domain_pol);
+               rpccli_samr_close(cli, mem_ctx, &domain_pol);
 
        if (got_connect_pol)
-               cli_samr_close(cli, mem_ctx, &connect_pol);
+               rpccli_samr_close(cli, mem_ctx, &connect_pol);
 
        return result;
 }
 
 /* Enumerate domain groups */
 
-static NTSTATUS cmd_samr_enum_dom_groups(struct cli_state *cli, 
+static NTSTATUS cmd_samr_enum_dom_groups(struct rpc_pipe_client *cli, 
                                          TALLOC_CTX *mem_ctx,
                                          int argc, const char **argv) 
 {
@@ -734,7 +937,7 @@ static NTSTATUS cmd_samr_enum_dom_groups(struct cli_state *cli,
 
        /* Get domain policy handle */
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      access_mask,
                                      &domain_sid, &domain_pol);
 
@@ -749,7 +952,7 @@ static NTSTATUS cmd_samr_enum_dom_groups(struct cli_state *cli,
        size = 0xffff;
 
        do {
-               result = cli_samr_enum_dom_groups(
+               result = rpccli_samr_enum_dom_groups(
                        cli, mem_ctx, &domain_pol, &start_idx, size,
                        &dom_groups, &num_dom_groups);
 
@@ -766,17 +969,17 @@ static NTSTATUS cmd_samr_enum_dom_groups(struct cli_state *cli,
 
  done:
        if (got_domain_pol)
-               cli_samr_close(cli, mem_ctx, &domain_pol);
+               rpccli_samr_close(cli, mem_ctx, &domain_pol);
 
        if (got_connect_pol)
-               cli_samr_close(cli, mem_ctx, &connect_pol);
+               rpccli_samr_close(cli, mem_ctx, &connect_pol);
 
        return result;
 }
 
 /* Enumerate alias groups */
 
-static NTSTATUS cmd_samr_enum_als_groups(struct cli_state *cli, 
+static NTSTATUS cmd_samr_enum_als_groups(struct rpc_pipe_client *cli, 
                                          TALLOC_CTX *mem_ctx,
                                          int argc, const char **argv) 
 {
@@ -785,11 +988,8 @@ static NTSTATUS cmd_samr_enum_als_groups(struct cli_state *cli,
        uint32 start_idx, size, num_als_groups, i;
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
        struct acct_info *als_groups;
-       DOM_SID global_sid_Builtin;
        BOOL got_connect_pol = False, got_domain_pol = False;
 
-       string_to_sid(&global_sid_Builtin, "S-1-5-32");
-
        if ((argc < 2) || (argc > 3)) {
                printf("Usage: %s builtin|domain [access mask]\n", argv[0]);
                return NT_STATUS_OK;
@@ -811,11 +1011,11 @@ static NTSTATUS cmd_samr_enum_als_groups(struct cli_state *cli,
        /* Get domain policy handle */
 
        if (StrCaseCmp(argv[1], "domain")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              access_mask,
                                              &domain_sid, &domain_pol);
        else if (StrCaseCmp(argv[1], "builtin")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              access_mask,
                                              &global_sid_Builtin, &domain_pol);
        else
@@ -832,7 +1032,7 @@ static NTSTATUS cmd_samr_enum_als_groups(struct cli_state *cli,
        size = 0xffff;          /* Number of groups to retrieve */
 
        do {
-               result = cli_samr_enum_als_groups(
+               result = rpccli_samr_enum_als_groups(
                        cli, mem_ctx, &domain_pol, &start_idx, size,
                        &als_groups, &num_als_groups);
 
@@ -848,17 +1048,17 @@ static NTSTATUS cmd_samr_enum_als_groups(struct cli_state *cli,
 
  done:
        if (got_domain_pol)
-               cli_samr_close(cli, mem_ctx, &domain_pol);
+               rpccli_samr_close(cli, mem_ctx, &domain_pol);
        
        if (got_connect_pol)
-               cli_samr_close(cli, mem_ctx, &connect_pol);
+               rpccli_samr_close(cli, mem_ctx, &connect_pol);
        
        return result;
 }
 
 /* Query alias membership */
 
-static NTSTATUS cmd_samr_query_aliasmem(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_aliasmem(struct rpc_pipe_client *cli, 
                                         TALLOC_CTX *mem_ctx,
                                         int argc, const char **argv) 
 {
@@ -867,9 +1067,6 @@ static NTSTATUS cmd_samr_query_aliasmem(struct cli_state *cli,
        uint32 alias_rid, num_members, i;
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
        DOM_SID *alias_sids;
-       DOM_SID global_sid_Builtin;
-       
-       string_to_sid(&global_sid_Builtin, "S-1-5-32");
 
        if ((argc < 3) || (argc > 4)) {
                printf("Usage: %s builtin|domain rid [access mask]\n", argv[0]);
@@ -892,11 +1089,11 @@ static NTSTATUS cmd_samr_query_aliasmem(struct cli_state *cli,
        /* Open handle on domain */
        
        if (StrCaseCmp(argv[1], "domain")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              MAXIMUM_ALLOWED_ACCESS,
                                              &domain_sid, &domain_pol);
        else if (StrCaseCmp(argv[1], "builtin")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              MAXIMUM_ALLOWED_ACCESS,
                                              &global_sid_Builtin, &domain_pol);
        else
@@ -907,13 +1104,13 @@ static NTSTATUS cmd_samr_query_aliasmem(struct cli_state *cli,
 
        /* Open handle on alias */
 
-       result = cli_samr_open_alias(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_open_alias(cli, mem_ctx, &domain_pol,
                                     access_mask,
                                     alias_rid, &alias_pol);
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_query_aliasmem(cli, mem_ctx, &alias_pol,
+       result = rpccli_samr_query_aliasmem(cli, mem_ctx, &alias_pol,
                                         &num_members, &alias_sids);
 
        if (!NT_STATUS_IS_OK(result))
@@ -926,19 +1123,99 @@ static NTSTATUS cmd_samr_query_aliasmem(struct cli_state *cli,
                printf("\tsid:[%s]\n", sid_str);
        }
 
+       rpccli_samr_close(cli, mem_ctx, &alias_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+ done:
+       return result;
+}
+
+/* Query delete an alias membership */
+
+static NTSTATUS cmd_samr_delete_alias(struct rpc_pipe_client *cli, 
+                                     TALLOC_CTX *mem_ctx,
+                                     int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol, alias_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       uint32 alias_rid;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+       if (argc != 3) {
+               printf("Usage: %s builtin|domain [rid|name]\n", argv[0]);
+               return NT_STATUS_OK;
+       }
+
+       alias_rid = strtoul(argv[2], NULL, 10);
+       
+       /* Open SAMR handle */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Open handle on domain */
+       
+       if (StrCaseCmp(argv[1], "domain")==0)
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                             MAXIMUM_ALLOWED_ACCESS,
+                                             &domain_sid, &domain_pol);
+       else if (StrCaseCmp(argv[1], "builtin")==0)
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                             MAXIMUM_ALLOWED_ACCESS,
+                                             &global_sid_Builtin, &domain_pol);
+       else
+               return NT_STATUS_INVALID_PARAMETER;
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Open handle on alias */
+
+       result = rpccli_samr_open_alias(cli, mem_ctx, &domain_pol,
+                                    access_mask,
+                                    alias_rid, &alias_pol);
+       if (!NT_STATUS_IS_OK(result) && (alias_rid == 0)) {
+               /* Probably this was a user name, try lookupnames */
+               uint32 num_rids;
+               uint32 *rids, *types;
+               
+               result = rpccli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+                                                 1000, 1, &argv[2],
+                                                 &num_rids, &rids,
+                                                 &types);
+
+               if (NT_STATUS_IS_OK(result)) {
+                       result = rpccli_samr_open_alias(cli, mem_ctx,
+                                                      &domain_pol,
+                                                      access_mask,
+                                                      rids[0], &alias_pol);
+               }
+       }
+
+       result = rpccli_samr_delete_dom_alias(cli, mem_ctx, &alias_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
        return result;
 }
 
 /* Query display info */
 
-static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli, 
-                                        TALLOC_CTX *mem_ctx,
-                                        int argc, const char **argv) 
+static NTSTATUS cmd_samr_query_dispinfo_int(struct rpc_pipe_client *cli, 
+                                           TALLOC_CTX *mem_ctx,
+                                           int argc, const char **argv, 
+                                           int opcode)
 {
        POLICY_HND connect_pol, domain_pol;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uint32 start_idx=0, max_entries=250, max_size = 0xffff, num_entries, i;
+       uint32 start_idx=0, max_entries=250, max_size = (uint32) -1, num_entries, i;
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
        uint32 info_level = 1;
        SAM_DISPINFO_CTR ctr;
@@ -950,7 +1227,7 @@ static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli,
        int loop_count = 0;
        BOOL got_params = False; /* Use get_query_dispinfo_params() or not? */
 
-       if (argc > 5) {
+       if (argc > 6) {
                printf("Usage: %s [info level] [start index] [max entries] [max size] [access mask]\n", argv[0]);
                return NT_STATUS_OK;
        }
@@ -974,6 +1251,7 @@ static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli,
        if (argc >= 6)
                 sscanf(argv[5], "%x", &access_mask);
 
+
        /* Get sam policy handle */
 
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
@@ -984,7 +1262,7 @@ static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli,
 
        /* Get domain policy handle */
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      access_mask, 
                                      &domain_sid, &domain_pol);
 
@@ -1020,20 +1298,40 @@ static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli,
        }
 
 
-       while(1) {
+       do {
 
                if (!got_params)
                        get_query_dispinfo_params(
                                loop_count, &max_entries, &max_size);
-               
-               result = cli_samr_query_dispinfo(cli, mem_ctx, &domain_pol,
-                                                &start_idx, info_level,
-                                                &num_entries, max_entries, 
-                                                max_size, &ctr);
+
+               switch (opcode) {
+               case SAMR_QUERY_DISPINFO:
+                       result = rpccli_samr_query_dispinfo(cli, mem_ctx, &domain_pol,
+                                                           &start_idx, info_level,
+                                                           &num_entries, max_entries, 
+                                                           max_size, &ctr);
+                       break;
+               case SAMR_QUERY_DISPINFO2:
+                       result = rpccli_samr_query_dispinfo2(cli, mem_ctx, &domain_pol,
+                                                            &start_idx, info_level,
+                                                            &num_entries, max_entries, 
+                                                            max_size, &ctr);
+                       break;
+               case SAMR_QUERY_DISPINFO3:
+                       result = rpccli_samr_query_dispinfo3(cli, mem_ctx, &domain_pol,
+                                                            &start_idx, info_level,
+                                                            &num_entries, max_entries, 
+                                                            max_size, &ctr);
+                       break;
+               default:
+                       printf("unknown opcode: %d\n", opcode);
+                       return NT_STATUS_INVALID_PARAMETER;
+                       break;
+               }
 
                loop_count++;
 
-               if (!NT_STATUS_IS_OK(result) && !NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES)) 
+               if (NT_STATUS_IS_ERR(result))
                        break;
 
                if (num_entries == 0) 
@@ -1058,92 +1356,230 @@ static NTSTATUS cmd_samr_query_dispinfo(struct cli_state *cli,
                                break;
                        }
                }
-       }
+       } while ( NT_STATUS_EQUAL(result, STATUS_MORE_ENTRIES));
 
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
        return result;
 }
 
-/* Query domain info */
+static NTSTATUS cmd_samr_query_dispinfo(struct rpc_pipe_client *cli, 
+                                       TALLOC_CTX *mem_ctx,
+                                       int argc, const char **argv)
+{
+       return cmd_samr_query_dispinfo_int(cli, mem_ctx, argc, argv, SAMR_QUERY_DISPINFO);
+}
 
-static NTSTATUS cmd_samr_query_dominfo(struct cli_state *cli, 
-                                       TALLOC_CTX *mem_ctx,
-                                       int argc, const char **argv) 
+static NTSTATUS cmd_samr_query_dispinfo2(struct rpc_pipe_client *cli, 
+                                        TALLOC_CTX *mem_ctx,
+                                        int argc, const char **argv) 
+{
+       return cmd_samr_query_dispinfo_int(cli, mem_ctx, argc, argv, SAMR_QUERY_DISPINFO2);
+}
+
+static NTSTATUS cmd_samr_query_dispinfo3(struct rpc_pipe_client *cli, 
+                                        TALLOC_CTX *mem_ctx,
+                                        int argc, const char **argv) 
+{
+       return cmd_samr_query_dispinfo_int(cli, mem_ctx, argc, argv, SAMR_QUERY_DISPINFO3);
+}
+
+/* Query display info index */
+
+static NTSTATUS cmd_samr_get_dispenum_index_int(struct rpc_pipe_client *cli, 
+                                               TALLOC_CTX *mem_ctx,
+                                               int argc, const char **argv,
+                                               int opcode)
 {
        POLICY_HND connect_pol, domain_pol;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uint32 switch_level = 2;
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
-       SAM_UNK_CTR ctr;
+       uint16 info_level = 1;
+       uint32 idx;
 
-       if (argc > 2) {
-               printf("Usage: %s [info level] [access mask]\n", argv[0]);
+       if (argc < 2 || argc > 3) {
+               printf("Usage: %s name [info level]\n", argv[0]);
                return NT_STATUS_OK;
        }
 
-       if (argc > 1)
-                sscanf(argv[1], "%i", &switch_level);
-       
-       if (argc > 2)
-                sscanf(argv[2], "%x", &access_mask);
+       if (argc >= 3) {
+               sscanf(argv[2], "%hd", &info_level);
+       }
 
        /* Get sam policy handle */
 
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
                                   &connect_pol);
 
-       if (!NT_STATUS_IS_OK(result))
+       if (!NT_STATUS_IS_OK(result)) {
                goto done;
+       }
 
        /* Get domain policy handle */
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
-                                     access_mask,
-                                     &domain_sid, &domain_pol);
-
-       if (!NT_STATUS_IS_OK(result))
-               goto done;
-
-       /* Query domain info */
-
-       result = cli_samr_query_dom_info(cli, mem_ctx, &domain_pol,
-                                        switch_level, &ctr);
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                        access_mask, 
+                                        &domain_sid, &domain_pol);
 
-       if (!NT_STATUS_IS_OK(result))
+       if (!NT_STATUS_IS_OK(result)) {
                goto done;
+       }
 
-       /* Display domain info */
+       /* Query display info index */
 
-       switch (switch_level) {
-       case 1:
-               display_sam_unk_info_1(&ctr.info.inf1);
+       switch (opcode) {
+       case SAMR_GET_DISPENUM_INDEX:
+               result = rpccli_samr_get_dispenum_index(cli, mem_ctx, &domain_pol,
+                                                       info_level, argv[1], &idx);
                break;
-       case 2:
-               display_sam_unk_info_2(&ctr.info.inf2);
+       case SAMR_GET_DISPENUM_INDEX2:
+               result = rpccli_samr_get_dispenum_index2(cli, mem_ctx, &domain_pol,
+                                                       info_level, argv[1], &idx);
                break;
        default:
-               printf("cannot display domain info for switch value %d\n",
-                      switch_level);
-               break;
+               printf("unknown opcode\n");
+               return NT_STATUS_INVALID_PARAMETER;
        }
+       
+       if (NT_STATUS_IS_ERR(result)) {
+               goto done;
+       };
+
+       printf("idx is: %d (0x%08x)\n", idx, idx);
 
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
-       cli_samr_close(cli, mem_ctx, &domain_pol);
-       cli_samr_close(cli, mem_ctx, &connect_pol);
        return result;
 }
 
-/* Create domain user */
+/* Query display info index */
 
-static NTSTATUS cmd_samr_create_dom_user(struct cli_state *cli, 
-                                         TALLOC_CTX *mem_ctx,
-                                         int argc, const char **argv) 
+static NTSTATUS cmd_samr_get_dispenum_index(struct rpc_pipe_client *cli, 
+                                           TALLOC_CTX *mem_ctx,
+                                           int argc, const char **argv)
 {
-       POLICY_HND connect_pol, domain_pol, user_pol;
-       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       return cmd_samr_get_dispenum_index_int(cli, mem_ctx, argc, argv, SAMR_GET_DISPENUM_INDEX);
+}
+
+/* Query display info index2 */
+
+static NTSTATUS cmd_samr_get_dispenum_index2(struct rpc_pipe_client *cli, 
+                                            TALLOC_CTX *mem_ctx,
+                                            int argc, const char **argv)
+{
+       return cmd_samr_get_dispenum_index_int(cli, mem_ctx, argc, argv, SAMR_GET_DISPENUM_INDEX2);
+}
+
+/* Query domain info */
+
+static NTSTATUS cmd_samr_query_dominfo(struct rpc_pipe_client *cli, 
+                                       TALLOC_CTX *mem_ctx,
+                                       int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       uint32 switch_level = 2;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+       SAM_UNK_CTR ctr;
+
+       if (argc > 3) {
+               printf("Usage: %s [info level] [access mask]\n", argv[0]);
+               return NT_STATUS_OK;
+       }
+
+       if (argc > 1)
+                sscanf(argv[1], "%i", &switch_level);
+       
+       if (argc > 2)
+                sscanf(argv[2], "%x", &access_mask);
+
+       /* Get sam policy handle */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Get domain policy handle */
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     access_mask,
+                                     &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Query domain info */
+
+       result = rpccli_samr_query_dom_info(cli, mem_ctx, &domain_pol,
+                                        switch_level, &ctr);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Display domain info */
+
+       switch (switch_level) {
+       case 1:
+               display_sam_unk_info_1(&ctr.info.inf1);
+               break;
+       case 2:
+               display_sam_unk_info_2(&ctr.info.inf2);
+               break;
+       case 3:
+               display_sam_unk_info_3(&ctr.info.inf3);
+               break;
+       case 4:
+               display_sam_unk_info_4(&ctr.info.inf4);
+               break;
+       case 5:
+               display_sam_unk_info_5(&ctr.info.inf5);
+               break;
+       case 6:
+               display_sam_unk_info_6(&ctr.info.inf6);
+               break;
+       case 7:
+               display_sam_unk_info_7(&ctr.info.inf7);
+               break;
+       case 8:
+               display_sam_unk_info_8(&ctr.info.inf8);
+               break;
+       case 9:
+               display_sam_unk_info_9(&ctr.info.inf9);
+               break;
+       case 12:
+               display_sam_unk_info_12(&ctr.info.inf12);
+               break;
+       case 13:
+               display_sam_unk_info_13(&ctr.info.inf13);
+               break;
+
+       default:
+               printf("cannot display domain info for switch value %d\n",
+                      switch_level);
+               break;
+       }
+
+ done:
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+       return result;
+}
+
+/* Create domain user */
+
+static NTSTATUS cmd_samr_create_dom_user(struct rpc_pipe_client *cli, 
+                                         TALLOC_CTX *mem_ctx,
+                                         int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol, user_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        const char *acct_name;
-       uint16 acb_info;
+       uint32 acb_info;
        uint32 unknown, user_rid;
        uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
 
@@ -1167,7 +1603,7 @@ static NTSTATUS cmd_samr_create_dom_user(struct cli_state *cli,
 
        /* Get domain policy handle */
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      access_mask,
                                      &domain_sid, &domain_pol);
 
@@ -1179,20 +1615,148 @@ static NTSTATUS cmd_samr_create_dom_user(struct cli_state *cli,
        acb_info = ACB_NORMAL;
        unknown = 0xe005000b; /* No idea what this is - a permission mask? */
 
-       result = cli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_create_dom_user(cli, mem_ctx, &domain_pol,
                                          acct_name, acb_info, unknown,
                                          &user_pol, &user_rid);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
+       result = rpccli_samr_close(cli, mem_ctx, &user_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+       return result;
+}
+
+/* Create domain group */
+
+static NTSTATUS cmd_samr_create_dom_group(struct rpc_pipe_client *cli, 
+                                          TALLOC_CTX *mem_ctx,
+                                          int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol, group_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       const char *grp_name;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+       if ((argc < 2) || (argc > 3)) {
+               printf("Usage: %s groupname [access mask]\n", argv[0]);
+               return NT_STATUS_OK;
+       }
+
+       grp_name = argv[1];
+       
+       if (argc > 2)
+                sscanf(argv[2], "%x", &access_mask);
+
+       /* Get sam policy handle */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Get domain policy handle */
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     access_mask,
+                                     &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Create domain user */
+
+       result = rpccli_samr_create_dom_group(cli, mem_ctx, &domain_pol,
+                                          grp_name, MAXIMUM_ALLOWED_ACCESS,
+                                          &group_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &group_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+       return result;
+}
+
+/* Create domain alias */
+
+static NTSTATUS cmd_samr_create_dom_alias(struct rpc_pipe_client *cli, 
+                                          TALLOC_CTX *mem_ctx,
+                                          int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol, alias_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       const char *alias_name;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+       if ((argc < 2) || (argc > 3)) {
+               printf("Usage: %s aliasname [access mask]\n", argv[0]);
+               return NT_STATUS_OK;
+       }
+
+       alias_name = argv[1];
+       
+       if (argc > 2)
+                sscanf(argv[2], "%x", &access_mask);
+
+       /* Get sam policy handle */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Get domain policy handle */
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                        access_mask,
+                                        &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Create domain user */
+
+       result = rpccli_samr_create_dom_alias(cli, mem_ctx, &domain_pol,
+                                             alias_name, &alias_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &alias_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
  done:
        return result;
 }
 
 /* Lookup sam names */
 
-static NTSTATUS cmd_samr_lookup_names(struct cli_state *cli, 
+static NTSTATUS cmd_samr_lookup_names(struct rpc_pipe_client *cli, 
                                       TALLOC_CTX *mem_ctx,
                                       int argc, const char **argv) 
 {
@@ -1202,9 +1766,6 @@ static NTSTATUS cmd_samr_lookup_names(struct cli_state *cli,
        uint32 num_rids, num_names, *name_types, *rids;
        const char **names;
        int i;
-       DOM_SID global_sid_Builtin;
-
-       string_to_sid(&global_sid_Builtin, "S-1-5-32");
 
        if (argc < 3) {
                printf("Usage: %s  domain|builtin name1 [name2 [name3] [...]]\n", argv[0]);
@@ -1222,11 +1783,11 @@ static NTSTATUS cmd_samr_lookup_names(struct cli_state *cli,
                goto done;
 
        if (StrCaseCmp(argv[1], "domain")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              MAXIMUM_ALLOWED_ACCESS,
                                              &domain_sid, &domain_pol);
        else if (StrCaseCmp(argv[1], "builtin")==0)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              MAXIMUM_ALLOWED_ACCESS,
                                              &global_sid_Builtin, &domain_pol);
        else
@@ -1238,12 +1799,21 @@ static NTSTATUS cmd_samr_lookup_names(struct cli_state *cli,
        /* Look up names */
 
        num_names = argc - 2;
-       names = (const char **)talloc(mem_ctx, sizeof(char *) * num_names);
+       if (num_names) {
+               if ((names = TALLOC_ARRAY(mem_ctx, const char *, num_names)) == NULL) {
+                       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+                       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+                       result = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+       } else {
+               names = NULL;
+       }
 
        for (i = 0; i < argc - 2; i++)
                names[i] = argv[i + 2];
 
-       result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+       result = rpccli_samr_lookup_names(cli, mem_ctx, &domain_pol,
                                       flags, num_names, names,
                                       &num_rids, &rids, &name_types);
 
@@ -1256,25 +1826,26 @@ static NTSTATUS cmd_samr_lookup_names(struct cli_state *cli,
                printf("name %s: 0x%x (%d)\n", names[i], rids[i], 
                       name_types[i]);
 
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
  done:
        return result;
 }
 
 /* Lookup sam rids */
 
-static NTSTATUS cmd_samr_lookup_rids(struct cli_state *cli, 
+static NTSTATUS cmd_samr_lookup_rids(struct rpc_pipe_client *cli, 
                                      TALLOC_CTX *mem_ctx,
                                      int argc, const char **argv) 
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
        POLICY_HND connect_pol, domain_pol;
-       uint32 flags = 0x000003e8; /* Unknown */
        uint32 num_rids, num_names, *rids, *name_types;
        char **names;
        int i;
 
-       if (argc < 2) {
-               printf("Usage: %s rid1 [rid2 [rid3] [...]]\n", argv[0]);
+       if (argc < 3) {
+               printf("Usage: %s domain|builtin rid1 [rid2 [rid3] [...]]\n", argv[0]);
                return NT_STATUS_OK;
        }
 
@@ -1286,26 +1857,42 @@ static NTSTATUS cmd_samr_lookup_rids(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
-                                     MAXIMUM_ALLOWED_ACCESS,
-                                     &domain_sid, &domain_pol);
+       if (StrCaseCmp(argv[1], "domain")==0)
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                             MAXIMUM_ALLOWED_ACCESS,
+                                             &domain_sid, &domain_pol);
+       else if (StrCaseCmp(argv[1], "builtin")==0)
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                             MAXIMUM_ALLOWED_ACCESS,
+                                             &global_sid_Builtin, &domain_pol);
+       else
+               return NT_STATUS_OK;
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
        /* Look up rids */
 
-       num_rids = argc - 1;
-       rids = (uint32 *)talloc(mem_ctx, sizeof(uint32) * num_rids);
+       num_rids = argc - 2;
+       if (num_rids) {
+               if ((rids = TALLOC_ARRAY(mem_ctx, uint32, num_rids)) == NULL) {
+                       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+                       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+                       result = NT_STATUS_NO_MEMORY;
+                       goto done;
+               }
+       } else {
+               rids = NULL;
+       }
 
-       for (i = 0; i < argc - 1; i++)
-                sscanf(argv[i + 1], "%i", &rids[i]);
+       for (i = 0; i < argc - 2; i++)
+                sscanf(argv[i + 2], "%i", &rids[i]);
 
-       result = cli_samr_lookup_rids(cli, mem_ctx, &domain_pol,
-                                     flags, num_rids, rids,
+       result = rpccli_samr_lookup_rids(cli, mem_ctx, &domain_pol, num_rids, rids,
                                      &num_names, &names, &name_types);
 
-       if (!NT_STATUS_IS_OK(result))
+       if (!NT_STATUS_IS_OK(result) &&
+           !NT_STATUS_EQUAL(result, STATUS_SOME_UNMAPPED))
                goto done;
 
        /* Display results */
@@ -1313,13 +1900,87 @@ static NTSTATUS cmd_samr_lookup_rids(struct cli_state *cli,
        for (i = 0; i < num_names; i++)
                printf("rid 0x%x: %s (%d)\n", rids[i], names[i], name_types[i]);
 
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+ done:
+       return result;
+}
+
+/* Delete domain group */
+
+static NTSTATUS cmd_samr_delete_dom_group(struct rpc_pipe_client *cli, 
+                                         TALLOC_CTX *mem_ctx,
+                                         int argc, const char **argv) 
+{
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       POLICY_HND connect_pol, domain_pol, group_pol;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+       if ((argc < 2) || (argc > 3)) {
+               printf("Usage: %s groupname\n", argv[0]);
+               return NT_STATUS_OK;
+       }
+       
+       if (argc > 2)
+                sscanf(argv[2], "%x", &access_mask);
+
+       /* Get sam policy and domain handles */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     MAXIMUM_ALLOWED_ACCESS,
+                                     &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Get handle on group */
+
+       {
+               uint32 *group_rids, num_rids, *name_types;
+               uint32 flags = 0x000003e8; /* Unknown */
+
+               result = rpccli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+                                              flags, 1, (const char **)&argv[1],
+                                              &num_rids, &group_rids,
+                                              &name_types);
+
+               if (!NT_STATUS_IS_OK(result))
+                       goto done;
+
+               result = rpccli_samr_open_group(cli, mem_ctx, &domain_pol,
+                                               access_mask,
+                                               group_rids[0], &group_pol);
+
+               if (!NT_STATUS_IS_OK(result))
+                       goto done;
+       }
+
+       /* Delete user */
+
+       result = rpccli_samr_delete_dom_group(cli, mem_ctx, &group_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Display results */
+
+       rpccli_samr_close(cli, mem_ctx, &group_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+
  done:
        return result;
 }
 
 /* Delete domain user */
 
-static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli, 
+static NTSTATUS cmd_samr_delete_dom_user(struct rpc_pipe_client *cli, 
                                          TALLOC_CTX *mem_ctx,
                                          int argc, const char **argv) 
 {
@@ -1343,7 +2004,7 @@ static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      MAXIMUM_ALLOWED_ACCESS,
                                      &domain_sid, &domain_pol);
 
@@ -1356,7 +2017,7 @@ static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli,
                uint32 *user_rids, num_rids, *name_types;
                uint32 flags = 0x000003e8; /* Unknown */
 
-               result = cli_samr_lookup_names(cli, mem_ctx, &domain_pol,
+               result = rpccli_samr_lookup_names(cli, mem_ctx, &domain_pol,
                                               flags, 1, (const char **)&argv[1],
                                               &num_rids, &user_rids,
                                               &name_types);
@@ -1364,7 +2025,7 @@ static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli,
                if (!NT_STATUS_IS_OK(result))
                        goto done;
 
-               result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+               result = rpccli_samr_open_user(cli, mem_ctx, &domain_pol,
                                            access_mask,
                                            user_rids[0], &user_pol);
 
@@ -1374,13 +2035,17 @@ static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli,
 
        /* Delete user */
 
-       result = cli_samr_delete_dom_user(cli, mem_ctx, &user_pol);
+       result = rpccli_samr_delete_dom_user(cli, mem_ctx, &user_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
        /* Display results */
 
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+
  done:
        return result;
 }
@@ -1388,13 +2053,13 @@ static NTSTATUS cmd_samr_delete_dom_user(struct cli_state *cli,
 /**********************************************************************
  * Query user security object 
  */
-static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli, 
+static NTSTATUS cmd_samr_query_sec_obj(struct rpc_pipe_client *cli, 
                                     TALLOC_CTX *mem_ctx,
                                     int argc, const char **argv) 
 {
        POLICY_HND connect_pol, domain_pol, user_pol, *pol;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uint32 info_level = 4;
+       uint32 sec_info = DACL_SECURITY_INFORMATION;
        fstring server;
        uint32 user_rid = 0;
        TALLOC_CTX *ctx = NULL;
@@ -1403,9 +2068,10 @@ static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli,
 
        ctx=talloc_init("cmd_samr_query_sec_obj");
        
-       if ((argc < 1) || (argc > 2)) {
-               printf("Usage: %s [rid|-d]\n", argv[0]);
+       if ((argc < 1) || (argc > 3)) {
+               printf("Usage: %s [rid|-d] [sec_info]\n", argv[0]);
                printf("\tSpecify rid for security on user, -d for security on domain\n");
+               talloc_destroy(ctx);
                return NT_STATUS_OK;
        }
        
@@ -1415,8 +2081,12 @@ static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli,
                else
                        sscanf(argv[1], "%i", &user_rid);
        }
+
+       if (argc == 3) {
+               sec_info = atoi(argv[2]);
+       }
        
-       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->desthost);
+       slprintf(server, sizeof(fstring)-1, "\\\\%s", cli->cli->desthost);
        strupper_m(server);
        result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS,
                                   &connect_pol);
@@ -1425,7 +2095,7 @@ static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli,
                goto done;
 
        if (domain || user_rid)
-               result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+               result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                              MAXIMUM_ALLOWED_ACCESS,
                                              &domain_sid, &domain_pol);
 
@@ -1433,7 +2103,7 @@ static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli,
                goto done;
 
        if (user_rid)
-               result = cli_samr_open_user(cli, mem_ctx, &domain_pol,
+               result = rpccli_samr_open_user(cli, mem_ctx, &domain_pol,
                                            MAXIMUM_ALLOWED_ACCESS,
                                            user_rid, &user_pol);
 
@@ -1452,37 +2122,97 @@ static NTSTATUS cmd_samr_query_sec_obj(struct cli_state *cli,
 
        /* Query SAM security object */
 
-       result = cli_samr_query_sec_obj(cli, mem_ctx, pol, info_level, ctx, 
+       result = rpccli_samr_query_sec_obj(cli, mem_ctx, pol, sec_info, ctx, 
                                        &sec_desc_buf);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       display_sec_desc(sec_desc_buf->sec);
-       
+       display_sec_desc(sec_desc_buf->sd);
+
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
 done:
        talloc_destroy(ctx);
        return result;
 }
 
-static NTSTATUS cmd_samr_get_dom_pwinfo(struct cli_state *cli, 
+static NTSTATUS cmd_samr_get_usrdom_pwinfo(struct rpc_pipe_client *cli, 
+                                          TALLOC_CTX *mem_ctx,
+                                          int argc, const char **argv) 
+{
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       POLICY_HND connect_pol, domain_pol, user_pol;
+       uint16 min_pwd_length;
+       uint32 password_properties, unknown1, rid;
+
+       if (argc != 2) {
+               printf("Usage: %s rid\n", argv[0]);
+               return NT_STATUS_OK;
+       }
+       
+       sscanf(argv[1], "%i", &rid);
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                        MAXIMUM_ALLOWED_ACCESS, &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       result = rpccli_samr_open_user(cli, mem_ctx, &domain_pol,
+                                      MAXIMUM_ALLOWED_ACCESS,
+                                      rid, &user_pol);
+
+       if (!NT_STATUS_IS_OK(result)) {
+               goto done;
+       }
+
+       result = rpccli_samr_get_usrdom_pwinfo(cli, mem_ctx, &user_pol,
+                                              &min_pwd_length, &password_properties, 
+                                              &unknown1) ;
+
+       if (NT_STATUS_IS_OK(result)) {
+               printf("min_pwd_length: %d\n", min_pwd_length);
+               printf("unknown1: %d\n", unknown1);
+               display_password_properties(password_properties);
+       }
+
+ done:
+       rpccli_samr_close(cli, mem_ctx, &user_pol);
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
+
+       return result;
+}
+
+
+static NTSTATUS cmd_samr_get_dom_pwinfo(struct rpc_pipe_client *cli, 
                                        TALLOC_CTX *mem_ctx,
                                        int argc, const char **argv) 
 {
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
-       uint16 unk_0, unk_1, unk_2;
+       uint16 min_pwd_length;
+       uint32 password_properties;
 
        if (argc != 1) {
                printf("Usage: %s\n", argv[0]);
                return NT_STATUS_OK;
        }
 
-       result = cli_samr_get_dom_pwinfo(cli, mem_ctx, &unk_0, &unk_1, &unk_2);
+       result = rpccli_samr_get_dom_pwinfo(cli, mem_ctx, &min_pwd_length, &password_properties) ;
        
        if (NT_STATUS_IS_OK(result)) {
-               printf("unk_0 = 0x%08x\n", unk_0);
-               printf("unk_1 = 0x%08x\n", unk_1);
-               printf("unk_2 = 0x%08x\n", unk_2);
+               printf("min_pwd_length: %d\n", min_pwd_length);
+               display_password_properties(password_properties);
        }
 
        return result;
@@ -1490,7 +2220,7 @@ static NTSTATUS cmd_samr_get_dom_pwinfo(struct cli_state *cli,
 
 /* Look up domain name */
 
-static NTSTATUS cmd_samr_lookup_domain(struct cli_state *cli, 
+static NTSTATUS cmd_samr_lookup_domain(struct rpc_pipe_client *cli, 
                                       TALLOC_CTX *mem_ctx,
                                       int argc, const char **argv) 
 {
@@ -1512,13 +2242,13 @@ static NTSTATUS cmd_samr_lookup_domain(struct cli_state *cli,
        if (!NT_STATUS_IS_OK(result))
                goto done;
 
-       result = cli_samr_open_domain(cli, mem_ctx, &connect_pol,
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
                                      access_mask, &domain_sid, &domain_pol);
 
        if (!NT_STATUS_IS_OK(result))
                goto done;
        
-       result = cli_samr_lookup_domain(
+       result = rpccli_samr_lookup_domain(
                cli, mem_ctx, &connect_pol, domain_name, &sid);
 
        sid_to_string(sid_string,&sid);
@@ -1527,10 +2257,143 @@ static NTSTATUS cmd_samr_lookup_domain(struct cli_state *cli,
                printf("SAMR_LOOKUP_DOMAIN: Domain Name: %s Domain SID: %s\n",
                       domain_name,sid_string);
 
+       rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       rpccli_samr_close(cli, mem_ctx, &connect_pol);
 done:
        return result;
 }
 
+/* Change user password */
+
+static NTSTATUS cmd_samr_chgpasswd2(struct rpc_pipe_client *cli, 
+                                   TALLOC_CTX *mem_ctx,
+                                   int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       const char *user, *oldpass, *newpass;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+
+       if (argc < 3) {
+               printf("Usage: %s username oldpass newpass\n", argv[0]);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       user = argv[1];
+       oldpass = argv[2];
+       newpass = argv[3];
+       
+       /* Get sam policy handle */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Get domain policy handle */
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     access_mask,
+                                     &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Change user password */
+       result = rpccli_samr_chgpasswd_user(cli, mem_ctx, user, newpass, oldpass);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+       return result;
+}
+
+
+/* Change user password */
+
+static NTSTATUS cmd_samr_chgpasswd3(struct rpc_pipe_client *cli, 
+                                   TALLOC_CTX *mem_ctx,
+                                   int argc, const char **argv) 
+{
+       POLICY_HND connect_pol, domain_pol;
+       NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
+       const char *user, *oldpass, *newpass;
+       uint32 access_mask = MAXIMUM_ALLOWED_ACCESS;
+       SAM_UNK_INFO_1 info;
+       SAMR_CHANGE_REJECT reject;
+
+       if (argc < 3) {
+               printf("Usage: %s username oldpass newpass\n", argv[0]);
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       user = argv[1];
+       oldpass = argv[2];
+       newpass = argv[3];
+       
+       /* Get sam policy handle */
+
+       result = try_samr_connects(cli, mem_ctx, MAXIMUM_ALLOWED_ACCESS, 
+                                  &connect_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Get domain policy handle */
+
+       result = rpccli_samr_open_domain(cli, mem_ctx, &connect_pol,
+                                     access_mask,
+                                     &domain_sid, &domain_pol);
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       /* Change user password */
+       result = rpccli_samr_chgpasswd3(cli, mem_ctx, user, newpass, oldpass, &info, &reject);
+
+       if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION)) {
+       
+               display_sam_unk_info_1(&info);
+
+               switch (reject.reject_reason) {
+                       case REJECT_REASON_TOO_SHORT:
+                               d_printf("REJECT_REASON_TOO_SHORT\n");
+                               break;
+                       case REJECT_REASON_IN_HISTORY:
+                               d_printf("REJECT_REASON_IN_HISTORY\n");
+                               break;
+                       case REJECT_REASON_NOT_COMPLEX:
+                               d_printf("REJECT_REASON_NOT_COMPLEX\n");
+                               break;
+                       case REJECT_REASON_OTHER:
+                               d_printf("REJECT_REASON_OTHER\n");
+                               break;
+                       default:
+                               d_printf("unknown reject reason: %d\n", reject.reject_reason);
+                               break;
+               }
+       }
+
+       if (!NT_STATUS_IS_OK(result))
+               goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &domain_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+       result = rpccli_samr_close(cli, mem_ctx, &connect_pol);
+       if (!NT_STATUS_IS_OK(result)) goto done;
+
+ done:
+       return result;
+}
 
 /* List of commands exported by this module */
 
@@ -1538,25 +2401,36 @@ struct cmd_set samr_commands[] = {
 
        { "SAMR" },
 
-       { "queryuser",  RPC_RTYPE_NTSTATUS, cmd_samr_query_user,                NULL, PI_SAMR,  "Query user info",         "" },
-       { "querygroup",         RPC_RTYPE_NTSTATUS, cmd_samr_query_group,               NULL, PI_SAMR,  "Query group info",        "" },
-       { "queryusergroups",    RPC_RTYPE_NTSTATUS, cmd_samr_query_usergroups,  NULL, PI_SAMR,  "Query user groups",       "" },
-       { "queryuseraliases",   RPC_RTYPE_NTSTATUS, cmd_samr_query_useraliases,         NULL, PI_SAMR,  "Query user aliases",      "" },
-       { "querygroupmem",      RPC_RTYPE_NTSTATUS, cmd_samr_query_groupmem,    NULL, PI_SAMR,  "Query group membership",  "" },
-       { "queryaliasmem",      RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasmem,    NULL, PI_SAMR,  "Query alias membership",  "" },
-       { "querydispinfo",      RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo,    NULL, PI_SAMR,  "Query display info",      "" },
-       { "querydominfo",       RPC_RTYPE_NTSTATUS, cmd_samr_query_dominfo,     NULL, PI_SAMR,  "Query domain info",       "" },
-       { "enumdomusers",      RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_users,       NULL, PI_SAMR,        "Enumerate domain users", "" },
-       { "enumdomgroups",      RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_groups,       NULL, PI_SAMR,      "Enumerate domain groups", "" },
-       { "enumalsgroups",      RPC_RTYPE_NTSTATUS, cmd_samr_enum_als_groups,       NULL, PI_SAMR,      "Enumerate alias groups",  "" },
-
-       { "createdomuser",      RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_user,       NULL, PI_SAMR,      "Create domain user",      "" },
-       { "samlookupnames",     RPC_RTYPE_NTSTATUS, cmd_samr_lookup_names,          NULL, PI_SAMR,      "Look up names",           "" },
-       { "samlookuprids",      RPC_RTYPE_NTSTATUS, cmd_samr_lookup_rids,           NULL, PI_SAMR,      "Look up names",           "" },
-       { "deletedomuser",      RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_user,       NULL, PI_SAMR,      "Delete domain user",      "" },
-       { "samquerysecobj",     RPC_RTYPE_NTSTATUS, cmd_samr_query_sec_obj,         NULL, PI_SAMR, "Query SAMR security object",   "" },
-       { "getdompwinfo",       RPC_RTYPE_NTSTATUS, cmd_samr_get_dom_pwinfo,        NULL, PI_SAMR, "Retrieve domain password info", "" },
-
-       { "lookupdomain",       RPC_RTYPE_NTSTATUS, cmd_samr_lookup_domain,         NULL, PI_SAMR, "Lookup Domain Name", "" },
+       { "queryuser",  RPC_RTYPE_NTSTATUS, cmd_samr_query_user,                NULL, PI_SAMR, NULL,    "Query user info",         "" },
+       { "querygroup",         RPC_RTYPE_NTSTATUS, cmd_samr_query_group,               NULL, PI_SAMR, NULL,    "Query group info",        "" },
+       { "queryusergroups",    RPC_RTYPE_NTSTATUS, cmd_samr_query_usergroups,  NULL, PI_SAMR, NULL,    "Query user groups",       "" },
+       { "queryuseraliases",   RPC_RTYPE_NTSTATUS, cmd_samr_query_useraliases,         NULL, PI_SAMR, NULL,    "Query user aliases",      "" },
+       { "querygroupmem",      RPC_RTYPE_NTSTATUS, cmd_samr_query_groupmem,    NULL, PI_SAMR, NULL,    "Query group membership",  "" },
+       { "queryaliasmem",      RPC_RTYPE_NTSTATUS, cmd_samr_query_aliasmem,    NULL, PI_SAMR, NULL,    "Query alias membership",  "" },
+       { "deletealias",        RPC_RTYPE_NTSTATUS, cmd_samr_delete_alias,      NULL, PI_SAMR, NULL,    "Delete an alias",  "" },
+       { "querydispinfo",      RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo,    NULL, PI_SAMR, NULL,    "Query display info",      "" },
+       { "querydispinfo2",     RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo2,   NULL, PI_SAMR, NULL,    "Query display info 2",      "" },
+       { "querydispinfo3",     RPC_RTYPE_NTSTATUS, cmd_samr_query_dispinfo3,   NULL, PI_SAMR, NULL,    "Query display info 3",      "" },
+       { "getdispenumindex",   RPC_RTYPE_NTSTATUS, cmd_samr_get_dispenum_index,        NULL, PI_SAMR, NULL,    "Query display info index",      "" },
+       { "getdispenumindex2",  RPC_RTYPE_NTSTATUS, cmd_samr_get_dispenum_index2,       NULL, PI_SAMR, NULL,    "Query display info index",      "" },
+       { "querydominfo",       RPC_RTYPE_NTSTATUS, cmd_samr_query_dominfo,     NULL, PI_SAMR, NULL,    "Query domain info",       "" },
+       { "enumdomusers",      RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_users,       NULL, PI_SAMR, NULL,  "Enumerate domain users", "" },
+       { "enumdomgroups",      RPC_RTYPE_NTSTATUS, cmd_samr_enum_dom_groups,       NULL, PI_SAMR, NULL,        "Enumerate domain groups", "" },
+       { "enumalsgroups",      RPC_RTYPE_NTSTATUS, cmd_samr_enum_als_groups,       NULL, PI_SAMR, NULL,        "Enumerate alias groups",  "" },
+
+       { "createdomuser",      RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_user,       NULL, PI_SAMR, NULL,        "Create domain user",      "" },
+       { "createdomgroup",     RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_group,      NULL, PI_SAMR, NULL,        "Create domain group",     "" },
+       { "createdomalias",     RPC_RTYPE_NTSTATUS, cmd_samr_create_dom_alias,      NULL, PI_SAMR, NULL,        "Create domain alias",     "" },
+       { "samlookupnames",     RPC_RTYPE_NTSTATUS, cmd_samr_lookup_names,          NULL, PI_SAMR, NULL,        "Look up names",           "" },
+       { "samlookuprids",      RPC_RTYPE_NTSTATUS, cmd_samr_lookup_rids,           NULL, PI_SAMR, NULL,        "Look up names",           "" },
+       { "deletedomgroup",     RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_group,      NULL, PI_SAMR, NULL,        "Delete domain group",     "" },
+       { "deletedomuser",      RPC_RTYPE_NTSTATUS, cmd_samr_delete_dom_user,       NULL, PI_SAMR, NULL,        "Delete domain user",      "" },
+       { "samquerysecobj",     RPC_RTYPE_NTSTATUS, cmd_samr_query_sec_obj,         NULL, PI_SAMR, NULL, "Query SAMR security object",   "" },
+       { "getdompwinfo",       RPC_RTYPE_NTSTATUS, cmd_samr_get_dom_pwinfo,        NULL, PI_SAMR, NULL, "Retrieve domain password info", "" },
+       { "getusrdompwinfo",    RPC_RTYPE_NTSTATUS, cmd_samr_get_usrdom_pwinfo,     NULL, PI_SAMR, NULL, "Retrieve user domain password info", "" },
+
+       { "lookupdomain",       RPC_RTYPE_NTSTATUS, cmd_samr_lookup_domain,         NULL, PI_SAMR, NULL, "Lookup Domain Name", "" },
+       { "chgpasswd2",         RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd2,            NULL, PI_SAMR, NULL, "Change user password", "" },
+       { "chgpasswd3",         RPC_RTYPE_NTSTATUS, cmd_samr_chgpasswd3,            NULL, PI_SAMR, NULL, "Change user password", "" },
        { NULL }
 };