netapi: implement NetUserSetInfo_r() for at least level 1007.
[ira/wip.git] / source3 / lib / netapi / user.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *  NetApi User Support
4  *  Copyright (C) Guenther Deschner 2008
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21
22 #include "librpc/gen_ndr/libnetapi.h"
23 #include "lib/netapi/netapi.h"
24 #include "lib/netapi/netapi_private.h"
25 #include "lib/netapi/libnetapi.h"
26
27 /****************************************************************
28 ****************************************************************/
29
30 static void convert_USER_INFO_X_to_samr_user_info21(struct USER_INFO_X *infoX,
31                                                     struct samr_UserInfo21 *info21)
32 {
33         uint32_t fields_present = SAMR_FIELD_ACCT_FLAGS;
34         struct samr_LogonHours zero_logon_hours;
35         struct lsa_BinaryString zero_parameters;
36         uint32_t acct_flags = 0;
37         NTTIME password_age;
38
39         ZERO_STRUCTP(info21);
40         ZERO_STRUCT(zero_logon_hours);
41         ZERO_STRUCT(zero_parameters);
42
43         if (infoX->usriX_name) {
44                 fields_present |= SAMR_FIELD_FULL_NAME;
45         }
46         if (infoX->usriX_password) {
47                 fields_present |= SAMR_FIELD_PASSWORD;
48         }
49         if (infoX->usriX_flags) {
50                 fields_present |= SAMR_FIELD_ACCT_FLAGS;
51         }
52         if (infoX->usriX_name) {
53                 fields_present |= SAMR_FIELD_FULL_NAME;
54         }
55         if (infoX->usriX_home_dir) {
56                 fields_present |= SAMR_FIELD_HOME_DIRECTORY;
57         }
58         if (infoX->usriX_script_path) {
59                 fields_present |= SAMR_FIELD_LOGON_SCRIPT;
60         }
61         if (infoX->usriX_comment) {
62                 fields_present |= SAMR_FIELD_DESCRIPTION;
63         }
64         if (infoX->usriX_password_age) {
65                 fields_present |= SAMR_FIELD_FORCE_PWD_CHANGE;
66         }
67
68         acct_flags |= infoX->usriX_flags | ACB_NORMAL;
69
70         unix_to_nt_time_abs(&password_age, infoX->usriX_password_age);
71
72         /* TODO: infoX->usriX_priv */
73         init_samr_user_info21(info21,
74                               0,
75                               0,
76                               0,
77                               0,
78                               0,
79                               password_age,
80                               NULL,
81                               infoX->usriX_name,
82                               infoX->usriX_home_dir,
83                               NULL,
84                               infoX->usriX_script_path,
85                               NULL,
86                               infoX->usriX_comment,
87                               NULL,
88                               NULL,
89                               &zero_parameters,
90                               0,
91                               0,
92                               acct_flags,
93                               fields_present,
94                               zero_logon_hours,
95                               0,
96                               0,
97                               0,
98                               0,
99                               0,
100                               0,
101                               0);
102 }
103
104 /****************************************************************
105 ****************************************************************/
106
107 static NTSTATUS construct_USER_INFO_X(uint32_t level,
108                                       uint8_t *buffer,
109                                       struct USER_INFO_X *uX)
110 {
111         struct USER_INFO_0 *u0 = NULL;
112         struct USER_INFO_1 *u1 = NULL;
113         struct USER_INFO_2 *u2 = NULL;
114         struct USER_INFO_1007 *u1007 = NULL;
115
116         if (!buffer || !uX) {
117                 return NT_STATUS_INVALID_PARAMETER;
118         }
119
120         ZERO_STRUCTP(uX);
121
122         switch (level) {
123                 case 0:
124                         u0 = (struct USER_INFO_0 *)buffer;
125                         uX->usriX_name          = u0->usri0_name;
126                         break;
127                 case 1:
128                         u1 = (struct USER_INFO_1 *)buffer;
129                         uX->usriX_name          = u1->usri1_name;
130                         uX->usriX_password      = u1->usri1_password;
131                         uX->usriX_password_age  = u1->usri1_password_age;
132                         uX->usriX_priv          = u1->usri1_priv;
133                         uX->usriX_home_dir      = u1->usri1_home_dir;
134                         uX->usriX_comment       = u1->usri1_comment;
135                         uX->usriX_flags         = u1->usri1_flags;
136                         uX->usriX_script_path   = u1->usri1_script_path;
137                         break;
138                 case 2:
139                         u2 = (struct USER_INFO_2 *)buffer;
140                         uX->usriX_name          = u2->usri2_name;
141                         uX->usriX_password      = u2->usri2_password;
142                         uX->usriX_password_age  = u2->usri2_password_age;
143                         uX->usriX_priv          = u2->usri2_priv;
144                         uX->usriX_home_dir      = u2->usri2_home_dir;
145                         uX->usriX_comment       = u2->usri2_comment;
146                         uX->usriX_flags         = u2->usri2_flags;
147                         uX->usriX_script_path   = u2->usri2_script_path;
148                         uX->usriX_auth_flags    = u2->usri2_auth_flags;
149                         uX->usriX_full_name     = u2->usri2_full_name;
150                         uX->usriX_usr_comment   = u2->usri2_usr_comment;
151                         uX->usriX_parms         = u2->usri2_parms;
152                         uX->usriX_workstations  = u2->usri2_workstations;
153                         uX->usriX_last_logon    = u2->usri2_last_logon;
154                         uX->usriX_last_logoff   = u2->usri2_last_logoff;
155                         uX->usriX_acct_expires  = u2->usri2_acct_expires;
156                         uX->usriX_max_storage   = u2->usri2_max_storage;
157                         uX->usriX_units_per_week= u2->usri2_units_per_week;
158                         uX->usriX_logon_hours   = u2->usri2_logon_hours;
159                         uX->usriX_bad_pw_count  = u2->usri2_bad_pw_count;
160                         uX->usriX_num_logons    = u2->usri2_num_logons;
161                         uX->usriX_logon_server  = u2->usri2_logon_server;
162                         uX->usriX_country_code  = u2->usri2_country_code;
163                         uX->usriX_code_page     = u2->usri2_code_page;
164                         break;
165                 case 1007:
166                         u1007 = (struct USER_INFO_1007 *)buffer;
167                         uX->usriX_comment       = u1007->usri1007_comment;
168                         break;
169                 case 3:
170                 case 4:
171                 default:
172                         return NT_STATUS_INVALID_INFO_CLASS;
173         }
174
175         return NT_STATUS_OK;
176 }
177
178 /****************************************************************
179 ****************************************************************/
180
181 WERROR NetUserAdd_r(struct libnetapi_ctx *ctx,
182                     struct NetUserAdd *r)
183 {
184         struct cli_state *cli = NULL;
185         struct rpc_pipe_client *pipe_cli = NULL;
186         NTSTATUS status;
187         WERROR werr;
188         POLICY_HND connect_handle, domain_handle, user_handle;
189         struct lsa_String lsa_account_name;
190         struct dom_sid2 *domain_sid = NULL;
191         struct samr_UserInfo21 info21;
192         union samr_UserInfo *user_info = NULL;
193         struct samr_PwInfo pw_info;
194         uint32_t access_granted = 0;
195         uint32_t rid = 0;
196         struct USER_INFO_X uX;
197
198         ZERO_STRUCT(connect_handle);
199         ZERO_STRUCT(domain_handle);
200         ZERO_STRUCT(user_handle);
201
202         if (!r->in.buffer) {
203                 return WERR_INVALID_PARAM;
204         }
205
206         switch (r->in.level) {
207                 case 1:
208                         break;
209                 case 2:
210                 case 3:
211                 case 4:
212                 default:
213                         werr = WERR_NOT_SUPPORTED;
214                         goto done;
215         }
216
217         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
218         if (!W_ERROR_IS_OK(werr)) {
219                 goto done;
220         }
221
222         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
223                                    &pipe_cli);
224         if (!W_ERROR_IS_OK(werr)) {
225                 goto done;
226         }
227
228         status = construct_USER_INFO_X(r->in.level, r->in.buffer, &uX);
229         if (!NT_STATUS_IS_OK(status)) {
230                 werr = ntstatus_to_werror(status);
231                 goto done;
232         }
233
234         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
235                                           SAMR_ACCESS_ENUM_DOMAINS |
236                                           SAMR_ACCESS_OPEN_DOMAIN,
237                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
238                                           SAMR_DOMAIN_ACCESS_CREATE_USER |
239                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
240                                           &connect_handle,
241                                           &domain_handle,
242                                           &domain_sid);
243         if (!W_ERROR_IS_OK(werr)) {
244                 goto done;
245         }
246
247         init_lsa_String(&lsa_account_name, uX.usriX_name);
248
249         status = rpccli_samr_CreateUser2(pipe_cli, ctx,
250                                          &domain_handle,
251                                          &lsa_account_name,
252                                          ACB_NORMAL,
253                                          SEC_STD_WRITE_DAC |
254                                          SEC_STD_DELETE |
255                                          SAMR_USER_ACCESS_SET_PASSWORD |
256                                          SAMR_USER_ACCESS_SET_ATTRIBUTES |
257                                          SAMR_USER_ACCESS_GET_ATTRIBUTES,
258                                          &user_handle,
259                                          &access_granted,
260                                          &rid);
261         if (!NT_STATUS_IS_OK(status)) {
262                 werr = ntstatus_to_werror(status);
263                 goto done;
264         }
265
266         status = rpccli_samr_QueryUserInfo(pipe_cli, ctx,
267                                            &user_handle,
268                                            16,
269                                            &user_info);
270         if (!NT_STATUS_IS_OK(status)) {
271                 werr = ntstatus_to_werror(status);
272                 goto done;
273         }
274
275         if (!(user_info->info16.acct_flags & ACB_NORMAL)) {
276                 werr = WERR_INVALID_PARAM;
277                 goto done;
278         }
279
280         status = rpccli_samr_GetUserPwInfo(pipe_cli, ctx,
281                                            &user_handle,
282                                            &pw_info);
283         if (!NT_STATUS_IS_OK(status)) {
284                 werr = ntstatus_to_werror(status);
285                 goto done;
286         }
287
288         convert_USER_INFO_X_to_samr_user_info21(&uX,
289                                                 &info21);
290
291         ZERO_STRUCTP(user_info);
292
293         if (uX.usriX_password) {
294
295                 uchar pwbuf[532];
296                 struct MD5Context md5_ctx;
297                 uint8_t confounder[16];
298                 DATA_BLOB confounded_session_key = data_blob(NULL, 16);
299
300                 encode_pw_buffer(pwbuf, uX.usriX_password, STR_UNICODE);
301
302                 generate_random_buffer((uint8_t *)confounder, 16);
303
304                 MD5Init(&md5_ctx);
305                 MD5Update(&md5_ctx, confounder, 16);
306                 MD5Update(&md5_ctx, cli->user_session_key.data,
307                                 cli->user_session_key.length);
308                 MD5Final(confounded_session_key.data, &md5_ctx);
309
310                 SamOEMhashBlob(pwbuf, 516, &confounded_session_key);
311                 memcpy(&pwbuf[516], confounder, 16);
312
313                 memcpy(user_info->info25.password.data, pwbuf, sizeof(pwbuf));
314                 data_blob_free(&confounded_session_key);
315
316                 user_info->info25.info = info21;
317
318                 status = rpccli_samr_SetUserInfo2(pipe_cli, ctx,
319                                                   &user_handle,
320                                                   25,
321                                                   user_info);
322
323                 if (NT_STATUS_EQUAL(status, NT_STATUS(DCERPC_FAULT_INVALID_TAG))) {
324
325                         user_info->info23.info = info21;
326
327                         encode_pw_buffer(user_info->info23.password.data,
328                                          uX.usriX_password, STR_UNICODE);
329                         SamOEMhashBlob(user_info->info23.password.data, 516,
330                                        &cli->user_session_key);
331
332                         status = rpccli_samr_SetUserInfo2(pipe_cli, ctx,
333                                                           &user_handle,
334                                                           23,
335                                                           user_info);
336                 }
337         } else {
338                 user_info->info21 = info21;
339                 status = rpccli_samr_SetUserInfo(pipe_cli, ctx,
340                                                  &user_handle,
341                                                  21,
342                                                  user_info);
343
344         }
345         if (!NT_STATUS_IS_OK(status)) {
346                 werr = ntstatus_to_werror(status);
347                 goto failed;
348         }
349
350         werr = WERR_OK;
351         goto done;
352
353  failed:
354         rpccli_samr_DeleteUser(pipe_cli, ctx,
355                                &user_handle);
356
357  done:
358         if (!cli) {
359                 return werr;
360         }
361
362         if (is_valid_policy_hnd(&user_handle)) {
363                 rpccli_samr_Close(pipe_cli, ctx, &user_handle);
364         }
365
366         if (ctx->disable_policy_handle_cache) {
367                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
368                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
369         }
370
371         return werr;
372 }
373
374 /****************************************************************
375 ****************************************************************/
376
377 WERROR NetUserAdd_l(struct libnetapi_ctx *ctx,
378                     struct NetUserAdd *r)
379 {
380         /* for now just talk to local RPC server */
381         if (!r->in.server_name) {
382                 r->in.server_name = "localhost";
383         }
384
385         return NetUserAdd_r(ctx, r);
386 }
387
388 /****************************************************************
389 ****************************************************************/
390
391 WERROR NetUserDel_r(struct libnetapi_ctx *ctx,
392                     struct NetUserDel *r)
393 {
394         struct cli_state *cli = NULL;
395         struct rpc_pipe_client *pipe_cli = NULL;
396         NTSTATUS status;
397         WERROR werr;
398         POLICY_HND connect_handle, builtin_handle, domain_handle, user_handle;
399         struct lsa_String lsa_account_name;
400         struct samr_Ids user_rids, name_types;
401         struct dom_sid2 *domain_sid = NULL;
402         struct dom_sid2 user_sid;
403
404         ZERO_STRUCT(connect_handle);
405         ZERO_STRUCT(builtin_handle);
406         ZERO_STRUCT(domain_handle);
407         ZERO_STRUCT(user_handle);
408
409         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
410         if (!W_ERROR_IS_OK(werr)) {
411                 goto done;
412         }
413
414         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
415                                    &pipe_cli);
416         if (!W_ERROR_IS_OK(werr)) {
417                 goto done;
418         }
419
420         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
421                                           SAMR_ACCESS_ENUM_DOMAINS |
422                                           SAMR_ACCESS_OPEN_DOMAIN,
423                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
424                                           &connect_handle,
425                                           &domain_handle,
426                                           &domain_sid);
427         if (!W_ERROR_IS_OK(werr)) {
428                 goto done;
429         }
430
431         status = rpccli_samr_OpenDomain(pipe_cli, ctx,
432                                         &connect_handle,
433                                         SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
434                                         CONST_DISCARD(DOM_SID *, &global_sid_Builtin),
435                                         &builtin_handle);
436         if (!NT_STATUS_IS_OK(status)) {
437                 werr = ntstatus_to_werror(status);
438                 goto done;
439         }
440
441         init_lsa_String(&lsa_account_name, r->in.user_name);
442
443         status = rpccli_samr_LookupNames(pipe_cli, ctx,
444                                          &domain_handle,
445                                          1,
446                                          &lsa_account_name,
447                                          &user_rids,
448                                          &name_types);
449         if (!NT_STATUS_IS_OK(status)) {
450                 werr = ntstatus_to_werror(status);
451                 goto done;
452         }
453
454         status = rpccli_samr_OpenUser(pipe_cli, ctx,
455                                       &domain_handle,
456                                       STD_RIGHT_DELETE_ACCESS,
457                                       user_rids.ids[0],
458                                       &user_handle);
459         if (!NT_STATUS_IS_OK(status)) {
460                 werr = ntstatus_to_werror(status);
461                 goto done;
462         }
463
464         sid_compose(&user_sid, domain_sid, user_rids.ids[0]);
465
466         status = rpccli_samr_RemoveMemberFromForeignDomain(pipe_cli, ctx,
467                                                            &builtin_handle,
468                                                            &user_sid);
469         if (!NT_STATUS_IS_OK(status)) {
470                 werr = ntstatus_to_werror(status);
471                 goto done;
472         }
473
474         status = rpccli_samr_DeleteUser(pipe_cli, ctx,
475                                         &user_handle);
476         if (!NT_STATUS_IS_OK(status)) {
477                 werr = ntstatus_to_werror(status);
478                 goto done;
479         }
480
481         werr = WERR_OK;
482
483  done:
484         if (!cli) {
485                 return werr;
486         }
487
488         if (is_valid_policy_hnd(&user_handle)) {
489                 rpccli_samr_Close(pipe_cli, ctx, &user_handle);
490         }
491
492         if (ctx->disable_policy_handle_cache) {
493                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
494                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
495                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
496         }
497
498         return werr;
499 }
500
501 /****************************************************************
502 ****************************************************************/
503
504 WERROR NetUserDel_l(struct libnetapi_ctx *ctx,
505                     struct NetUserDel *r)
506 {
507         /* for now just talk to local RPC server */
508         if (!r->in.server_name) {
509                 r->in.server_name = "localhost";
510         }
511
512         return NetUserDel_r(ctx, r);
513 }
514
515 /****************************************************************
516 ****************************************************************/
517
518 static NTSTATUS libnetapi_samr_lookup_user(TALLOC_CTX *mem_ctx,
519                                            struct rpc_pipe_client *pipe_cli,
520                                            struct policy_handle *domain_handle,
521                                            struct policy_handle *builtin_handle,
522                                            const char *user_name,
523                                            uint32_t rid,
524                                            uint32_t level,
525                                            struct samr_UserInfo21 **info21,
526                                            struct sec_desc_buf **sec_desc)
527 {
528         NTSTATUS status;
529
530         struct policy_handle user_handle;
531         union samr_UserInfo *user_info = NULL;
532         struct samr_RidWithAttributeArray *rid_array = NULL;
533         uint32_t access_mask = SEC_STD_READ_CONTROL |
534                                SAMR_USER_ACCESS_GET_ATTRIBUTES |
535                                SAMR_USER_ACCESS_GET_NAME_ETC;
536
537         ZERO_STRUCT(user_handle);
538
539         switch (level) {
540                 case 0:
541                 case 1:
542                 case 2:
543                 case 3:
544                 case 10:
545                 case 11:
546                 case 20:
547                 case 23:
548                         break;
549                 default:
550                         return NT_STATUS_INVALID_LEVEL;
551         }
552
553         if (level == 0) {
554                 return NT_STATUS_OK;
555         }
556
557         status = rpccli_samr_OpenUser(pipe_cli, mem_ctx,
558                                       domain_handle,
559                                       access_mask,
560                                       rid,
561                                       &user_handle);
562         if (!NT_STATUS_IS_OK(status)) {
563                 goto done;
564         }
565
566         status = rpccli_samr_QueryUserInfo(pipe_cli, mem_ctx,
567                                            &user_handle,
568                                            21,
569                                            &user_info);
570         if (!NT_STATUS_IS_OK(status)) {
571                 goto done;
572         }
573
574         status = rpccli_samr_QuerySecurity(pipe_cli, mem_ctx,
575                                            &user_handle,
576                                            SECINFO_DACL,
577                                            sec_desc);
578         if (!NT_STATUS_IS_OK(status)) {
579                 goto done;
580         }
581
582         if (level == 1) {
583                 status = rpccli_samr_GetGroupsForUser(pipe_cli, mem_ctx,
584                                                       &user_handle,
585                                                       &rid_array);
586                 if (!NT_STATUS_IS_OK(status)) {
587                         goto done;
588                 }
589
590 #if 0
591                 status = rpccli_samr_GetAliasMembership(pipe_cli, ctx,
592                                                         &builtin_handle,
593                                                         &sids,
594                                                         &rids);
595                 if (!NT_STATUS_IS_OK(status)) {
596                         goto done;
597                 }
598 #endif
599         }
600
601         *info21 = &user_info->info21;
602
603  done:
604         if (is_valid_policy_hnd(&user_handle)) {
605                 rpccli_samr_Close(pipe_cli, mem_ctx, &user_handle);
606         }
607
608         return status;
609 }
610
611 /****************************************************************
612 ****************************************************************/
613
614 static NTSTATUS libnetapi_samr_lookup_user_map_USER_INFO(TALLOC_CTX *mem_ctx,
615                                                          struct rpc_pipe_client *pipe_cli,
616                                                          struct dom_sid *domain_sid,
617                                                          struct policy_handle *domain_handle,
618                                                          struct policy_handle *builtin_handle,
619                                                          const char *user_name,
620                                                          uint32_t rid,
621                                                          uint32_t level,
622                                                          uint8_t **buffer,
623                                                          uint32_t *num_entries)
624 {
625         NTSTATUS status;
626
627         struct samr_UserInfo21 *info21 = NULL;
628         struct sec_desc_buf *sec_desc = NULL;
629         struct dom_sid sid;
630
631         struct USER_INFO_0 *info0 = NULL;
632         struct USER_INFO_10 *info10 = NULL;
633         struct USER_INFO_20 *info20 = NULL;
634         struct USER_INFO_23 *info23 = NULL;
635
636         switch (level) {
637                 case 0:
638                 case 1:
639                 case 2:
640                 case 3:
641                 case 10:
642                 case 11:
643                 case 20:
644                 case 23:
645                         break;
646                 default:
647                         return NT_STATUS_INVALID_LEVEL;
648         }
649
650         if (level == 0) {
651                 info0 = TALLOC_P(mem_ctx, struct USER_INFO_0);
652                 NT_STATUS_HAVE_NO_MEMORY(info0);
653
654                 info0->usri0_name = talloc_strdup(mem_ctx, user_name);
655                 NT_STATUS_HAVE_NO_MEMORY(info0->usri0_name);
656
657                 ADD_TO_ARRAY(mem_ctx, struct USER_INFO_0, *info0,
658                              (struct USER_INFO_0 **)buffer, num_entries);
659
660                 return NT_STATUS_OK;
661         }
662
663         status = libnetapi_samr_lookup_user(mem_ctx, pipe_cli,
664                                             domain_handle,
665                                             builtin_handle,
666                                             user_name,
667                                             rid,
668                                             level,
669                                             &info21,
670                                             &sec_desc);
671
672         if (!NT_STATUS_IS_OK(status)) {
673                 goto done;
674         }
675
676         switch (level) {
677                 case 10:
678                         info10 = TALLOC_P(mem_ctx, struct USER_INFO_10);
679                         NT_STATUS_HAVE_NO_MEMORY(info10);
680
681                         info10->usri10_name = talloc_strdup(mem_ctx, user_name);
682                         NT_STATUS_HAVE_NO_MEMORY(info10->usri10_name);
683
684                         info10->usri10_comment = talloc_strdup(mem_ctx,
685                                 info21->description.string);
686
687                         info10->usri10_full_name = talloc_strdup(mem_ctx,
688                                 info21->full_name.string);
689
690                         info10->usri10_usr_comment = talloc_strdup(mem_ctx,
691                                 info21->comment.string);
692
693                         ADD_TO_ARRAY(mem_ctx, struct USER_INFO_10, *info10,
694                                      (struct USER_INFO_10 **)buffer, num_entries);
695
696                         break;
697
698                 case 20:
699                         info20 = TALLOC_P(mem_ctx, struct USER_INFO_20);
700                         NT_STATUS_HAVE_NO_MEMORY(info20);
701
702                         info20->usri20_name = talloc_strdup(mem_ctx, user_name);
703                         NT_STATUS_HAVE_NO_MEMORY(info20->usri20_name);
704
705                         info20->usri20_comment = talloc_strdup(mem_ctx,
706                                 info21->description.string);
707
708                         info20->usri20_flags = info21->acct_flags;
709                         info20->usri20_user_id = rid;
710
711                         ADD_TO_ARRAY(mem_ctx, struct USER_INFO_20, *info20,
712                                      (struct USER_INFO_20 **)buffer, num_entries);
713
714                         break;
715                 case 23:
716                         info23 = TALLOC_P(mem_ctx, struct USER_INFO_23);
717                         NT_STATUS_HAVE_NO_MEMORY(info23);
718
719                         info23->usri23_name = talloc_strdup(mem_ctx, user_name);
720                         NT_STATUS_HAVE_NO_MEMORY(info23->usri23_name);
721
722                         info23->usri23_comment = talloc_strdup(mem_ctx,
723                                 info21->description.string);
724
725                         info23->usri23_flags = info21->acct_flags;
726
727                         if (!sid_compose(&sid, domain_sid, rid)) {
728                                 return NT_STATUS_NO_MEMORY;
729                         }
730
731                         info23->usri23_user_sid =
732                                 (struct domsid *)sid_dup_talloc(mem_ctx, &sid);
733
734                         ADD_TO_ARRAY(mem_ctx, struct USER_INFO_23, *info23,
735                                      (struct USER_INFO_23 **)buffer, num_entries);
736                         break;
737         }
738
739  done:
740         return status;
741 }
742
743 /****************************************************************
744 ****************************************************************/
745
746 WERROR NetUserEnum_r(struct libnetapi_ctx *ctx,
747                      struct NetUserEnum *r)
748 {
749         struct cli_state *cli = NULL;
750         struct rpc_pipe_client *pipe_cli = NULL;
751         struct policy_handle connect_handle;
752         struct dom_sid2 *domain_sid = NULL;
753         struct policy_handle domain_handle;
754         struct samr_SamArray *sam = NULL;
755         uint32_t filter = ACB_NORMAL;
756         int i;
757         uint32_t entries_read = 0;
758
759         NTSTATUS status = NT_STATUS_OK;
760         WERROR werr;
761
762         ZERO_STRUCT(connect_handle);
763         ZERO_STRUCT(domain_handle);
764
765         if (!r->out.buffer) {
766                 return WERR_INVALID_PARAM;
767         }
768
769         *r->out.buffer = NULL;
770         *r->out.entries_read = 0;
771
772         switch (r->in.level) {
773                 case 0:
774                 case 10:
775                 case 20:
776                 case 23:
777                         break;
778                 case 1:
779                 case 2:
780                 case 3:
781                 case 11:
782                 default:
783                         return WERR_NOT_SUPPORTED;
784         }
785
786         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
787         if (!W_ERROR_IS_OK(werr)) {
788                 goto done;
789         }
790
791         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
792                                    &pipe_cli);
793         if (!W_ERROR_IS_OK(werr)) {
794                 goto done;
795         }
796
797         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
798                                           SAMR_ACCESS_ENUM_DOMAINS |
799                                           SAMR_ACCESS_OPEN_DOMAIN,
800                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
801                                           SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
802                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
803                                           &connect_handle,
804                                           &domain_handle,
805                                           &domain_sid);
806         if (!W_ERROR_IS_OK(werr)) {
807                 goto done;
808         }
809
810         switch (r->in.filter) {
811                 case FILTER_NORMAL_ACCOUNT:
812                         filter = ACB_NORMAL;
813                         break;
814                 case FILTER_TEMP_DUPLICATE_ACCOUNT:
815                         filter = ACB_TEMPDUP;
816                         break;
817                 case FILTER_INTERDOMAIN_TRUST_ACCOUNT:
818                         filter = ACB_DOMTRUST;
819                         break;
820                 case FILTER_WORKSTATION_TRUST_ACCOUNT:
821                         filter = ACB_WSTRUST;
822                         break;
823                 case FILTER_SERVER_TRUST_ACCOUNT:
824                         filter = ACB_SVRTRUST;
825                         break;
826                 default:
827                         break;
828         }
829
830         status = rpccli_samr_EnumDomainUsers(pipe_cli,
831                                              ctx,
832                                              &domain_handle,
833                                              r->in.resume_handle,
834                                              filter,
835                                              &sam,
836                                              r->in.prefmaxlen,
837                                              &entries_read);
838         werr = ntstatus_to_werror(status);
839         if (NT_STATUS_IS_ERR(status)) {
840                 goto done;
841         }
842
843         for (i=0; i < sam->count; i++) {
844
845                 status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli,
846                                                                   domain_sid,
847                                                                   &domain_handle,
848                                                                   NULL, /*&builtin_handle, */
849                                                                   sam->entries[i].name.string,
850                                                                   sam->entries[i].idx,
851                                                                   r->in.level,
852                                                                   r->out.buffer,
853                                                                   r->out.entries_read);
854                 if (!NT_STATUS_IS_OK(status)) {
855                         werr = ntstatus_to_werror(status);
856                         goto done;
857                 }
858         }
859
860  done:
861         if (!cli) {
862                 return werr;
863         }
864
865         /* if last query */
866         if (NT_STATUS_IS_OK(status) ||
867             NT_STATUS_IS_ERR(status)) {
868
869                 if (ctx->disable_policy_handle_cache) {
870                         libnetapi_samr_close_domain_handle(ctx, &domain_handle);
871                         libnetapi_samr_close_connect_handle(ctx, &connect_handle);
872                 }
873         }
874
875         return werr;
876 }
877
878 /****************************************************************
879 ****************************************************************/
880
881 WERROR NetUserEnum_l(struct libnetapi_ctx *ctx,
882                      struct NetUserEnum *r)
883 {
884         return WERR_NOT_SUPPORTED;
885 }
886
887 /****************************************************************
888 ****************************************************************/
889
890 static WERROR convert_samr_dispinfo_to_NET_DISPLAY_USER(TALLOC_CTX *mem_ctx,
891                                                         struct samr_DispInfoGeneral *info,
892                                                         uint32_t *entries_read,
893                                                         void **buffer)
894 {
895         struct NET_DISPLAY_USER *user = NULL;
896         int i;
897
898         user = TALLOC_ZERO_ARRAY(mem_ctx,
899                                  struct NET_DISPLAY_USER,
900                                  info->count);
901         W_ERROR_HAVE_NO_MEMORY(user);
902
903         for (i = 0; i < info->count; i++) {
904                 user[i].usri1_name = talloc_strdup(mem_ctx,
905                         info->entries[i].account_name.string);
906                 user[i].usri1_comment = talloc_strdup(mem_ctx,
907                         info->entries[i].description.string);
908                 user[i].usri1_flags =
909                         info->entries[i].acct_flags;
910                 user[i].usri1_full_name = talloc_strdup(mem_ctx,
911                         info->entries[i].full_name.string);
912                 user[i].usri1_user_id =
913                         info->entries[i].rid;
914                 user[i].usri1_next_index =
915                         info->entries[i].idx;
916
917                 if (!user[i].usri1_name) {
918                         return WERR_NOMEM;
919                 }
920         }
921
922         *buffer = talloc_memdup(mem_ctx, user,
923                 sizeof(struct NET_DISPLAY_USER) * info->count);
924         W_ERROR_HAVE_NO_MEMORY(*buffer);
925
926         *entries_read = info->count;
927
928         return WERR_OK;
929 }
930
931 /****************************************************************
932 ****************************************************************/
933
934 static WERROR convert_samr_dispinfo_to_NET_DISPLAY_MACHINE(TALLOC_CTX *mem_ctx,
935                                                            struct samr_DispInfoFull *info,
936                                                            uint32_t *entries_read,
937                                                            void **buffer)
938 {
939         struct NET_DISPLAY_MACHINE *machine = NULL;
940         int i;
941
942         machine = TALLOC_ZERO_ARRAY(mem_ctx,
943                                     struct NET_DISPLAY_MACHINE,
944                                     info->count);
945         W_ERROR_HAVE_NO_MEMORY(machine);
946
947         for (i = 0; i < info->count; i++) {
948                 machine[i].usri2_name = talloc_strdup(mem_ctx,
949                         info->entries[i].account_name.string);
950                 machine[i].usri2_comment = talloc_strdup(mem_ctx,
951                         info->entries[i].description.string);
952                 machine[i].usri2_flags =
953                         info->entries[i].acct_flags;
954                 machine[i].usri2_user_id =
955                         info->entries[i].rid;
956                 machine[i].usri2_next_index =
957                         info->entries[i].idx;
958
959                 if (!machine[i].usri2_name) {
960                         return WERR_NOMEM;
961                 }
962         }
963
964         *buffer = talloc_memdup(mem_ctx, machine,
965                 sizeof(struct NET_DISPLAY_MACHINE) * info->count);
966         W_ERROR_HAVE_NO_MEMORY(*buffer);
967
968         *entries_read = info->count;
969
970         return WERR_OK;
971 }
972
973 /****************************************************************
974 ****************************************************************/
975
976 static WERROR convert_samr_dispinfo_to_NET_DISPLAY_GROUP(TALLOC_CTX *mem_ctx,
977                                                          struct samr_DispInfoFullGroups *info,
978                                                          uint32_t *entries_read,
979                                                          void **buffer)
980 {
981         struct NET_DISPLAY_GROUP *group = NULL;
982         int i;
983
984         group = TALLOC_ZERO_ARRAY(mem_ctx,
985                                   struct NET_DISPLAY_GROUP,
986                                   info->count);
987         W_ERROR_HAVE_NO_MEMORY(group);
988
989         for (i = 0; i < info->count; i++) {
990                 group[i].grpi3_name = talloc_strdup(mem_ctx,
991                         info->entries[i].account_name.string);
992                 group[i].grpi3_comment = talloc_strdup(mem_ctx,
993                         info->entries[i].description.string);
994                 group[i].grpi3_group_id =
995                         info->entries[i].rid;
996                 group[i].grpi3_attributes =
997                         info->entries[i].acct_flags;
998                 group[i].grpi3_next_index =
999                         info->entries[i].idx;
1000
1001                 if (!group[i].grpi3_name) {
1002                         return WERR_NOMEM;
1003                 }
1004         }
1005
1006         *buffer = talloc_memdup(mem_ctx, group,
1007                 sizeof(struct NET_DISPLAY_GROUP) * info->count);
1008         W_ERROR_HAVE_NO_MEMORY(*buffer);
1009
1010         *entries_read = info->count;
1011
1012         return WERR_OK;
1013
1014 }
1015
1016 /****************************************************************
1017 ****************************************************************/
1018
1019 static WERROR convert_samr_dispinfo_to_NET_DISPLAY(TALLOC_CTX *mem_ctx,
1020                                                    union samr_DispInfo *info,
1021                                                    uint32_t level,
1022                                                    uint32_t *entries_read,
1023                                                    void **buffer)
1024 {
1025         switch (level) {
1026                 case 1:
1027                         return convert_samr_dispinfo_to_NET_DISPLAY_USER(mem_ctx,
1028                                                                          &info->info1,
1029                                                                          entries_read,
1030                                                                          buffer);
1031                 case 2:
1032                         return convert_samr_dispinfo_to_NET_DISPLAY_MACHINE(mem_ctx,
1033                                                                             &info->info2,
1034                                                                             entries_read,
1035                                                                             buffer);
1036                 case 3:
1037                         return convert_samr_dispinfo_to_NET_DISPLAY_GROUP(mem_ctx,
1038                                                                           &info->info3,
1039                                                                           entries_read,
1040                                                                           buffer);
1041                 default:
1042                         return WERR_UNKNOWN_LEVEL;
1043         }
1044
1045         return WERR_OK;
1046 }
1047
1048 /****************************************************************
1049 ****************************************************************/
1050
1051 WERROR NetQueryDisplayInformation_r(struct libnetapi_ctx *ctx,
1052                                     struct NetQueryDisplayInformation *r)
1053 {
1054         struct cli_state *cli = NULL;
1055         struct rpc_pipe_client *pipe_cli = NULL;
1056         struct policy_handle connect_handle;
1057         struct dom_sid2 *domain_sid = NULL;
1058         struct policy_handle domain_handle;
1059         union samr_DispInfo info;
1060
1061         uint32_t total_size = 0;
1062         uint32_t returned_size = 0;
1063
1064         NTSTATUS status = NT_STATUS_OK;
1065         WERROR werr;
1066
1067         ZERO_STRUCT(connect_handle);
1068         ZERO_STRUCT(domain_handle);
1069
1070         switch (r->in.level) {
1071                 case 1:
1072                 case 2:
1073                 case 3:
1074                         break;
1075                 default:
1076                         return WERR_UNKNOWN_LEVEL;
1077         }
1078
1079         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
1080         if (!W_ERROR_IS_OK(werr)) {
1081                 goto done;
1082         }
1083
1084         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
1085                                    &pipe_cli);
1086         if (!W_ERROR_IS_OK(werr)) {
1087                 goto done;
1088         }
1089
1090         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1091                                           SAMR_ACCESS_ENUM_DOMAINS |
1092                                           SAMR_ACCESS_OPEN_DOMAIN,
1093                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_2 |
1094                                           SAMR_DOMAIN_ACCESS_ENUM_ACCOUNTS |
1095                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1096                                           &connect_handle,
1097                                           &domain_handle,
1098                                           &domain_sid);
1099         if (!W_ERROR_IS_OK(werr)) {
1100                 goto done;
1101         }
1102
1103         status = rpccli_samr_QueryDisplayInfo2(pipe_cli,
1104                                                ctx,
1105                                                &domain_handle,
1106                                                r->in.level,
1107                                                r->in.idx,
1108                                                r->in.entries_requested,
1109                                                r->in.prefmaxlen,
1110                                                &total_size,
1111                                                &returned_size,
1112                                                &info);
1113         if (!NT_STATUS_IS_OK(status)) {
1114                 werr = ntstatus_to_werror(status);
1115                 goto done;
1116         }
1117
1118         werr = convert_samr_dispinfo_to_NET_DISPLAY(ctx, &info,
1119                                                     r->in.level,
1120                                                     r->out.entries_read,
1121                                                     r->out.buffer);
1122  done:
1123         if (!cli) {
1124                 return werr;
1125         }
1126
1127         /* if last query */
1128         if (NT_STATUS_IS_OK(status) ||
1129             NT_STATUS_IS_ERR(status)) {
1130
1131                 if (ctx->disable_policy_handle_cache) {
1132                         libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1133                         libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1134                 }
1135         }
1136
1137         return werr;
1138
1139 }
1140
1141 /****************************************************************
1142 ****************************************************************/
1143
1144
1145 WERROR NetQueryDisplayInformation_l(struct libnetapi_ctx *ctx,
1146                                     struct NetQueryDisplayInformation *r)
1147 {
1148         return WERR_NOT_SUPPORTED;
1149 }
1150
1151 /****************************************************************
1152 ****************************************************************/
1153
1154 WERROR NetUserChangePassword_r(struct libnetapi_ctx *ctx,
1155                                struct NetUserChangePassword *r)
1156 {
1157         return WERR_NOT_SUPPORTED;
1158 }
1159
1160 /****************************************************************
1161 ****************************************************************/
1162
1163 WERROR NetUserChangePassword_l(struct libnetapi_ctx *ctx,
1164                                struct NetUserChangePassword *r)
1165 {
1166         return WERR_NOT_SUPPORTED;
1167 }
1168
1169 /****************************************************************
1170 ****************************************************************/
1171
1172 WERROR NetUserGetInfo_r(struct libnetapi_ctx *ctx,
1173                         struct NetUserGetInfo *r)
1174 {
1175         struct cli_state *cli = NULL;
1176         struct rpc_pipe_client *pipe_cli = NULL;
1177         NTSTATUS status;
1178         WERROR werr;
1179
1180         struct policy_handle connect_handle, domain_handle, builtin_handle, user_handle;
1181         struct lsa_String lsa_account_name;
1182         struct dom_sid2 *domain_sid = NULL;
1183         struct samr_Ids user_rids, name_types;
1184         uint32_t num_entries = 0;
1185
1186         ZERO_STRUCT(connect_handle);
1187         ZERO_STRUCT(domain_handle);
1188         ZERO_STRUCT(builtin_handle);
1189         ZERO_STRUCT(user_handle);
1190
1191         if (!r->out.buffer) {
1192                 return WERR_INVALID_PARAM;
1193         }
1194
1195         switch (r->in.level) {
1196                 case 0:
1197                 /* case 1: */
1198                 case 10:
1199                 case 20:
1200                 case 23:
1201                         break;
1202                 default:
1203                         werr = WERR_NOT_SUPPORTED;
1204                         goto done;
1205         }
1206
1207         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
1208         if (!W_ERROR_IS_OK(werr)) {
1209                 goto done;
1210         }
1211
1212         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
1213                                    &pipe_cli);
1214         if (!W_ERROR_IS_OK(werr)) {
1215                 goto done;
1216         }
1217
1218         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1219                                           SAMR_ACCESS_ENUM_DOMAINS |
1220                                           SAMR_ACCESS_OPEN_DOMAIN,
1221                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1222                                           &connect_handle,
1223                                           &domain_handle,
1224                                           &domain_sid);
1225         if (!W_ERROR_IS_OK(werr)) {
1226                 goto done;
1227         }
1228
1229         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
1230                                                   SAMR_ACCESS_ENUM_DOMAINS |
1231                                                   SAMR_ACCESS_OPEN_DOMAIN,
1232                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
1233                                                   SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
1234                                                   &connect_handle,
1235                                                   &builtin_handle);
1236         if (!W_ERROR_IS_OK(werr)) {
1237                 goto done;
1238         }
1239
1240         init_lsa_String(&lsa_account_name, r->in.user_name);
1241
1242         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1243                                          &domain_handle,
1244                                          1,
1245                                          &lsa_account_name,
1246                                          &user_rids,
1247                                          &name_types);
1248         if (!NT_STATUS_IS_OK(status)) {
1249                 werr = ntstatus_to_werror(status);
1250                 goto done;
1251         }
1252
1253         status = libnetapi_samr_lookup_user_map_USER_INFO(ctx, pipe_cli,
1254                                                           domain_sid,
1255                                                           &domain_handle,
1256                                                           &builtin_handle,
1257                                                           r->in.user_name,
1258                                                           user_rids.ids[0],
1259                                                           r->in.level,
1260                                                           r->out.buffer,
1261                                                           &num_entries);
1262         if (!NT_STATUS_IS_OK(status)) {
1263                 werr = ntstatus_to_werror(status);
1264                 goto done;
1265         }
1266
1267  done:
1268         if (!cli) {
1269                 return werr;
1270         }
1271
1272         if (is_valid_policy_hnd(&user_handle)) {
1273                 rpccli_samr_Close(pipe_cli, ctx, &user_handle);
1274         }
1275
1276         if (ctx->disable_policy_handle_cache) {
1277                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1278                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1279         }
1280
1281         return werr;
1282 }
1283
1284 /****************************************************************
1285 ****************************************************************/
1286
1287 WERROR NetUserGetInfo_l(struct libnetapi_ctx *ctx,
1288                         struct NetUserGetInfo *r)
1289 {
1290         return WERR_NOT_SUPPORTED;
1291 }
1292
1293 /****************************************************************
1294 ****************************************************************/
1295
1296 WERROR NetUserSetInfo_r(struct libnetapi_ctx *ctx,
1297                         struct NetUserSetInfo *r)
1298 {
1299         struct cli_state *cli = NULL;
1300         struct rpc_pipe_client *pipe_cli = NULL;
1301         NTSTATUS status;
1302         WERROR werr;
1303
1304         struct policy_handle connect_handle, domain_handle, builtin_handle, user_handle;
1305         struct lsa_String lsa_account_name;
1306         struct dom_sid2 *domain_sid = NULL;
1307         struct samr_Ids user_rids, name_types;
1308         union samr_UserInfo user_info;
1309
1310         struct USER_INFO_X uX;
1311
1312         ZERO_STRUCT(connect_handle);
1313         ZERO_STRUCT(domain_handle);
1314         ZERO_STRUCT(builtin_handle);
1315         ZERO_STRUCT(user_handle);
1316
1317         if (!r->in.buffer) {
1318                 return WERR_INVALID_PARAM;
1319         }
1320
1321         switch (r->in.level) {
1322                 case 0:
1323                 case 1007:
1324                         break;
1325                 default:
1326                         werr = WERR_NOT_SUPPORTED;
1327                         goto done;
1328         }
1329
1330         werr = libnetapi_open_ipc_connection(ctx, r->in.server_name, &cli);
1331         if (!W_ERROR_IS_OK(werr)) {
1332                 goto done;
1333         }
1334
1335         werr = libnetapi_open_pipe(ctx, cli, &ndr_table_samr.syntax_id,
1336                                    &pipe_cli);
1337         if (!W_ERROR_IS_OK(werr)) {
1338                 goto done;
1339         }
1340
1341         werr = libnetapi_samr_open_domain(ctx, pipe_cli,
1342                                           SAMR_ACCESS_ENUM_DOMAINS |
1343                                           SAMR_ACCESS_OPEN_DOMAIN,
1344                                           SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 |
1345                                           SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT,
1346                                           &connect_handle,
1347                                           &domain_handle,
1348                                           &domain_sid);
1349         if (!W_ERROR_IS_OK(werr)) {
1350                 goto done;
1351         }
1352
1353         werr = libnetapi_samr_open_builtin_domain(ctx, pipe_cli,
1354                                                   SAMR_ACCESS_ENUM_DOMAINS |
1355                                                   SAMR_ACCESS_OPEN_DOMAIN,
1356                                                   SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT |
1357                                                   SAMR_DOMAIN_ACCESS_LOOKUP_ALIAS,
1358                                                   &connect_handle,
1359                                                   &builtin_handle);
1360         if (!W_ERROR_IS_OK(werr)) {
1361                 goto done;
1362         }
1363
1364         init_lsa_String(&lsa_account_name, r->in.user_name);
1365
1366         status = rpccli_samr_LookupNames(pipe_cli, ctx,
1367                                          &domain_handle,
1368                                          1,
1369                                          &lsa_account_name,
1370                                          &user_rids,
1371                                          &name_types);
1372         if (!NT_STATUS_IS_OK(status)) {
1373                 werr = ntstatus_to_werror(status);
1374                 goto done;
1375         }
1376
1377         status = rpccli_samr_OpenUser(pipe_cli, ctx,
1378                                       &domain_handle,
1379                                       SAMR_USER_ACCESS_SET_ATTRIBUTES,
1380                                       user_rids.ids[0],
1381                                       &user_handle);
1382         if (!NT_STATUS_IS_OK(status)) {
1383                 werr = ntstatus_to_werror(status);
1384                 goto done;
1385         }
1386
1387         status = construct_USER_INFO_X(r->in.level, r->in.buffer, &uX);
1388         if (!NT_STATUS_IS_OK(status)) {
1389                 werr = ntstatus_to_werror(status);
1390                 goto done;
1391         }
1392
1393         convert_USER_INFO_X_to_samr_user_info21(&uX, &user_info.info21);
1394
1395         status = rpccli_samr_SetUserInfo(pipe_cli, ctx,
1396                                          &user_handle,
1397                                          21,
1398                                          &user_info);
1399         if (!NT_STATUS_IS_OK(status)) {
1400                 werr = ntstatus_to_werror(status);
1401                 goto done;
1402         }
1403
1404         werr = WERR_OK;
1405
1406  done:
1407         if (!cli) {
1408                 return werr;
1409         }
1410
1411         if (is_valid_policy_hnd(&user_handle)) {
1412                 rpccli_samr_Close(pipe_cli, ctx, &user_handle);
1413         }
1414
1415         if (ctx->disable_policy_handle_cache) {
1416                 libnetapi_samr_close_domain_handle(ctx, &domain_handle);
1417                 libnetapi_samr_close_builtin_handle(ctx, &builtin_handle);
1418                 libnetapi_samr_close_connect_handle(ctx, &connect_handle);
1419         }
1420
1421         return werr;
1422 }
1423
1424 /****************************************************************
1425 ****************************************************************/
1426
1427 WERROR NetUserSetInfo_l(struct libnetapi_ctx *ctx,
1428                         struct NetUserSetInfo *r)
1429 {
1430         return WERR_NOT_SUPPORTED;
1431 }
1432