Fix a segv in winbindd caused by trying to free an fstring. Make a copy of the machin...
[tprouty/samba.git] / source / libmsrpc / cac_samr.c
1
2 /* 
3  *  Unix SMB/CIFS implementation.
4  *  MS-RPC client library implementation (SAMR pipe)
5  *  Copyright (C) Chris Nicholls              2005.
6  *  
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *  
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  */
21
22 #include "libmsrpc.h"
23 #include "libmsrpc_internal.h"
24
25 /*used by cac_SamGetNamesFromRids*/
26 #define SAMR_RID_UNKNOWN 8
27
28 #define SAMR_ENUM_MAX_SIZE 0xffff
29
30 /*not sure what this is.. taken from rpcclient/cmd_samr.c*/
31 #define SAMR_LOOKUP_FLAGS 0x000003e8
32
33 DOM_SID *cac_get_domain_sid( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
34                              uint32 des_access );
35
36 int cac_SamConnect( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
37                     struct SamConnect *op )
38 {
39         SMBCSRV *srv = NULL;
40         struct rpc_pipe_client *pipe_hnd = NULL;
41         POLICY_HND *sam_out = NULL;
42
43         if ( !hnd )
44                 return CAC_FAILURE;
45
46         if ( !hnd->_internal.ctx ) {
47                 hnd->status = NT_STATUS_INVALID_HANDLE;
48                 return CAC_FAILURE;
49         }
50
51         if ( !op || op->in.access == 0 || !mem_ctx ) {
52                 hnd->status = NT_STATUS_INVALID_PARAMETER;
53                 return CAC_FAILURE;
54         }
55
56         srv = cac_GetServer( hnd );
57         if ( !srv ) {
58                 hnd->status = NT_STATUS_INVALID_CONNECTION;
59                 return CAC_FAILURE;
60         }
61
62         /*initialize for samr pipe if we have to */
63         if ( !hnd->_internal.pipes[PI_SAMR] ) {
64                 if ( !
65                      ( pipe_hnd =
66                        cli_rpc_pipe_open_noauth( srv->cli, PI_SAMR,
67                                                  &hnd->status ) ) ) {
68                         return CAC_FAILURE;
69                 }
70
71                 hnd->_internal.pipes[PI_SAMR] = True;
72         }
73
74         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
75         if ( !pipe_hnd ) {
76                 hnd->status = NT_STATUS_INVALID_HANDLE;
77                 return CAC_FAILURE;
78         }
79
80         sam_out = talloc( mem_ctx, POLICY_HND );
81         if ( !sam_out ) {
82                 hnd->status = NT_STATUS_NO_MEMORY;
83                 return CAC_FAILURE;
84         }
85
86         if ( hnd->_internal.srv_level >= SRV_WIN_2K_SP3 ) {
87                 hnd->status =
88                         rpccli_samr_connect4( pipe_hnd, mem_ctx,
89                                               op->in.access, sam_out );
90         }
91
92         if ( hnd->_internal.srv_level < SRV_WIN_2K_SP3
93              || !NT_STATUS_IS_OK( hnd->status ) ) {
94                 /*if sam_connect4 failed, the use sam_connect and lower srv_level */
95
96                 hnd->status =
97                         rpccli_samr_connect( pipe_hnd, mem_ctx, op->in.access,
98                                              sam_out );
99
100                 if ( NT_STATUS_IS_OK( hnd->status )
101                      && hnd->_internal.srv_level > SRV_WIN_2K ) {
102                         hnd->_internal.srv_level = SRV_WIN_2K;
103                 }
104         }
105
106         if ( !NT_STATUS_IS_OK( hnd->status ) )
107                 return CAC_FAILURE;
108
109         op->out.sam = sam_out;
110
111         return CAC_SUCCESS;
112 }
113
114 int cac_SamClose( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
115                   POLICY_HND * sam )
116 {
117         struct rpc_pipe_client *pipe_hnd = NULL;
118
119         if ( !hnd )
120                 return CAC_FAILURE;
121
122         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
123                 hnd->status = NT_STATUS_INVALID_HANDLE;
124                 return CAC_FAILURE;
125         }
126
127         if ( !sam || !mem_ctx ) {
128                 hnd->status = NT_STATUS_INVALID_PARAMETER;
129                 return CAC_FAILURE;
130         }
131
132         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
133         if ( !pipe_hnd ) {
134                 hnd->status = NT_STATUS_INVALID_HANDLE;
135                 return CAC_FAILURE;
136         }
137
138         hnd->status = rpccli_samr_close( pipe_hnd, mem_ctx, sam );
139
140         if ( !NT_STATUS_IS_OK( hnd->status ) )
141                 return CAC_FAILURE;
142
143         return CAC_SUCCESS;
144 }
145
146 /*this is an internal function. Due to a circular dependency, it must be prototyped in libmsrpc.h (which I don't want to do)
147  * cac_SamOpenDomain() is the only function that calls it, so I just put the definition here
148  */
149
150 /*attempts to find the sid of the domain we are connected to*/
151 DOM_SID *cac_get_domain_sid( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
152                              uint32 des_access )
153 {
154         struct LsaOpenPolicy lop;
155         struct LsaFetchSid fs;
156
157         DOM_SID *sid;
158
159         ZERO_STRUCT( lop );
160         ZERO_STRUCT( fs );
161
162         lop.in.access = des_access;
163         lop.in.security_qos = True;
164
165         if ( !cac_LsaOpenPolicy( hnd, mem_ctx, &lop ) )
166                 return NULL;
167
168         fs.in.pol = lop.out.pol;
169         fs.in.info_class = CAC_DOMAIN_INFO;
170
171         if ( !cac_LsaFetchSid( hnd, mem_ctx, &fs ) )
172                 return NULL;
173
174         cac_LsaClosePolicy( hnd, mem_ctx, lop.out.pol );
175
176         if ( !fs.out.domain_sid )
177                 return NULL;
178
179         sid = ( DOM_SID * ) TALLOC_MEMDUP( mem_ctx,
180                                            &( fs.out.domain_sid->sid ),
181                                            sizeof( DOM_SID ) );
182
183         if ( !sid ) {
184                 hnd->status = NT_STATUS_NO_MEMORY;
185         }
186
187         return sid;
188
189 }
190
191 int cac_SamOpenDomain( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
192                        struct SamOpenDomain *op )
193 {
194         struct rpc_pipe_client *pipe_hnd = NULL;
195
196         DOM_SID *sid_buf;
197         POLICY_HND *sam_out;
198         POLICY_HND *pol_out;
199
200         struct SamLookupDomain sld;
201
202         if ( !hnd )
203                 return CAC_FAILURE;
204
205         if ( !hnd->_internal.ctx ) {
206                 hnd->status = NT_STATUS_INVALID_HANDLE;
207                 return CAC_FAILURE;
208         }
209
210         if ( !op || op->in.access == 0 || !mem_ctx ) {
211                 hnd->status = NT_STATUS_INVALID_PARAMETER;
212                 return CAC_FAILURE;
213         }
214
215         if ( !op->in.sam ) {
216                 /*use cac_SamConnect() since it does the session setup */
217                 struct SamConnect sc;
218
219                 ZERO_STRUCT( sc );
220
221                 sc.in.access = op->in.access;
222
223                 if ( !cac_SamConnect( hnd, mem_ctx, &sc ) ) {
224                         return CAC_FAILURE;
225                 }
226
227                 sam_out = sc.out.sam;
228         } else {
229                 sam_out = op->in.sam;
230         }
231
232         if ( !op->in.sid ) {
233                 /*find the sid for the SAM's domain */
234
235                 /*try using cac_SamLookupDomain() first */
236                 ZERO_STRUCT( sld );
237
238                 sld.in.sam = sam_out;
239                 sld.in.name = hnd->domain;
240
241                 if ( cac_SamLookupDomain( hnd, mem_ctx, &sld ) ) {
242                         /*then we got the sid */
243                         sid_buf = sld.out.sid;
244                 } else {
245                         /*try to get it from the LSA */
246                         sid_buf =
247                                 cac_get_domain_sid( hnd, mem_ctx,
248                                                     op->in.access );
249                 }
250         } else {
251                 /*we already have the sid for the domain we want */
252                 sid_buf = op->in.sid;
253         }
254
255         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
256         if ( !pipe_hnd ) {
257                 hnd->status = NT_STATUS_INVALID_HANDLE;
258                 return CAC_FAILURE;
259         }
260
261         pol_out = talloc( mem_ctx, POLICY_HND );
262         if ( !pol_out ) {
263                 hnd->status = NT_STATUS_NO_MEMORY;
264                 return CAC_FAILURE;
265         }
266
267         /*now open the domain */
268         hnd->status =
269                 rpccli_samr_open_domain( pipe_hnd, mem_ctx, sam_out,
270                                          op->in.access, sid_buf, pol_out );
271
272         if ( !NT_STATUS_IS_OK( hnd->status ) )
273                 return CAC_FAILURE;
274
275         op->out.sam = sam_out;
276         op->out.dom_hnd = pol_out;
277
278         return CAC_SUCCESS;
279 }
280
281 int cac_SamOpenUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
282                      struct SamOpenUser *op )
283 {
284         struct rpc_pipe_client *pipe_hnd = NULL;
285
286         uint32 *rid_buf = NULL;
287
288         uint32 num_rids = 0;
289         uint32 *rid_types = NULL;
290
291         POLICY_HND *user_out = NULL;
292
293         if ( !hnd )
294                 return CAC_FAILURE;
295
296         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
297                 hnd->status = NT_STATUS_INVALID_HANDLE;
298                 return CAC_FAILURE;
299         }
300
301         if ( !op || !op->in.dom_hnd || op->in.access == 0 || !mem_ctx ) {
302                 hnd->status = NT_STATUS_INVALID_PARAMETER;
303                 return CAC_FAILURE;
304         }
305
306         if ( op->in.rid == 0 && op->in.name == NULL ) {
307                 hnd->status = NT_STATUS_INVALID_PARAMETER;
308                 return CAC_FAILURE;
309         }
310
311         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
312         if ( !pipe_hnd ) {
313                 hnd->status = NT_STATUS_INVALID_HANDLE;
314                 return CAC_FAILURE;
315         }
316
317         if ( op->in.rid == 0 && op->in.name ) {
318                 /*lookup the name and then set rid_buf */
319
320                 hnd->status =
321                         rpccli_samr_lookup_names( pipe_hnd, mem_ctx,
322                                                   op->in.dom_hnd,
323                                                   SAMR_LOOKUP_FLAGS, 1,
324                                                   ( const char ** ) &op->in.
325                                                   name, &num_rids, &rid_buf,
326                                                   &rid_types );
327
328                 if ( !NT_STATUS_IS_OK( hnd->status ) )
329                         return CAC_FAILURE;
330
331                 if ( num_rids == 0 || rid_buf == NULL
332                      || rid_types[0] == SAMR_RID_UNKNOWN ) {
333                         hnd->status = NT_STATUS_INVALID_PARAMETER;
334                         return CAC_FAILURE;
335                 }
336
337                 TALLOC_FREE( rid_types );
338
339         } else {
340                 rid_buf = &op->in.rid;
341         }
342
343         user_out = talloc( mem_ctx, POLICY_HND );
344         if ( !user_out ) {
345                 hnd->status = NT_STATUS_NO_MEMORY;
346                 return CAC_FAILURE;
347         }
348
349         hnd->status =
350                 rpccli_samr_open_user( pipe_hnd, mem_ctx, op->in.dom_hnd,
351                                        op->in.access, *rid_buf, user_out );
352
353         if ( !NT_STATUS_IS_OK( hnd->status ) )
354                 return CAC_FAILURE;
355
356         op->out.user_hnd = user_out;
357
358         return CAC_SUCCESS;
359 }
360
361 int cac_SamCreateUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
362                        struct SamCreateUser *op )
363 {
364         struct rpc_pipe_client *pipe_hnd = NULL;
365
366         POLICY_HND *user_out = NULL;
367         uint32 rid_out;
368
369    /**found in rpcclient/cmd_samr.c*/
370         uint32 unknown = 0xe005000b;
371
372         if ( !hnd )
373                 return CAC_FAILURE;
374
375         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
376                 hnd->status = NT_STATUS_INVALID_HANDLE;
377                 return CAC_FAILURE;
378         }
379
380         if ( !op || !op->in.dom_hnd || !op->in.name || op->in.acb_mask == 0
381              || !mem_ctx ) {
382                 hnd->status = NT_STATUS_INVALID_PARAMETER;
383                 return CAC_FAILURE;
384         }
385
386         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
387         if ( !pipe_hnd ) {
388                 hnd->status = NT_STATUS_INVALID_HANDLE;
389                 return CAC_FAILURE;
390         }
391
392         user_out = talloc( mem_ctx, POLICY_HND );
393         if ( !user_out ) {
394                 hnd->status = NT_STATUS_NO_MEMORY;
395                 return CAC_FAILURE;
396         }
397
398         hnd->status =
399                 rpccli_samr_create_dom_user( pipe_hnd, mem_ctx,
400                                              op->in.dom_hnd, op->in.name,
401                                              op->in.acb_mask, unknown,
402                                              user_out, &rid_out );
403
404         if ( !NT_STATUS_IS_OK( hnd->status ) )
405                 return CAC_FAILURE;
406
407         op->out.user_hnd = user_out;
408         op->out.rid = rid_out;
409
410         return CAC_SUCCESS;
411 }
412
413 int cac_SamDeleteUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
414                        POLICY_HND * user_hnd )
415 {
416         struct rpc_pipe_client *pipe_hnd = NULL;
417
418         if ( !hnd )
419                 return CAC_FAILURE;
420
421         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
422                 hnd->status = NT_STATUS_INVALID_HANDLE;
423                 return CAC_FAILURE;
424         }
425
426         if ( !user_hnd || !mem_ctx ) {
427                 hnd->status = NT_STATUS_INVALID_PARAMETER;
428                 return CAC_FAILURE;
429         }
430
431         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
432         if ( !pipe_hnd ) {
433                 hnd->status = NT_STATUS_INVALID_HANDLE;
434                 return CAC_FAILURE;
435         }
436
437         hnd->status =
438                 rpccli_samr_delete_dom_user( pipe_hnd, mem_ctx, user_hnd );
439
440         if ( !NT_STATUS_IS_OK( hnd->status ) )
441                 return CAC_FAILURE;
442
443         return CAC_SUCCESS;
444 }
445
446 int cac_SamEnumUsers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
447                       struct SamEnumUsers *op )
448 {
449         struct rpc_pipe_client *pipe_hnd = NULL;
450
451         uint32 resume_idx_out = 0;
452         char **names_out = NULL;
453         uint32 *rids_out = NULL;
454         uint32 num_users_out = 0;
455
456         if ( !hnd )
457                 return CAC_FAILURE;
458
459         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
460                 hnd->status = NT_STATUS_INVALID_HANDLE;
461                 return CAC_FAILURE;
462         }
463
464         if ( !op || !op->in.dom_hnd || !mem_ctx ) {
465                 hnd->status = NT_STATUS_INVALID_PARAMETER;
466                 return CAC_FAILURE;
467         }
468
469         /*this is a hack.. but is the only reliable way to know if everything has been enumerated */
470         if ( op->out.done == True )
471                 return CAC_FAILURE;
472
473         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
474         if ( !pipe_hnd ) {
475                 hnd->status = NT_STATUS_INVALID_HANDLE;
476                 return CAC_FAILURE;
477         }
478
479         resume_idx_out = op->out.resume_idx;
480
481         hnd->status =
482                 rpccli_samr_enum_dom_users( pipe_hnd, mem_ctx, op->in.dom_hnd,
483                                             &resume_idx_out, op->in.acb_mask,
484                                             SAMR_ENUM_MAX_SIZE, &names_out,
485                                             &rids_out, &num_users_out );
486
487
488         if ( NT_STATUS_IS_OK( hnd->status ) )
489                 op->out.done = True;
490
491         /*if there are no more entries, the operation will return NT_STATUS_OK. 
492          * We want to return failure if no results were returned*/
493         if ( !NT_STATUS_IS_OK( hnd->status )
494              && NT_STATUS_V( hnd->status ) !=
495              NT_STATUS_V( STATUS_MORE_ENTRIES ) )
496                 return CAC_FAILURE;
497
498         op->out.resume_idx = resume_idx_out;
499         op->out.num_users = num_users_out;
500         op->out.rids = rids_out;
501         op->out.names = names_out;
502
503         return CAC_SUCCESS;
504 }
505
506 int cac_SamGetNamesFromRids( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
507                              struct SamGetNamesFromRids *op )
508 {
509         struct rpc_pipe_client *pipe_hnd = NULL;
510
511         uint32 num_names_out;
512         char **names_out;
513         uint32 *name_types_out;
514
515
516         uint32 i = 0;
517
518         CacLookupRidsRecord *map_out;
519
520         if ( !hnd )
521                 return CAC_FAILURE;
522
523         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
524                 hnd->status = NT_STATUS_INVALID_HANDLE;
525                 return CAC_FAILURE;
526         }
527
528         if ( !op || !op->in.dom_hnd || !mem_ctx ) {
529                 hnd->status = NT_STATUS_INVALID_PARAMETER;
530                 return CAC_FAILURE;
531         }
532
533         if ( !op->in.rids && op->in.num_rids != 0 ) {
534                 hnd->status = NT_STATUS_INVALID_PARAMETER;
535                 return CAC_FAILURE;
536         }
537
538         if ( op->in.num_rids == 0 ) {
539                 /*nothing to do */
540                 op->out.num_names = 0;
541                 return CAC_SUCCESS;
542         }
543
544         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
545         if ( !pipe_hnd ) {
546                 hnd->status = NT_STATUS_INVALID_HANDLE;
547                 return CAC_FAILURE;
548         }
549
550         hnd->status =
551                 rpccli_samr_lookup_rids( pipe_hnd, mem_ctx, op->in.dom_hnd,
552                                          op->in.num_rids, op->in.rids,
553                                          &num_names_out, &names_out,
554                                          &name_types_out );
555
556         if ( !NT_STATUS_IS_OK( hnd->status )
557              && !NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) )
558                 return CAC_FAILURE;
559
560         if (num_names_out) {
561                 map_out = TALLOC_ARRAY( mem_ctx, CacLookupRidsRecord, num_names_out );
562                 if ( !map_out ) {
563                         hnd->status = NT_STATUS_NO_MEMORY;
564                         return CAC_FAILURE;
565                 }
566         } else {
567                 map_out = NULL;
568         }
569
570         for ( i = 0; i < num_names_out; i++ ) {
571                 if ( name_types_out[i] == SAMR_RID_UNKNOWN ) {
572                         map_out[i].found = False;
573                         map_out[i].name = NULL;
574                         map_out[i].type = 0;
575                 } else {
576                         map_out[i].found = True;
577                         map_out[i].name =
578                                 talloc_strdup( mem_ctx, names_out[i] );
579                         map_out[i].type = name_types_out[i];
580                 }
581                 map_out[i].rid = op->in.rids[i];
582         }
583
584         TALLOC_FREE( names_out );
585         TALLOC_FREE( name_types_out );
586
587         op->out.num_names = num_names_out;
588         op->out.map = map_out;
589
590         if ( NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) )
591                 return CAC_PARTIAL_SUCCESS;
592
593         return CAC_SUCCESS;
594 }
595
596 int cac_SamGetRidsFromNames( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
597                              struct SamGetRidsFromNames *op )
598 {
599         struct rpc_pipe_client *pipe_hnd = NULL;
600
601         uint32 num_rids_out;
602         uint32 *rids_out;
603         uint32 *rid_types_out;
604
605         uint32 i = 0;
606
607         CacLookupRidsRecord *map_out;
608
609         if ( !hnd )
610                 return CAC_FAILURE;
611
612         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
613                 hnd->status = NT_STATUS_INVALID_HANDLE;
614                 return CAC_FAILURE;
615         }
616
617         if ( !op || !op->in.dom_hnd || !mem_ctx ) {
618                 hnd->status = NT_STATUS_INVALID_PARAMETER;
619                 return CAC_FAILURE;
620         }
621
622         if ( !op->in.names && op->in.num_names != 0 ) {
623                 hnd->status = NT_STATUS_INVALID_PARAMETER;
624                 return CAC_FAILURE;
625         }
626
627         if ( op->in.num_names == 0 ) {
628                 /*then we don't have to do anything */
629                 op->out.num_rids = 0;
630                 return CAC_SUCCESS;
631         }
632
633         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
634         if ( !pipe_hnd ) {
635                 hnd->status = NT_STATUS_INVALID_HANDLE;
636                 return CAC_FAILURE;
637         }
638
639         hnd->status =
640                 rpccli_samr_lookup_names( pipe_hnd, mem_ctx, op->in.dom_hnd,
641                                           SAMR_LOOKUP_FLAGS, op->in.num_names,
642                                           ( const char ** ) op->in.names,
643                                           &num_rids_out, &rids_out,
644                                           &rid_types_out );
645
646         if ( !NT_STATUS_IS_OK( hnd->status )
647              && !NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) )
648                 return CAC_FAILURE;
649
650         if (num_rids_out) {
651                 map_out = TALLOC_ARRAY( mem_ctx, CacLookupRidsRecord, num_rids_out );
652                 if ( !map_out ) {
653                         hnd->status = NT_STATUS_NO_MEMORY;
654                         return CAC_FAILURE;
655                 }
656         } else {
657                 map_out = NULL;
658         }
659
660         for ( i = 0; i < num_rids_out; i++ ) {
661
662                 if ( rid_types_out[i] == SAMR_RID_UNKNOWN ) {
663                         map_out[i].found = False;
664                         map_out[i].rid = 0;
665                         map_out[i].type = 0;
666                 } else {
667                         map_out[i].found = True;
668                         map_out[i].rid = rids_out[i];
669                         map_out[i].type = rid_types_out[i];
670                 }
671
672                 map_out[i].name = talloc_strdup( mem_ctx, op->in.names[i] );
673         }
674
675         op->out.num_rids = num_rids_out;
676         op->out.map = map_out;
677
678         TALLOC_FREE( rids_out );
679         TALLOC_FREE( rid_types_out );
680
681         if ( NT_STATUS_EQUAL( hnd->status, STATUS_SOME_UNMAPPED ) )
682                 return CAC_PARTIAL_SUCCESS;
683
684         return CAC_SUCCESS;
685 }
686
687
688 int cac_SamGetGroupsForUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
689                              struct SamGetGroupsForUser *op )
690 {
691         struct rpc_pipe_client *pipe_hnd = NULL;
692
693         DOM_GID *groups = NULL;
694         uint32 num_groups_out = 0;
695
696         uint32 *rids_out = NULL;
697         uint32 *attr_out = NULL;
698
699         uint32 i;
700
701         if ( !hnd )
702                 return CAC_FAILURE;
703
704         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
705                 hnd->status = NT_STATUS_INVALID_HANDLE;
706                 return CAC_FAILURE;
707         }
708
709         if ( !op || !op->in.user_hnd || !mem_ctx ) {
710                 hnd->status = NT_STATUS_INVALID_PARAMETER;
711                 return CAC_FAILURE;
712         }
713
714         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
715         if ( !pipe_hnd ) {
716                 hnd->status = NT_STATUS_INVALID_HANDLE;
717                 return CAC_FAILURE;
718         }
719
720         hnd->status =
721                 rpccli_samr_query_usergroups( pipe_hnd, mem_ctx,
722                                               op->in.user_hnd,
723                                               &num_groups_out, &groups );
724
725         if ( !NT_STATUS_IS_OK( hnd->status ) )
726                 return CAC_FAILURE;
727
728
729         if (num_groups_out) {
730                 rids_out = TALLOC_ARRAY( mem_ctx, uint32, num_groups_out );
731                 if ( !rids_out ) {
732                         hnd->status = NT_STATUS_NO_MEMORY;
733                         return CAC_FAILURE;
734                 }
735                 attr_out = TALLOC_ARRAY( mem_ctx, uint32, num_groups_out );
736                 if ( !attr_out ) {
737                         hnd->status = NT_STATUS_NO_MEMORY;
738                         return CAC_FAILURE;
739                 }
740         } else {
741                 rids_out = NULL;
742                 attr_out = NULL;
743         }
744
745         for ( i = 0; i < num_groups_out; i++ ) {
746                 rids_out[i] = groups[i].g_rid;
747                 attr_out[i] = groups[i].attr;
748         }
749
750         TALLOC_FREE( groups );
751
752         op->out.num_groups = num_groups_out;
753         op->out.rids = rids_out;
754         op->out.attributes = attr_out;
755
756         return CAC_SUCCESS;
757 }
758
759
760 int cac_SamOpenGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
761                       struct SamOpenGroup *op )
762 {
763         struct rpc_pipe_client *pipe_hnd = NULL;
764
765         POLICY_HND *group_hnd_out = NULL;
766
767         if ( !hnd )
768                 return CAC_FAILURE;
769
770         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
771                 hnd->status = NT_STATUS_INVALID_HANDLE;
772                 return CAC_FAILURE;
773         }
774
775         if ( !op || op->in.access == 0 || op->in.rid == 0 || !mem_ctx ) {
776                 hnd->status = NT_STATUS_INVALID_PARAMETER;
777                 return CAC_FAILURE;
778         }
779
780         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
781         if ( !pipe_hnd ) {
782                 hnd->status = NT_STATUS_INVALID_HANDLE;
783                 return CAC_FAILURE;
784         }
785
786         group_hnd_out = talloc( mem_ctx, POLICY_HND );
787         if ( !group_hnd_out ) {
788                 hnd->status = NT_STATUS_NO_MEMORY;
789                 return CAC_FAILURE;
790         }
791
792         hnd->status =
793                 rpccli_samr_open_group( pipe_hnd, mem_ctx, op->in.dom_hnd,
794                                         op->in.access, op->in.rid,
795                                         group_hnd_out );
796
797         if ( !NT_STATUS_IS_OK( hnd->status ) )
798                 return CAC_FAILURE;
799
800         op->out.group_hnd = group_hnd_out;
801
802         return CAC_SUCCESS;
803 }
804
805 int cac_SamCreateGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
806                         struct SamCreateGroup *op )
807 {
808         struct rpc_pipe_client *pipe_hnd = NULL;
809
810         POLICY_HND *group_hnd_out = NULL;
811
812         if ( !hnd )
813                 return CAC_FAILURE;
814
815         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
816                 hnd->status = NT_STATUS_INVALID_HANDLE;
817                 return CAC_FAILURE;
818         }
819
820         if ( !op || !op->in.name || op->in.name[0] == '\0'
821              || op->in.access == 0 || !mem_ctx ) {
822                 hnd->status = NT_STATUS_INVALID_PARAMETER;
823                 return CAC_FAILURE;
824         }
825
826         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
827         if ( !pipe_hnd ) {
828                 hnd->status = NT_STATUS_INVALID_HANDLE;
829                 return CAC_FAILURE;
830         }
831
832         group_hnd_out = talloc( mem_ctx, POLICY_HND );
833         if ( !group_hnd_out ) {
834                 hnd->status = NT_STATUS_NO_MEMORY;
835                 return CAC_FAILURE;
836         }
837
838         hnd->status =
839                 rpccli_samr_create_dom_group( pipe_hnd, mem_ctx,
840                                               op->in.dom_hnd, op->in.name,
841                                               op->in.access, group_hnd_out );
842
843         if ( !NT_STATUS_IS_OK( hnd->status ) )
844                 return CAC_FAILURE;
845
846         op->out.group_hnd = group_hnd_out;
847
848         return CAC_SUCCESS;
849
850 }
851
852 int cac_SamDeleteGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
853                         POLICY_HND * group_hnd )
854 {
855         struct rpc_pipe_client *pipe_hnd = NULL;
856
857         if ( !hnd )
858                 return CAC_FAILURE;
859
860         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
861                 hnd->status = NT_STATUS_INVALID_HANDLE;
862                 return CAC_FAILURE;
863         }
864
865         if ( !group_hnd || !mem_ctx ) {
866                 hnd->status = NT_STATUS_INVALID_PARAMETER;
867                 return CAC_FAILURE;
868         }
869
870         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
871         if ( !pipe_hnd ) {
872                 hnd->status = NT_STATUS_INVALID_HANDLE;
873                 return CAC_FAILURE;
874         }
875
876         hnd->status =
877                 rpccli_samr_delete_dom_group( pipe_hnd, mem_ctx, group_hnd );
878
879         if ( !NT_STATUS_IS_OK( hnd->status ) )
880                 return CAC_FAILURE;
881
882         return CAC_SUCCESS;
883
884 }
885
886 int cac_SamGetGroupMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
887                             struct SamGetGroupMembers *op )
888 {
889         struct rpc_pipe_client *pipe_hnd = NULL;
890
891         uint32 num_mem_out;
892         uint32 *rids_out;
893         uint32 *attr_out;
894
895         if ( !hnd )
896                 return CAC_FAILURE;
897
898         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
899                 hnd->status = NT_STATUS_INVALID_HANDLE;
900                 return CAC_FAILURE;
901         }
902
903         if ( !op || !op->in.group_hnd || !mem_ctx ) {
904                 hnd->status = NT_STATUS_INVALID_PARAMETER;
905                 return CAC_FAILURE;
906         }
907
908         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
909         if ( !pipe_hnd ) {
910                 hnd->status = NT_STATUS_INVALID_HANDLE;
911                 return CAC_FAILURE;
912         }
913
914         hnd->status =
915                 rpccli_samr_query_groupmem( pipe_hnd, mem_ctx,
916                                             op->in.group_hnd, &num_mem_out,
917                                             &rids_out, &attr_out );
918
919         if ( !NT_STATUS_IS_OK( hnd->status ) )
920                 return CAC_FAILURE;
921
922         op->out.num_members = num_mem_out;
923         op->out.rids = rids_out;
924         op->out.attributes = attr_out;
925
926         return CAC_SUCCESS;
927 }
928
929
930 int cac_SamAddGroupMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
931                            struct SamAddGroupMember *op )
932 {
933         struct rpc_pipe_client *pipe_hnd = NULL;
934
935         if ( !hnd )
936                 return CAC_FAILURE;
937
938         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
939                 hnd->status = NT_STATUS_INVALID_HANDLE;
940                 return CAC_FAILURE;
941         }
942
943         if ( !op || !op->in.group_hnd || op->in.rid == 0 || !mem_ctx ) {
944                 hnd->status = NT_STATUS_INVALID_PARAMETER;
945                 return CAC_FAILURE;
946         }
947
948         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
949         if ( !pipe_hnd ) {
950                 hnd->status = NT_STATUS_INVALID_HANDLE;
951                 return CAC_FAILURE;
952         }
953
954         hnd->status =
955                 rpccli_samr_add_groupmem( pipe_hnd, mem_ctx, op->in.group_hnd,
956                                           op->in.rid );
957
958         if ( !NT_STATUS_IS_OK( hnd->status ) )
959                 return CAC_FAILURE;
960
961         return CAC_SUCCESS;
962 }
963
964 int cac_SamRemoveGroupMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
965                               struct SamRemoveGroupMember *op )
966 {
967         struct rpc_pipe_client *pipe_hnd = NULL;
968
969         if ( !hnd )
970                 return CAC_FAILURE;
971
972         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
973                 hnd->status = NT_STATUS_INVALID_HANDLE;
974                 return CAC_FAILURE;
975         }
976
977         if ( !op || !op->in.group_hnd || op->in.rid == 0 || !mem_ctx ) {
978                 hnd->status = NT_STATUS_INVALID_PARAMETER;
979                 return CAC_FAILURE;
980         }
981
982         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
983         if ( !pipe_hnd ) {
984                 hnd->status = NT_STATUS_INVALID_HANDLE;
985                 return CAC_FAILURE;
986         }
987
988         hnd->status =
989                 rpccli_samr_del_groupmem( pipe_hnd, mem_ctx, op->in.group_hnd,
990                                           op->in.rid );
991
992         if ( !NT_STATUS_IS_OK( hnd->status ) )
993                 return CAC_FAILURE;
994
995         return CAC_SUCCESS;
996 }
997
998 int cac_SamClearGroupMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
999                               POLICY_HND * group_hnd )
1000 {
1001         struct rpc_pipe_client *pipe_hnd = NULL;
1002
1003         int result = CAC_SUCCESS;
1004
1005         int i = 0;
1006
1007         uint32 num_mem = 0;
1008         uint32 *rid = NULL;
1009         uint32 *attr = NULL;
1010
1011         NTSTATUS status;
1012
1013         if ( !hnd )
1014                 return CAC_FAILURE;
1015
1016         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1017                 hnd->status = NT_STATUS_INVALID_HANDLE;
1018                 return CAC_FAILURE;
1019         }
1020
1021         if ( !group_hnd || !mem_ctx ) {
1022                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1023                 return CAC_FAILURE;
1024         }
1025
1026         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1027         if ( !pipe_hnd ) {
1028                 hnd->status = NT_STATUS_INVALID_HANDLE;
1029                 return CAC_FAILURE;
1030         }
1031
1032         hnd->status =
1033                 rpccli_samr_query_groupmem( pipe_hnd, mem_ctx, group_hnd,
1034                                             &num_mem, &rid, &attr );
1035
1036         if ( !NT_STATUS_IS_OK( hnd->status ) )
1037                 return CAC_FAILURE;
1038
1039         /*try to delete the users one by one */
1040         for ( i = 0; i < num_mem && NT_STATUS_IS_OK( hnd->status ); i++ ) {
1041                 hnd->status =
1042                         rpccli_samr_del_groupmem( pipe_hnd, mem_ctx,
1043                                                   group_hnd, rid[i] );
1044         }
1045
1046         /*if not all members could be removed, then try to re-add the members that were already deleted */
1047         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1048                 status = NT_STATUS_OK;
1049
1050                 for ( i -= 1; i >= 0 && NT_STATUS_IS_OK( status ); i-- ) {
1051                         status = rpccli_samr_add_groupmem( pipe_hnd, mem_ctx,
1052                                                            group_hnd,
1053                                                            rid[i] );
1054                 }
1055
1056                 /*we return with the NTSTATUS error that we got when trying to delete users */
1057                 if ( !NT_STATUS_IS_OK( status ) )
1058                         result = CAC_FAILURE;
1059         }
1060
1061         TALLOC_FREE( attr );
1062
1063         return result;
1064 }
1065
1066 int cac_SamSetGroupMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1067                             struct SamSetGroupMembers *op )
1068 {
1069         struct rpc_pipe_client *pipe_hnd = NULL;
1070
1071         uint32 i = 0;
1072
1073         if ( !hnd )
1074                 return CAC_FAILURE;
1075
1076         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1077                 hnd->status = NT_STATUS_INVALID_HANDLE;
1078                 return CAC_FAILURE;
1079         }
1080
1081         if ( !op || !op->in.group_hnd || !mem_ctx ) {
1082                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1083                 return CAC_FAILURE;
1084         }
1085
1086         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1087         if ( !pipe_hnd ) {
1088                 hnd->status = NT_STATUS_INVALID_HANDLE;
1089                 return CAC_FAILURE;
1090         }
1091
1092         /*use cac_SamClearGroupMembers() to clear them */
1093         if ( !cac_SamClearGroupMembers( hnd, mem_ctx, op->in.group_hnd ) )
1094                 return CAC_FAILURE;     /*hnd->status is already set */
1095
1096
1097         for ( i = 0; i < op->in.num_members && NT_STATUS_IS_OK( hnd->status );
1098               i++ ) {
1099                 hnd->status =
1100                         rpccli_samr_add_groupmem( pipe_hnd, mem_ctx,
1101                                                   op->in.group_hnd,
1102                                                   op->in.rids[i] );
1103         }
1104
1105         if ( !NT_STATUS_IS_OK( hnd->status ) )
1106                 return CAC_FAILURE;
1107
1108         return CAC_SUCCESS;
1109
1110 }
1111
1112 int cac_SamEnumGroups( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1113                        struct SamEnumGroups *op )
1114 {
1115         struct rpc_pipe_client *pipe_hnd = NULL;
1116
1117         uint32 i = 0;
1118
1119         uint32 resume_idx_out = 0;
1120         char **names_out = NULL;
1121         char **desc_out = NULL;
1122         uint32 *rids_out = NULL;
1123         uint32 num_groups_out = 0;
1124
1125         struct acct_info *acct_buf = NULL;
1126
1127         if ( !hnd )
1128                 return CAC_FAILURE;
1129
1130         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1131                 hnd->status = NT_STATUS_INVALID_HANDLE;
1132                 return CAC_FAILURE;
1133         }
1134
1135         if ( !op || !op->in.dom_hnd || !mem_ctx ) {
1136                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1137                 return CAC_FAILURE;
1138         }
1139
1140         /*using this BOOL is the only reliable way to know that we are done */
1141         if ( op->out.done == True )     /*we return failure so the call will break out of a loop */
1142                 return CAC_FAILURE;
1143
1144         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1145         if ( !pipe_hnd ) {
1146                 hnd->status = NT_STATUS_INVALID_HANDLE;
1147                 return CAC_FAILURE;
1148         }
1149
1150         resume_idx_out = op->out.resume_idx;
1151
1152         hnd->status =
1153                 rpccli_samr_enum_dom_groups( pipe_hnd, mem_ctx,
1154                                              op->in.dom_hnd, &resume_idx_out,
1155                                              SAMR_ENUM_MAX_SIZE, &acct_buf,
1156                                              &num_groups_out );
1157
1158
1159         if ( NT_STATUS_IS_OK( hnd->status ) ) {
1160                 op->out.done = True;
1161         } else if ( NT_STATUS_V( hnd->status ) !=
1162                     NT_STATUS_V( STATUS_MORE_ENTRIES ) ) {
1163                 /*if there are no more entries, the operation will return NT_STATUS_OK. 
1164                  * We want to return failure if no results were returned*/
1165                 return CAC_FAILURE;
1166         }
1167
1168         if (num_groups_out) {
1169                 names_out = TALLOC_ARRAY( mem_ctx, char *, num_groups_out );
1170                 if ( !names_out ) {
1171                         hnd->status = NT_STATUS_NO_MEMORY;
1172                         TALLOC_FREE( acct_buf );
1173                         return CAC_FAILURE;
1174                 }
1175
1176                 desc_out = TALLOC_ARRAY( mem_ctx, char *, num_groups_out );
1177                 if ( !desc_out ) {
1178                         hnd->status = NT_STATUS_NO_MEMORY;
1179                         TALLOC_FREE( acct_buf );
1180                         TALLOC_FREE( names_out );
1181                         return CAC_FAILURE;
1182                 }
1183
1184                 rids_out = TALLOC_ARRAY( mem_ctx, uint32, num_groups_out );
1185                 if ( !rids_out ) {
1186                         hnd->status = NT_STATUS_NO_MEMORY;
1187                         TALLOC_FREE( acct_buf );
1188                         TALLOC_FREE( names_out );
1189                         TALLOC_FREE( desc_out );
1190                         return CAC_FAILURE;
1191                 }
1192         } else {
1193                 names_out = NULL;
1194                 desc_out = NULL;
1195                 rids_out = NULL;
1196         }
1197
1198         for ( i = 0; i < num_groups_out; i++ ) {
1199                 names_out[i] =
1200                         talloc_strdup( mem_ctx, acct_buf[i].acct_name );
1201                 desc_out[i] = talloc_strdup( mem_ctx, acct_buf[i].acct_desc );
1202                 rids_out[i] = acct_buf[i].rid;
1203
1204                 if ( !names_out[i] || !desc_out[i] ) {
1205                         hnd->status = NT_STATUS_NO_MEMORY;
1206                         return CAC_FAILURE;
1207                 }
1208         }
1209
1210         op->out.resume_idx = resume_idx_out;
1211         op->out.num_groups = num_groups_out;
1212         op->out.rids = rids_out;
1213         op->out.names = names_out;
1214         op->out.descriptions = desc_out;
1215
1216         return CAC_SUCCESS;
1217 }
1218
1219 int cac_SamEnumAliases( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1220                         struct SamEnumAliases *op )
1221 {
1222         struct rpc_pipe_client *pipe_hnd = NULL;
1223
1224         uint32 i = 0;
1225
1226         uint32 resume_idx_out = 0;
1227         char **names_out = NULL;
1228         char **desc_out = NULL;
1229         uint32 *rids_out = NULL;
1230         uint32 num_als_out = 0;
1231
1232         struct acct_info *acct_buf = NULL;
1233
1234         if ( !hnd )
1235                 return CAC_FAILURE;
1236
1237         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1238                 hnd->status = NT_STATUS_INVALID_HANDLE;
1239                 return CAC_FAILURE;
1240         }
1241
1242         if ( !op || !op->in.dom_hnd || !mem_ctx ) {
1243                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1244                 return CAC_FAILURE;
1245         }
1246
1247         /*this is a hack.. but is the only reliable way to know if everything has been enumerated */
1248         if ( op->out.done == True ) {
1249                 return CAC_FAILURE;
1250         }
1251
1252         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1253         if ( !pipe_hnd ) {
1254                 hnd->status = NT_STATUS_INVALID_HANDLE;
1255                 return CAC_FAILURE;
1256         }
1257
1258         resume_idx_out = op->out.resume_idx;
1259
1260         hnd->status =
1261                 rpccli_samr_enum_als_groups( pipe_hnd, mem_ctx,
1262                                              op->in.dom_hnd, &resume_idx_out,
1263                                              SAMR_ENUM_MAX_SIZE, &acct_buf,
1264                                              &num_als_out );
1265
1266
1267         if ( NT_STATUS_IS_OK( hnd->status ) )
1268                 op->out.done = True;
1269
1270         /*if there are no more entries, the operation will return NT_STATUS_OK. 
1271          * We want to return failure if no results were returned*/
1272         if ( !NT_STATUS_IS_OK( hnd->status )
1273              && NT_STATUS_V( hnd->status ) !=
1274              NT_STATUS_V( STATUS_MORE_ENTRIES ) )
1275                 return CAC_FAILURE;
1276
1277         if (num_als_out) {
1278                 names_out = TALLOC_ARRAY( mem_ctx, char *, num_als_out );
1279                 if ( !names_out ) {
1280                         hnd->status = NT_STATUS_NO_MEMORY;
1281                         TALLOC_FREE( acct_buf );
1282                         return CAC_FAILURE;
1283                 }
1284
1285                 desc_out = TALLOC_ARRAY( mem_ctx, char *, num_als_out );
1286                 if ( !desc_out ) {
1287                         hnd->status = NT_STATUS_NO_MEMORY;
1288                         TALLOC_FREE( acct_buf );
1289                         TALLOC_FREE( names_out );
1290                         return CAC_FAILURE;
1291                 }
1292
1293                 rids_out = TALLOC_ARRAY( mem_ctx, uint32, num_als_out );
1294                 if ( !rids_out ) {
1295                         hnd->status = NT_STATUS_NO_MEMORY;
1296                         TALLOC_FREE( acct_buf );
1297                         TALLOC_FREE( names_out );
1298                         TALLOC_FREE( desc_out );
1299                         return CAC_FAILURE;
1300                 }
1301         } else {
1302                 names_out = NULL;
1303                 desc_out = NULL;
1304                 rids_out = NULL;
1305         }
1306
1307         for ( i = 0; i < num_als_out; i++ ) {
1308                 names_out[i] =
1309                         talloc_strdup( mem_ctx, acct_buf[i].acct_name );
1310                 desc_out[i] = talloc_strdup( mem_ctx, acct_buf[i].acct_desc );
1311                 rids_out[i] = acct_buf[i].rid;
1312
1313                 if ( !names_out[i] || !desc_out[i] ) {
1314                         hnd->status = NT_STATUS_NO_MEMORY;
1315                         return CAC_FAILURE;
1316                 }
1317         }
1318
1319         op->out.resume_idx = resume_idx_out;
1320         op->out.num_aliases = num_als_out;
1321         op->out.rids = rids_out;
1322         op->out.names = names_out;
1323         op->out.descriptions = desc_out;
1324
1325         return CAC_SUCCESS;
1326 }
1327
1328 int cac_SamCreateAlias( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1329                         struct SamCreateAlias *op )
1330 {
1331         struct rpc_pipe_client *pipe_hnd = NULL;
1332
1333         POLICY_HND *als_hnd_out = NULL;
1334
1335         if ( !hnd )
1336                 return CAC_FAILURE;
1337
1338         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1339                 hnd->status = NT_STATUS_INVALID_HANDLE;
1340                 return CAC_FAILURE;
1341         }
1342
1343         if ( !op || !op->in.name || op->in.name[0] == '\0' || !mem_ctx ) {
1344                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1345                 return CAC_FAILURE;
1346         }
1347
1348         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1349         if ( !pipe_hnd ) {
1350                 hnd->status = NT_STATUS_INVALID_HANDLE;
1351                 return CAC_FAILURE;
1352         }
1353
1354         als_hnd_out = talloc( mem_ctx, POLICY_HND );
1355         if ( !als_hnd_out ) {
1356                 hnd->status = NT_STATUS_NO_MEMORY;
1357                 return CAC_FAILURE;
1358         }
1359
1360         hnd->status =
1361                 rpccli_samr_create_dom_alias( pipe_hnd, mem_ctx,
1362                                               op->in.dom_hnd, op->in.name,
1363                                               als_hnd_out );
1364
1365         if ( !NT_STATUS_IS_OK( hnd->status ) )
1366                 return CAC_FAILURE;
1367
1368         op->out.alias_hnd = als_hnd_out;
1369
1370         return CAC_SUCCESS;
1371
1372 }
1373
1374 int cac_SamOpenAlias( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1375                       struct SamOpenAlias *op )
1376 {
1377         struct rpc_pipe_client *pipe_hnd = NULL;
1378
1379         POLICY_HND *als_hnd_out = NULL;
1380
1381         if ( !hnd )
1382                 return CAC_FAILURE;
1383
1384         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1385                 hnd->status = NT_STATUS_INVALID_HANDLE;
1386                 return CAC_FAILURE;
1387         }
1388
1389         if ( !op || op->in.access == 0 || op->in.rid == 0 || !mem_ctx ) {
1390                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1391                 return CAC_FAILURE;
1392         }
1393
1394         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1395         if ( !pipe_hnd ) {
1396                 hnd->status = NT_STATUS_INVALID_HANDLE;
1397                 return CAC_FAILURE;
1398         }
1399
1400         als_hnd_out = talloc( mem_ctx, POLICY_HND );
1401         if ( !als_hnd_out ) {
1402                 hnd->status = NT_STATUS_NO_MEMORY;
1403                 return CAC_FAILURE;
1404         }
1405
1406         hnd->status =
1407                 rpccli_samr_open_alias( pipe_hnd, mem_ctx, op->in.dom_hnd,
1408                                         op->in.access, op->in.rid,
1409                                         als_hnd_out );
1410
1411         if ( !NT_STATUS_IS_OK( hnd->status ) )
1412                 return CAC_FAILURE;
1413
1414         op->out.alias_hnd = als_hnd_out;
1415
1416         return CAC_SUCCESS;
1417 }
1418
1419 int cac_SamDeleteAlias( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1420                         POLICY_HND * alias_hnd )
1421 {
1422         struct rpc_pipe_client *pipe_hnd = NULL;
1423
1424         if ( !hnd )
1425                 return CAC_FAILURE;
1426
1427         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1428                 hnd->status = NT_STATUS_INVALID_HANDLE;
1429                 return CAC_FAILURE;
1430         }
1431
1432         if ( !alias_hnd || !mem_ctx ) {
1433                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1434                 return CAC_FAILURE;
1435         }
1436
1437         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1438         if ( !pipe_hnd ) {
1439                 hnd->status = NT_STATUS_INVALID_HANDLE;
1440                 return CAC_FAILURE;
1441         }
1442
1443         hnd->status =
1444                 rpccli_samr_delete_dom_alias( pipe_hnd, mem_ctx, alias_hnd );
1445
1446         if ( !NT_STATUS_IS_OK( hnd->status ) )
1447                 return CAC_FAILURE;
1448
1449         return CAC_SUCCESS;
1450
1451 }
1452
1453 int cac_SamAddAliasMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1454                            struct SamAddAliasMember *op )
1455 {
1456         struct rpc_pipe_client *pipe_hnd = NULL;
1457
1458         if ( !hnd )
1459                 return CAC_FAILURE;
1460
1461         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1462                 hnd->status = NT_STATUS_INVALID_HANDLE;
1463                 return CAC_FAILURE;
1464         }
1465
1466         if ( !op || !op->in.alias_hnd || !op->in.sid || !mem_ctx ) {
1467                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1468                 return CAC_FAILURE;
1469         }
1470
1471         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1472         if ( !pipe_hnd ) {
1473                 hnd->status = NT_STATUS_INVALID_HANDLE;
1474                 return CAC_FAILURE;
1475         }
1476
1477         hnd->status =
1478                 rpccli_samr_add_aliasmem( pipe_hnd, mem_ctx, op->in.alias_hnd,
1479                                           op->in.sid );
1480
1481         if ( !NT_STATUS_IS_OK( hnd->status ) )
1482                 return CAC_FAILURE;
1483
1484         return CAC_SUCCESS;
1485 }
1486
1487 int cac_SamRemoveAliasMember( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1488                               struct SamRemoveAliasMember *op )
1489 {
1490         struct rpc_pipe_client *pipe_hnd = NULL;
1491
1492         if ( !hnd )
1493                 return CAC_FAILURE;
1494
1495         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1496                 hnd->status = NT_STATUS_INVALID_HANDLE;
1497                 return CAC_FAILURE;
1498         }
1499
1500         if ( !op || !op->in.alias_hnd || !op->in.sid || !mem_ctx ) {
1501                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1502                 return CAC_FAILURE;
1503         }
1504
1505         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1506         if ( !pipe_hnd ) {
1507                 hnd->status = NT_STATUS_INVALID_HANDLE;
1508                 return CAC_FAILURE;
1509         }
1510
1511         hnd->status =
1512                 rpccli_samr_del_aliasmem( pipe_hnd, mem_ctx, op->in.alias_hnd,
1513                                           op->in.sid );
1514
1515         if ( !NT_STATUS_IS_OK( hnd->status ) )
1516                 return CAC_FAILURE;
1517
1518         return CAC_SUCCESS;
1519 }
1520
1521 int cac_SamGetAliasMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1522                             struct SamGetAliasMembers *op )
1523 {
1524         struct rpc_pipe_client *pipe_hnd = NULL;
1525
1526         uint32 num_mem_out;
1527         DOM_SID *sids_out;
1528
1529         if ( !hnd )
1530                 return CAC_FAILURE;
1531
1532         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1533                 hnd->status = NT_STATUS_INVALID_HANDLE;
1534                 return CAC_FAILURE;
1535         }
1536
1537         if ( !op || !op->in.alias_hnd || !mem_ctx ) {
1538                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1539                 return CAC_FAILURE;
1540         }
1541
1542         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1543         if ( !pipe_hnd ) {
1544                 hnd->status = NT_STATUS_INVALID_HANDLE;
1545                 return CAC_FAILURE;
1546         }
1547
1548         hnd->status =
1549                 rpccli_samr_query_aliasmem( pipe_hnd, mem_ctx,
1550                                             op->in.alias_hnd, &num_mem_out,
1551                                             &sids_out );
1552
1553         if ( !NT_STATUS_IS_OK( hnd->status ) )
1554                 return CAC_FAILURE;
1555
1556         op->out.num_members = num_mem_out;
1557         op->out.sids = sids_out;
1558
1559         return CAC_SUCCESS;
1560 }
1561
1562 int cac_SamClearAliasMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1563                               POLICY_HND * alias_hnd )
1564 {
1565         struct rpc_pipe_client *pipe_hnd = NULL;
1566
1567         int result = CAC_SUCCESS;
1568
1569         int i = 0;
1570
1571         uint32 num_mem = 0;
1572         DOM_SID *sid = NULL;
1573
1574         NTSTATUS status;
1575
1576         if ( !hnd )
1577                 return CAC_FAILURE;
1578
1579         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1580                 hnd->status = NT_STATUS_INVALID_HANDLE;
1581                 return CAC_FAILURE;
1582         }
1583
1584         if ( !alias_hnd || !mem_ctx ) {
1585                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1586                 return CAC_FAILURE;
1587         }
1588
1589         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1590         if ( !pipe_hnd ) {
1591                 hnd->status = NT_STATUS_INVALID_HANDLE;
1592                 return CAC_FAILURE;
1593         }
1594
1595         hnd->status =
1596                 rpccli_samr_query_aliasmem( pipe_hnd, mem_ctx, alias_hnd,
1597                                             &num_mem, &sid );
1598
1599         if ( !NT_STATUS_IS_OK( hnd->status ) )
1600                 return CAC_FAILURE;
1601
1602         /*try to delete the users one by one */
1603         for ( i = 0; i < num_mem && NT_STATUS_IS_OK( hnd->status ); i++ ) {
1604                 hnd->status =
1605                         rpccli_samr_del_aliasmem( pipe_hnd, mem_ctx,
1606                                                   alias_hnd, &sid[i] );
1607         }
1608
1609         /*if not all members could be removed, then try to re-add the members that were already deleted */
1610         if ( !NT_STATUS_IS_OK( hnd->status ) ) {
1611                 status = NT_STATUS_OK;
1612
1613                 for ( i -= 1; i >= 0 && NT_STATUS_IS_OK( status ); i-- ) {
1614                         status = rpccli_samr_add_aliasmem( pipe_hnd, mem_ctx,
1615                                                            alias_hnd,
1616                                                            &sid[i] );
1617                 }
1618
1619                 /*we return with the NTSTATUS error that we got when trying to delete users */
1620                 if ( !NT_STATUS_IS_OK( status ) )
1621                         result = CAC_FAILURE;
1622         }
1623
1624         TALLOC_FREE( sid );
1625         return result;
1626 }
1627
1628 int cac_SamSetAliasMembers( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1629                             struct SamSetAliasMembers *op )
1630 {
1631         struct rpc_pipe_client *pipe_hnd = NULL;
1632
1633         uint32 i = 0;
1634
1635         if ( !hnd )
1636                 return CAC_FAILURE;
1637
1638         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1639                 hnd->status = NT_STATUS_INVALID_HANDLE;
1640                 return CAC_FAILURE;
1641         }
1642
1643         if ( !op || !op->in.alias_hnd || !mem_ctx ) {
1644                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1645                 return CAC_FAILURE;
1646         }
1647
1648         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1649         if ( !pipe_hnd ) {
1650                 hnd->status = NT_STATUS_INVALID_HANDLE;
1651                 return CAC_FAILURE;
1652         }
1653
1654         /*use cac_SamClearAliasMembers() to clear them */
1655         if ( !cac_SamClearAliasMembers( hnd, mem_ctx, op->in.alias_hnd ) )
1656                 return CAC_FAILURE;     /*hnd->status is already set */
1657
1658
1659         for ( i = 0; i < op->in.num_members && NT_STATUS_IS_OK( hnd->status );
1660               i++ ) {
1661                 hnd->status =
1662                         rpccli_samr_add_aliasmem( pipe_hnd, mem_ctx,
1663                                                   op->in.alias_hnd,
1664                                                   &( op->in.sids[i] ) );
1665         }
1666
1667         if ( !NT_STATUS_IS_OK( hnd->status ) )
1668                 return CAC_FAILURE;
1669
1670         return CAC_SUCCESS;
1671
1672 }
1673
1674 int cac_SamUserChangePasswd( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1675                              struct SamUserChangePasswd *op )
1676 {
1677         SMBCSRV *srv = NULL;
1678         struct rpc_pipe_client *pipe_hnd = NULL;
1679
1680         if ( !hnd )
1681                 return CAC_FAILURE;
1682
1683         if ( !hnd->_internal.ctx ) {
1684                 hnd->status = NT_STATUS_INVALID_HANDLE;
1685                 return CAC_FAILURE;
1686         }
1687
1688         if ( !op || !op->in.username || !op->in.password
1689              || !op->in.new_password || !mem_ctx ) {
1690                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1691                 return CAC_FAILURE;
1692         }
1693
1694         srv = cac_GetServer( hnd );
1695         if ( !srv ) {
1696                 hnd->status = NT_STATUS_INVALID_CONNECTION;
1697                 return CAC_FAILURE;
1698         }
1699
1700         /*open a session on SAMR if we don't have one */
1701         if ( !hnd->_internal.pipes[PI_SAMR] ) {
1702                 if ( !
1703                      ( pipe_hnd =
1704                        cli_rpc_pipe_open_noauth( srv->cli, PI_SAMR,
1705                                                  &hnd->status ) ) ) {
1706                         return CAC_FAILURE;
1707                 }
1708
1709                 hnd->_internal.pipes[PI_SAMR] = True;
1710         }
1711
1712         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1713         if ( !pipe_hnd ) {
1714                 hnd->status = NT_STATUS_INVALID_HANDLE;
1715                 return CAC_FAILURE;
1716         }
1717
1718         hnd->status =
1719                 rpccli_samr_chgpasswd_user( pipe_hnd, mem_ctx,
1720                                             op->in.username,
1721                                             op->in.new_password,
1722                                             op->in.password );
1723
1724         if ( !NT_STATUS_IS_OK( hnd->status ) )
1725                 return CAC_FAILURE;
1726
1727         return CAC_SUCCESS;
1728 }
1729
1730 int cac_SamEnableUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1731                        POLICY_HND * user_hnd )
1732 {
1733         SMBCSRV *srv = NULL;
1734         struct rpc_pipe_client *pipe_hnd = NULL;
1735
1736         SAM_USERINFO_CTR *ctr;
1737
1738         if ( !hnd )
1739                 return CAC_FAILURE;
1740
1741         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1742                 hnd->status = NT_STATUS_INVALID_HANDLE;
1743                 return CAC_FAILURE;
1744         }
1745
1746         if ( !user_hnd || !mem_ctx ) {
1747                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1748                 return CAC_FAILURE;
1749         }
1750
1751         srv = cac_GetServer( hnd );
1752         if ( !srv ) {
1753                 hnd->status = NT_STATUS_INVALID_CONNECTION;
1754                 return CAC_FAILURE;
1755         }
1756
1757         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1758         if ( !pipe_hnd ) {
1759                 hnd->status = NT_STATUS_INVALID_HANDLE;
1760                 return CAC_FAILURE;
1761         }
1762
1763         /*info_level = 21 is the only level that I have found to work reliably. It would be nice if user_level = 10 worked. */
1764         hnd->status =
1765                 rpccli_samr_query_userinfo( pipe_hnd, mem_ctx, user_hnd, 0x10,
1766                                             &ctr );
1767
1768         if ( !NT_STATUS_IS_OK( hnd->status ) )
1769                 return CAC_FAILURE;
1770
1771    /**check the ACB mask*/
1772         if ( ( ctr->info.id16->acb_info & ACB_DISABLED ) == ACB_DISABLED ) {
1773                 /*toggle the disabled bit */
1774                 ctr->info.id16->acb_info ^= ACB_DISABLED;
1775         } else {
1776                 /*the user is already enabled so just return success */
1777                 return CAC_SUCCESS;
1778         }
1779
1780         /*now set the userinfo */
1781         hnd->status =
1782                 rpccli_samr_set_userinfo2( pipe_hnd, mem_ctx, user_hnd, 0x10,
1783                                            &srv->cli->user_session_key, ctr );
1784
1785         /*this will only work properly if we use set_userinfo2 - fail if it is not supported */
1786         if ( !NT_STATUS_IS_OK( hnd->status ) )
1787                 return CAC_FAILURE;
1788
1789         return CAC_SUCCESS;
1790 }
1791
1792 int cac_SamDisableUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1793                         POLICY_HND * user_hnd )
1794 {
1795         SMBCSRV *srv = NULL;
1796         struct rpc_pipe_client *pipe_hnd = NULL;
1797
1798         SAM_USERINFO_CTR *ctr;
1799
1800         if ( !hnd )
1801                 return CAC_FAILURE;
1802
1803         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1804                 hnd->status = NT_STATUS_INVALID_HANDLE;
1805                 return CAC_FAILURE;
1806         }
1807
1808         if ( !user_hnd || !mem_ctx ) {
1809                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1810                 return CAC_FAILURE;
1811         }
1812
1813         srv = cac_GetServer( hnd );
1814         if ( !srv ) {
1815                 hnd->status = NT_STATUS_INVALID_CONNECTION;
1816                 return CAC_FAILURE;
1817         }
1818
1819         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1820         if ( !pipe_hnd ) {
1821                 hnd->status = NT_STATUS_INVALID_HANDLE;
1822                 return CAC_FAILURE;
1823         }
1824
1825         hnd->status =
1826                 rpccli_samr_query_userinfo( pipe_hnd, mem_ctx, user_hnd, 0x10,
1827                                             &ctr );
1828
1829         if ( !NT_STATUS_IS_OK( hnd->status ) )
1830                 return CAC_FAILURE;
1831
1832         if ( ( ctr->info.id16->acb_info & ACB_DISABLED ) == ACB_DISABLED ) {
1833                 /*then the user is already disabled */
1834                 return CAC_SUCCESS;
1835         }
1836
1837         /*toggle the disabled bit */
1838         ctr->info.id16->acb_info ^= ACB_DISABLED;
1839
1840         /*this will only work properly if we use set_userinfo2 */
1841         hnd->status =
1842                 rpccli_samr_set_userinfo2( pipe_hnd, mem_ctx, user_hnd, 0x10,
1843                                            &srv->cli->user_session_key, ctr );
1844
1845         /*this will only work properly if we use set_userinfo2 fail if it is not supported */
1846         if ( !NT_STATUS_IS_OK( hnd->status ) )
1847                 return CAC_FAILURE;
1848
1849         return CAC_SUCCESS;
1850 }
1851
1852 int cac_SamSetPassword( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1853                         struct SamSetPassword *op )
1854 {
1855         SMBCSRV *srv = NULL;
1856         struct rpc_pipe_client *pipe_hnd = NULL;
1857
1858         SAM_USERINFO_CTR ctr;
1859         SAM_USER_INFO_24 info24;
1860         uint8 pw[516];
1861
1862         if ( !hnd )
1863                 return CAC_FAILURE;
1864
1865         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1866                 hnd->status = NT_STATUS_INVALID_HANDLE;
1867                 return CAC_FAILURE;
1868         }
1869
1870         if ( !op->in.user_hnd || !op->in.password || !mem_ctx ) {
1871                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1872                 return CAC_FAILURE;
1873         }
1874
1875         srv = cac_GetServer( hnd );
1876         if ( !srv ) {
1877                 hnd->status = NT_STATUS_INVALID_CONNECTION;
1878                 return CAC_FAILURE;
1879         }
1880
1881         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1882         if ( !pipe_hnd ) {
1883                 hnd->status = NT_STATUS_INVALID_HANDLE;
1884                 return CAC_FAILURE;
1885         }
1886
1887         ZERO_STRUCT( ctr );
1888         ZERO_STRUCT( info24 );
1889
1890         encode_pw_buffer( pw, op->in.password, STR_UNICODE );
1891
1892         init_sam_user_info24( &info24, ( char * ) pw, 24 );
1893
1894         ctr.switch_value = 24;
1895         ctr.info.id24 = &info24;
1896
1897         hnd->status =
1898                 rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd,
1899                                           24, &srv->cli->user_session_key,
1900                                           &ctr );
1901
1902         if ( !NT_STATUS_IS_OK( hnd->status ) )
1903                 return CAC_FAILURE;
1904
1905         return CAC_SUCCESS;
1906 }
1907
1908 int cac_SamGetUserInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1909                         struct SamGetUserInfo *op )
1910 {
1911         struct rpc_pipe_client *pipe_hnd = NULL;
1912
1913         SAM_USERINFO_CTR *ctr;
1914
1915         if ( !hnd )
1916                 return CAC_FAILURE;
1917
1918         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1919                 hnd->status = NT_STATUS_INVALID_HANDLE;
1920                 return CAC_FAILURE;
1921         }
1922
1923         if ( !op->in.user_hnd || !mem_ctx ) {
1924                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1925                 return CAC_FAILURE;
1926         }
1927
1928         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1929         if ( !pipe_hnd ) {
1930                 hnd->status = NT_STATUS_INVALID_HANDLE;
1931                 return CAC_FAILURE;
1932         }
1933
1934         hnd->status =
1935                 rpccli_samr_query_userinfo( pipe_hnd, mem_ctx,
1936                                             op->in.user_hnd, 21, &ctr );
1937
1938         if ( !NT_STATUS_IS_OK( hnd->status ) )
1939                 return CAC_FAILURE;
1940
1941         op->out.info = cac_MakeUserInfo( mem_ctx, ctr );
1942
1943         if ( !op->out.info ) {
1944                 hnd->status = NT_STATUS_NO_MEMORY;
1945                 return CAC_FAILURE;
1946         }
1947
1948         return CAC_SUCCESS;
1949 }
1950
1951 int cac_SamSetUserInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
1952                         struct SamSetUserInfo *op )
1953 {
1954         SMBCSRV *srv = NULL;
1955         struct rpc_pipe_client *pipe_hnd = NULL;
1956
1957         SAM_USERINFO_CTR *ctr;
1958
1959         if ( !hnd )
1960                 return CAC_FAILURE;
1961
1962         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
1963                 hnd->status = NT_STATUS_INVALID_HANDLE;
1964                 return CAC_FAILURE;
1965         }
1966
1967         if ( !op->in.user_hnd || !op->in.info || !mem_ctx ) {
1968                 hnd->status = NT_STATUS_INVALID_PARAMETER;
1969                 return CAC_FAILURE;
1970         }
1971
1972         ctr = cac_MakeUserInfoCtr( mem_ctx, op->in.info );
1973         if ( !ctr ) {
1974                 hnd->status = NT_STATUS_NO_MEMORY;
1975                 return CAC_FAILURE;
1976         }
1977
1978         srv = cac_GetServer( hnd );
1979         if ( !srv ) {
1980                 hnd->status = NT_STATUS_INVALID_CONNECTION;
1981                 return CAC_FAILURE;
1982         }
1983
1984         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
1985         if ( !pipe_hnd ) {
1986                 hnd->status = NT_STATUS_INVALID_HANDLE;
1987                 return CAC_FAILURE;
1988         }
1989
1990         if ( hnd->_internal.srv_level >= SRV_WIN_NT4 ) {
1991                 hnd->status =
1992                         rpccli_samr_set_userinfo2( pipe_hnd, mem_ctx,
1993                                                    op->in.user_hnd, 21,
1994                                                    &srv->cli->
1995                                                    user_session_key, ctr );
1996         }
1997
1998         if ( hnd->_internal.srv_level < SRV_WIN_NT4
1999              || !NT_STATUS_IS_OK( hnd->status ) ) {
2000                 hnd->status =
2001                         rpccli_samr_set_userinfo( pipe_hnd, mem_ctx,
2002                                                   op->in.user_hnd, 21,
2003                                                   &srv->cli->user_session_key,
2004                                                   ctr );
2005
2006                 if ( NT_STATUS_IS_OK( hnd->status )
2007                      && hnd->_internal.srv_level > SRV_WIN_NT4 ) {
2008                         hnd->_internal.srv_level = SRV_WIN_NT4;
2009                 }
2010         }
2011
2012
2013         if ( !NT_STATUS_IS_OK( hnd->status ) )
2014                 return CAC_FAILURE;
2015
2016         return CAC_SUCCESS;
2017 }
2018
2019
2020 int cac_SamGetUserInfoCtr( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2021                            struct SamGetUserInfoCtr *op )
2022 {
2023         struct rpc_pipe_client *pipe_hnd = NULL;
2024
2025         SAM_USERINFO_CTR *ctr_out;
2026
2027         if ( !hnd )
2028                 return CAC_FAILURE;
2029
2030         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2031                 hnd->status = NT_STATUS_INVALID_HANDLE;
2032                 return CAC_FAILURE;
2033         }
2034
2035         if ( !op->in.user_hnd || op->in.info_class == 0 || !mem_ctx ) {
2036                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2037                 return CAC_FAILURE;
2038         }
2039
2040         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2041         if ( !pipe_hnd ) {
2042                 hnd->status = NT_STATUS_INVALID_HANDLE;
2043                 return CAC_FAILURE;
2044         }
2045
2046         hnd->status =
2047                 rpccli_samr_query_userinfo( pipe_hnd, mem_ctx,
2048                                             op->in.user_hnd,
2049                                             op->in.info_class, &ctr_out );
2050
2051         if ( !NT_STATUS_IS_OK( hnd->status ) )
2052                 return CAC_FAILURE;
2053
2054         op->out.ctr = ctr_out;
2055
2056         return CAC_SUCCESS;
2057 }
2058
2059 int cac_SamSetUserInfoCtr( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2060                            struct SamSetUserInfoCtr *op )
2061 {
2062         SMBCSRV *srv = NULL;
2063         struct rpc_pipe_client *pipe_hnd = NULL;
2064
2065         if ( !hnd )
2066                 return CAC_FAILURE;
2067
2068         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2069                 hnd->status = NT_STATUS_INVALID_HANDLE;
2070                 return CAC_FAILURE;
2071         }
2072
2073         if ( !op->in.user_hnd || !op->in.ctr || !mem_ctx ) {
2074                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2075                 return CAC_FAILURE;
2076         }
2077
2078         srv = cac_GetServer( hnd );
2079         if ( !srv ) {
2080                 hnd->status = NT_STATUS_INVALID_CONNECTION;
2081                 return CAC_FAILURE;
2082         }
2083
2084         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2085         if ( !pipe_hnd ) {
2086                 hnd->status = NT_STATUS_INVALID_HANDLE;
2087                 return CAC_FAILURE;
2088         }
2089
2090
2091         hnd->status =
2092                 rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd,
2093                                           op->in.ctr->switch_value,
2094                                           &srv->cli->user_session_key,
2095                                           op->in.ctr );
2096
2097         if ( !NT_STATUS_IS_OK( hnd->status ) )
2098                 return CAC_FAILURE;
2099
2100         return CAC_SUCCESS;
2101
2102 }
2103
2104 int cac_SamRenameUser( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2105                        struct SamRenameUser *op )
2106 {
2107         SMBCSRV *srv = NULL;
2108         struct rpc_pipe_client *pipe_hnd = NULL;
2109
2110         SAM_USERINFO_CTR ctr;
2111         SAM_USER_INFO_7 info7;
2112
2113         if ( !hnd )
2114                 return CAC_FAILURE;
2115
2116         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2117                 hnd->status = NT_STATUS_INVALID_HANDLE;
2118                 return CAC_FAILURE;
2119         }
2120
2121         if ( !op->in.user_hnd || !op->in.new_name
2122              || op->in.new_name[0] == '\0' || !mem_ctx ) {
2123                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2124                 return CAC_FAILURE;
2125         }
2126
2127         srv = cac_GetServer( hnd );
2128         if ( !srv ) {
2129                 hnd->status = NT_STATUS_INVALID_CONNECTION;
2130                 return CAC_FAILURE;
2131         }
2132
2133         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2134         if ( !pipe_hnd ) {
2135                 hnd->status = NT_STATUS_INVALID_HANDLE;
2136                 return CAC_FAILURE;
2137         }
2138
2139         ZERO_STRUCT( ctr );
2140         ZERO_STRUCT( info7 );
2141
2142         init_sam_user_info7( &info7, op->in.new_name );
2143
2144         ctr.switch_value = 7;
2145         ctr.info.id7 = &info7;
2146
2147         hnd->status =
2148                 rpccli_samr_set_userinfo( pipe_hnd, mem_ctx, op->in.user_hnd,
2149                                           7, &srv->cli->user_session_key,
2150                                           &ctr );
2151
2152         if ( !NT_STATUS_IS_OK( hnd->status ) )
2153                 return CAC_FAILURE;
2154
2155         return CAC_SUCCESS;
2156 }
2157
2158
2159 int cac_SamGetGroupInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2160                          struct SamGetGroupInfo *op )
2161 {
2162         struct rpc_pipe_client *pipe_hnd = NULL;
2163
2164         GROUP_INFO_CTR *ctr;
2165
2166         if ( !hnd )
2167                 return CAC_FAILURE;
2168
2169         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2170                 hnd->status = NT_STATUS_INVALID_HANDLE;
2171                 return CAC_FAILURE;
2172         }
2173
2174         if ( !op->in.group_hnd || !mem_ctx ) {
2175                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2176                 return CAC_FAILURE;
2177         }
2178
2179         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2180         if ( !pipe_hnd ) {
2181                 hnd->status = NT_STATUS_INVALID_HANDLE;
2182                 return CAC_FAILURE;
2183         }
2184
2185
2186         /*get a GROUP_INFO_1 structure */
2187         hnd->status =
2188                 rpccli_samr_query_groupinfo( pipe_hnd, mem_ctx,
2189                                              op->in.group_hnd, 1, &ctr );
2190
2191         if ( !NT_STATUS_IS_OK( hnd->status ) )
2192                 return CAC_FAILURE;
2193
2194         op->out.info = cac_MakeGroupInfo( mem_ctx, ctr );
2195         if ( !op->out.info ) {
2196                 hnd->status = NT_STATUS_NO_MEMORY;
2197                 return CAC_FAILURE;
2198         }
2199
2200         return CAC_SUCCESS;
2201 }
2202
2203 int cac_SamSetGroupInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2204                          struct SamSetGroupInfo *op )
2205 {
2206         struct rpc_pipe_client *pipe_hnd = NULL;
2207
2208         GROUP_INFO_CTR *ctr = NULL;
2209
2210         if ( !hnd )
2211                 return CAC_FAILURE;
2212
2213         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2214                 hnd->status = NT_STATUS_INVALID_HANDLE;
2215                 return CAC_FAILURE;
2216         }
2217
2218         if ( !op->in.group_hnd || !op->in.info || !mem_ctx ) {
2219                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2220                 return CAC_FAILURE;
2221         }
2222
2223         ctr = cac_MakeGroupInfoCtr( mem_ctx, op->in.info );
2224         if ( !ctr ) {
2225                 hnd->status = NT_STATUS_NO_MEMORY;
2226                 return CAC_FAILURE;
2227         }
2228
2229         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2230         if ( !pipe_hnd ) {
2231                 hnd->status = NT_STATUS_INVALID_HANDLE;
2232                 return CAC_FAILURE;
2233         }
2234
2235         hnd->status =
2236                 rpccli_samr_set_groupinfo( pipe_hnd, mem_ctx,
2237                                            op->in.group_hnd, ctr );
2238
2239         if ( !NT_STATUS_IS_OK( hnd->status ) )
2240                 return CAC_FAILURE;
2241
2242         return CAC_SUCCESS;
2243 }
2244
2245 int cac_SamRenameGroup( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2246                         struct SamRenameGroup *op )
2247 {
2248         struct rpc_pipe_client *pipe_hnd = NULL;
2249
2250         GROUP_INFO_CTR ctr;
2251
2252         if ( !hnd )
2253                 return CAC_FAILURE;
2254
2255         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2256                 hnd->status = NT_STATUS_INVALID_HANDLE;
2257                 return CAC_FAILURE;
2258         }
2259
2260         if ( !op->in.group_hnd || !op->in.new_name
2261              || op->in.new_name[0] == '\0' || !mem_ctx ) {
2262                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2263                 return CAC_FAILURE;
2264         }
2265
2266         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2267         if ( !pipe_hnd ) {
2268                 hnd->status = NT_STATUS_INVALID_HANDLE;
2269                 return CAC_FAILURE;
2270         }
2271
2272         ZERO_STRUCT( ctr );
2273
2274         init_samr_group_info2( &ctr.group.info2, op->in.new_name );
2275         ctr.switch_value1 = 2;
2276
2277         hnd->status =
2278                 rpccli_samr_set_groupinfo( pipe_hnd, mem_ctx,
2279                                            op->in.group_hnd, &ctr );
2280
2281         if ( !NT_STATUS_IS_OK( hnd->status ) )
2282                 return CAC_FAILURE;
2283
2284         return CAC_SUCCESS;
2285 }
2286
2287 int cac_SamGetAliasInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2288                          struct SamGetAliasInfo *op )
2289 {
2290         struct rpc_pipe_client *pipe_hnd = NULL;
2291
2292         ALIAS_INFO_CTR ctr;
2293
2294         if ( !hnd )
2295                 return CAC_FAILURE;
2296
2297         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2298                 hnd->status = NT_STATUS_INVALID_HANDLE;
2299                 return CAC_FAILURE;
2300         }
2301
2302         if ( !op->in.alias_hnd || !mem_ctx ) {
2303                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2304                 return CAC_FAILURE;
2305         }
2306
2307         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2308         if ( !pipe_hnd ) {
2309                 hnd->status = NT_STATUS_INVALID_HANDLE;
2310                 return CAC_FAILURE;
2311         }
2312
2313         /*get a GROUP_INFO_1 structure */
2314         hnd->status =
2315                 rpccli_samr_query_alias_info( pipe_hnd, mem_ctx,
2316                                               op->in.alias_hnd, 1, &ctr );
2317
2318         if ( !NT_STATUS_IS_OK( hnd->status ) )
2319                 return CAC_FAILURE;
2320
2321         op->out.info = cac_MakeAliasInfo( mem_ctx, ctr );
2322         if ( !op->out.info ) {
2323                 hnd->status = NT_STATUS_NO_MEMORY;
2324                 return CAC_FAILURE;
2325         }
2326
2327         return CAC_SUCCESS;
2328
2329 }
2330
2331 int cac_SamSetAliasInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2332                          struct SamSetAliasInfo *op )
2333 {
2334         struct rpc_pipe_client *pipe_hnd = NULL;
2335
2336         ALIAS_INFO_CTR *ctr = NULL;
2337
2338         if ( !hnd )
2339                 return CAC_FAILURE;
2340
2341         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2342                 hnd->status = NT_STATUS_INVALID_HANDLE;
2343                 return CAC_FAILURE;
2344         }
2345
2346         if ( !op->in.alias_hnd || !op->in.info || !mem_ctx ) {
2347                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2348                 return CAC_FAILURE;
2349         }
2350
2351         ctr = cac_MakeAliasInfoCtr( mem_ctx, op->in.info );
2352         if ( !ctr ) {
2353                 hnd->status = NT_STATUS_NO_MEMORY;
2354                 return CAC_FAILURE;
2355         }
2356
2357         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2358         if ( !pipe_hnd ) {
2359                 hnd->status = NT_STATUS_INVALID_HANDLE;
2360                 return CAC_FAILURE;
2361         }
2362
2363         hnd->status =
2364                 rpccli_samr_set_aliasinfo( pipe_hnd, mem_ctx,
2365                                            op->in.alias_hnd, ctr );
2366
2367         if ( !NT_STATUS_IS_OK( hnd->status ) )
2368                 return CAC_FAILURE;
2369
2370         return CAC_SUCCESS;
2371 }
2372
2373 int cac_SamGetDomainInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2374                           struct SamGetDomainInfo *op )
2375 {
2376         struct rpc_pipe_client *pipe_hnd = NULL;
2377
2378         SAM_UNK_CTR ctr;
2379         SAM_UNK_INFO_1 info1;
2380         SAM_UNK_INFO_2 info2;
2381         SAM_UNK_INFO_12 info12;
2382
2383         /*use this to keep track of a failed call */
2384         NTSTATUS status_buf = NT_STATUS_OK;
2385
2386         uint16 fail_count = 0;
2387
2388
2389         if ( !hnd )
2390                 return CAC_FAILURE;
2391
2392         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2393                 hnd->status = NT_STATUS_INVALID_HANDLE;
2394                 return CAC_FAILURE;
2395         }
2396
2397         if ( !op->in.dom_hnd || !mem_ctx ) {
2398                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2399                 return CAC_FAILURE;
2400         }
2401
2402         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2403         if ( !pipe_hnd ) {
2404                 hnd->status = NT_STATUS_INVALID_HANDLE;
2405                 return CAC_FAILURE;
2406         }
2407
2408         /*first try with info 1 */
2409         hnd->status =
2410                 rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd,
2411                                             1, &ctr );
2412
2413         if ( NT_STATUS_IS_OK( hnd->status ) ) {
2414                 /*then we buffer the SAM_UNK_INFO_1 structure */
2415                 info1 = ctr.info.inf1;
2416         } else {
2417                 /*then the call failed, store the status and ZERO out the info structure */
2418                 ZERO_STRUCT( info1 );
2419                 status_buf = hnd->status;
2420                 fail_count++;
2421         }
2422
2423         /*try again for the next one */
2424         hnd->status =
2425                 rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd,
2426                                             2, &ctr );
2427
2428         if ( NT_STATUS_IS_OK( hnd->status ) ) {
2429                 /*store the info */
2430                 info2 = ctr.info.inf2;
2431         } else {
2432                 /*ZERO out the structure and store the bad status */
2433                 ZERO_STRUCT( info2 );
2434                 status_buf = hnd->status;
2435                 fail_count++;
2436         }
2437
2438         /*once more */
2439         hnd->status =
2440                 rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd,
2441                                             12, &ctr );
2442
2443         if ( NT_STATUS_IS_OK( hnd->status ) ) {
2444                 info12 = ctr.info.inf12;
2445         } else {
2446                 ZERO_STRUCT( info12 );
2447                 status_buf = hnd->status;
2448                 fail_count++;
2449         }
2450
2451         /*return failure if all 3 calls failed */
2452         if ( fail_count == 3 )
2453                 return CAC_FAILURE;
2454
2455         op->out.info = cac_MakeDomainInfo( mem_ctx, &info1, &info2, &info12 );
2456
2457         if ( !op->out.info ) {
2458                 hnd->status = NT_STATUS_NO_MEMORY;
2459                 return CAC_FAILURE;
2460         }
2461
2462         if ( fail_count > 0 ) {
2463                 hnd->status = status_buf;
2464                 return CAC_PARTIAL_SUCCESS;
2465         }
2466
2467         return CAC_SUCCESS;
2468 }
2469
2470 int cac_SamGetDomainInfoCtr( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2471                              struct SamGetDomainInfoCtr *op )
2472 {
2473         struct rpc_pipe_client *pipe_hnd = NULL;
2474
2475         SAM_UNK_CTR *ctr_out;
2476
2477         if ( !hnd )
2478                 return CAC_FAILURE;
2479
2480         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2481                 hnd->status = NT_STATUS_INVALID_HANDLE;
2482                 return CAC_FAILURE;
2483         }
2484
2485         if ( !op->in.dom_hnd || op->in.info_class == 0 || !mem_ctx ) {
2486                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2487                 return CAC_FAILURE;
2488         }
2489
2490         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2491         if ( !pipe_hnd ) {
2492                 hnd->status = NT_STATUS_INVALID_HANDLE;
2493                 return CAC_FAILURE;
2494         }
2495
2496         ctr_out = talloc( mem_ctx, SAM_UNK_CTR );
2497         if ( !ctr_out ) {
2498                 hnd->status = NT_STATUS_NO_MEMORY;
2499                 return CAC_FAILURE;
2500         }
2501
2502         hnd->status =
2503                 rpccli_samr_query_dom_info( pipe_hnd, mem_ctx, op->in.dom_hnd,
2504                                             op->in.info_class, ctr_out );
2505
2506         if ( !NT_STATUS_IS_OK( hnd->status ) )
2507                 return CAC_FAILURE;
2508
2509         op->out.info = ctr_out;
2510
2511         return CAC_SUCCESS;
2512 }
2513
2514 int cac_SamGetDisplayInfo( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2515                            struct SamGetDisplayInfo *op )
2516 {
2517         struct rpc_pipe_client *pipe_hnd = NULL;
2518
2519         SAM_DISPINFO_CTR ctr_out;
2520
2521         uint32 max_entries_buf = 0;
2522         uint32 max_size_buf = 0;
2523
2524         uint32 resume_idx_out;
2525         uint32 num_entries_out;
2526
2527         if ( !hnd )
2528                 return CAC_FAILURE;
2529
2530         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2531                 hnd->status = NT_STATUS_INVALID_HANDLE;
2532                 return CAC_FAILURE;
2533         }
2534
2535         if ( !op->in.dom_hnd || op->in.info_class == 0 || !mem_ctx ) {
2536                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2537                 return CAC_FAILURE;
2538         }
2539
2540         if ( op->out.done == True )     /*this is done so we can use the function as a loop condition */
2541                 return CAC_FAILURE;
2542
2543         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2544         if ( !pipe_hnd ) {
2545                 hnd->status = NT_STATUS_INVALID_HANDLE;
2546                 return CAC_FAILURE;
2547         }
2548
2549         if ( op->in.max_entries == 0 || op->in.max_size == 0 ) {
2550                 get_query_dispinfo_params( op->out.loop_count,
2551                                            &max_entries_buf, &max_size_buf );
2552         } else {
2553                 max_entries_buf = op->in.max_entries;
2554                 max_size_buf = op->in.max_size;
2555         }
2556
2557         resume_idx_out = op->out.resume_idx;
2558
2559         hnd->status =
2560                 rpccli_samr_query_dispinfo( pipe_hnd, mem_ctx, op->in.dom_hnd,
2561                                             &resume_idx_out,
2562                                             op->in.info_class,
2563                                             &num_entries_out, max_entries_buf,
2564                                             max_size_buf, &ctr_out );
2565
2566         if ( !NT_STATUS_IS_OK( hnd->status )
2567              && !NT_STATUS_EQUAL( hnd->status, STATUS_MORE_ENTRIES ) ) {
2568                 /*be defensive, maybe they'll call again without zeroing the struct */
2569                 op->out.loop_count = 0;
2570                 op->out.resume_idx = 0;
2571                 return CAC_FAILURE;
2572         }
2573
2574         if ( NT_STATUS_IS_OK( hnd->status ) ) {
2575                 /*we want to quit once the function is called next. so it can be used in a loop */
2576                 op->out.done = True;
2577         }
2578
2579         op->out.resume_idx = resume_idx_out;
2580         op->out.num_entries = num_entries_out;
2581         op->out.ctr = ctr_out;
2582         op->out.loop_count++;
2583
2584         return CAC_SUCCESS;
2585 }
2586
2587 int cac_SamLookupDomain( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2588                          struct SamLookupDomain *op )
2589 {
2590         struct rpc_pipe_client *pipe_hnd = NULL;
2591
2592         DOM_SID *sid_out = NULL;
2593
2594         if ( !hnd )
2595                 return CAC_FAILURE;
2596
2597         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2598                 hnd->status = NT_STATUS_INVALID_HANDLE;
2599                 return CAC_FAILURE;
2600         }
2601
2602         if ( !op->in.sam || !op->in.name || !mem_ctx ) {
2603                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2604                 return CAC_FAILURE;
2605         }
2606
2607         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2608         if ( !pipe_hnd ) {
2609                 hnd->status = NT_STATUS_INVALID_HANDLE;
2610                 return CAC_FAILURE;
2611         }
2612
2613         sid_out = talloc( mem_ctx, DOM_SID );
2614         if ( !sid_out ) {
2615                 hnd->status = NT_STATUS_NO_MEMORY;
2616                 return CAC_FAILURE;
2617         }
2618
2619         hnd->status =
2620                 rpccli_samr_lookup_domain( pipe_hnd, mem_ctx, op->in.sam,
2621                                            op->in.name, sid_out );
2622
2623         if ( !NT_STATUS_IS_OK( hnd->status ) )
2624                 return CAC_FAILURE;
2625
2626         op->out.sid = sid_out;
2627
2628         return CAC_SUCCESS;
2629 }
2630
2631 int cac_SamGetSecurityObject( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2632                               struct SamGetSecurityObject *op )
2633 {
2634         struct rpc_pipe_client *pipe_hnd = NULL;
2635
2636         /*this number taken from rpcclient/cmd_samr.c, I think it is the only supported level */
2637         uint32 sec_info = DACL_SECURITY_INFORMATION;
2638
2639         SEC_DESC_BUF *sec_out = NULL;
2640
2641         if ( !hnd )
2642                 return CAC_FAILURE;
2643
2644         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2645                 hnd->status = NT_STATUS_INVALID_HANDLE;
2646                 return CAC_FAILURE;
2647         }
2648
2649         if ( !op->in.pol || !mem_ctx ) {
2650                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2651                 return CAC_FAILURE;
2652         }
2653
2654         pipe_hnd = cac_GetPipe( hnd, PI_SAMR );
2655         if ( !pipe_hnd ) {
2656                 hnd->status = NT_STATUS_INVALID_HANDLE;
2657                 return CAC_FAILURE;
2658         }
2659
2660         hnd->status =
2661                 rpccli_samr_query_sec_obj( pipe_hnd, mem_ctx, op->in.pol,
2662                                            sec_info, mem_ctx, &sec_out );
2663
2664         if ( !NT_STATUS_IS_OK( hnd->status ) )
2665                 return CAC_FAILURE;
2666
2667         op->out.sec = sec_out;
2668
2669         return CAC_SUCCESS;
2670 }
2671
2672 int cac_SamFlush( CacServerHandle * hnd, TALLOC_CTX * mem_ctx,
2673                   struct SamFlush *op )
2674 {
2675         struct SamOpenDomain od;
2676
2677         if ( !hnd )
2678                 return CAC_FAILURE;
2679
2680         if ( !hnd->_internal.ctx || !hnd->_internal.pipes[PI_SAMR] ) {
2681                 hnd->status = NT_STATUS_INVALID_HANDLE;
2682                 return CAC_FAILURE;
2683         }
2684
2685         if ( !op || !op->in.dom_hnd || !mem_ctx ) {
2686                 hnd->status = NT_STATUS_INVALID_PARAMETER;
2687                 return CAC_FAILURE;
2688         }
2689
2690         if ( !cac_SamClose( hnd, mem_ctx, op->in.dom_hnd ) )
2691                 return CAC_FAILURE;
2692
2693         ZERO_STRUCT( od );
2694         od.in.access =
2695                 ( op->in.access ) ? op->in.access : MAXIMUM_ALLOWED_ACCESS;
2696         od.in.sid = op->in.sid;
2697
2698         if ( !cac_SamOpenDomain( hnd, mem_ctx, &od ) )
2699                 return CAC_FAILURE;
2700
2701         /*this function does not use an output parameter to make it as convenient as possible to use */
2702         *op->in.dom_hnd = *od.out.dom_hnd;
2703
2704         TALLOC_FREE( od.out.dom_hnd );
2705
2706         return CAC_SUCCESS;
2707 }