2 Unix SMB/CIFS implementation.
3 Password and authentication handling
4 Copyright (C) Andrew Bartlett 2002
5 Copyright (C) Jelmer Vernooij 2002
6 Copyright (C) Stefan (metze) Metzmacher 2002
7 Copyright (C) Kai Krüger 2002
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 #define DBGC_CLASS DBGC_SAM
29 extern DOM_SID global_sid_Builtin
;
31 /** List of various built-in sam modules */
33 const struct sam_init_function_entry builtin_sam_init_functions
[] = {
34 { "plugin", sam_init_plugin
},
36 { "ads", sam_init_ads
},
38 { "skel", sam_init_skel
},
43 static NTSTATUS
sam_get_methods_by_sid(const SAM_CONTEXT
*context
, SAM_METHODS
**sam_method
, const DOM_SID
*domainsid
)
45 SAM_METHODS
*tmp_methods
;
47 DEBUG(5,("sam_get_methods_by_sid: %d\n", __LINE__
));
49 /* invalid sam_context specified */
50 SAM_ASSERT(context
&& context
->methods
);
52 tmp_methods
= context
->methods
;
55 if (sid_equal(domainsid
, &(tmp_methods
->domain_sid
)))
57 (*sam_method
) = tmp_methods
;
60 tmp_methods
= tmp_methods
->next
;
63 DEBUG(3,("sam_get_methods_by_sid: There is no backend specified for domain %s\n", sid_string_static(domainsid
)));
65 return NT_STATUS_NO_SUCH_DOMAIN
;
68 static NTSTATUS
sam_get_methods_by_name(const SAM_CONTEXT
*context
, SAM_METHODS
**sam_method
, const char *domainname
)
70 SAM_METHODS
*tmp_methods
;
72 DEBUG(5,("sam_get_methods_by_name: %d\n", __LINE__
));
74 /* invalid sam_context specified */
75 SAM_ASSERT(context
&& context
->methods
);
77 tmp_methods
= context
->methods
;
80 if (strequal(domainname
, tmp_methods
->domain_name
))
82 (*sam_method
) = tmp_methods
;
85 tmp_methods
= tmp_methods
->next
;
88 DEBUG(3,("sam_get_methods_by_sid: There is no backend specified for domain %s\n", domainname
));
90 return NT_STATUS_NO_SUCH_DOMAIN
;
93 static NTSTATUS
make_sam_methods(TALLOC_CTX
*mem_ctx
, SAM_METHODS
**methods
)
95 *methods
= talloc(mem_ctx
, sizeof(SAM_METHODS
));
98 return NT_STATUS_NO_MEMORY
;
101 ZERO_STRUCTP(*methods
);
106 /******************************************************************
107 Free and cleanup a sam context, any associated data and anything
108 that the attached modules might have associated.
109 *******************************************************************/
111 void free_sam_context(SAM_CONTEXT
**context
)
113 SAM_METHODS
*sam_selected
= (*context
)->methods
;
115 while (sam_selected
) {
116 if (sam_selected
->free_private_data
) {
117 sam_selected
->free_private_data(&(sam_selected
->private_data
));
119 sam_selected
= sam_selected
->next
;
122 talloc_destroy((*context
)->mem_ctx
);
126 /******************************************************************
127 Make a backend_entry from scratch
128 *******************************************************************/
130 static NTSTATUS
make_backend_entry(SAM_BACKEND_ENTRY
*backend_entry
, char *sam_backend_string
)
133 char *tmp_string
= sam_backend_string
;
135 DEBUG(5,("make_backend_entry: %d\n", __LINE__
));
137 SAM_ASSERT(sam_backend_string
&& backend_entry
);
139 backend_entry
->module_name
= sam_backend_string
;
141 DEBUG(5,("makeing backend_entry for %s\n", backend_entry
->module_name
));
143 if ((tmp
= strrchr(tmp_string
, '|')) != NULL
) {
144 DEBUGADD(20,("a domain name has been specified\n"));
146 backend_entry
->domain_name
= smb_xstrdup(tmp
+ 1);
147 tmp_string
= tmp
+ 1;
150 if ((tmp
= strchr(tmp_string
, ':')) != NULL
) {
151 DEBUG(20,("options for the backend have been specified\n"));
153 backend_entry
->module_params
= smb_xstrdup(tmp
+ 1);
154 tmp_string
= tmp
+ 1;
157 if (backend_entry
->domain_name
== NULL
) {
158 DEBUG(10,("make_backend_entry: no domain was specified for sam module %s. Using default domain %s\n",
159 backend_entry
->module_name
, lp_workgroup()));
160 backend_entry
->domain_name
= smb_xstrdup(lp_workgroup());
163 if ((backend_entry
->domain_sid
= (DOM_SID
*)malloc(sizeof(DOM_SID
))) == NULL
) {
164 DEBUG(0,("make_backend_entry: failed to malloc domain_sid\n"));
165 return NT_STATUS_NO_MEMORY
;
168 DEBUG(10,("looking up sid for domain %s\n", backend_entry
->domain_name
));
170 if (!secrets_fetch_domain_sid(backend_entry
->domain_name
, backend_entry
->domain_sid
)) {
171 DEBUG(2,("make_backend_entry: There is no SID stored for domain %s. Creating a new one.\n",
172 backend_entry
->domain_name
));
173 DEBUG(0, ("FIXME in %s:%d\n", __FILE__
, __LINE__
));
174 ZERO_STRUCTP(backend_entry
->domain_sid
);
177 DEBUG(5,("make_backend_entry: module name: %s, module parameters: %s, domain name: %s, domain sid: %s\n",
178 backend_entry
->module_name
, backend_entry
->module_params
, backend_entry
->domain_name
, sid_string_static(backend_entry
->domain_sid
)));
183 /******************************************************************
184 create sam_methods struct based on sam_backend_entry
185 *****************************************************************/
187 static NTSTATUS
make_sam_methods_backend_entry(SAM_CONTEXT
*context
, SAM_METHODS
**methods_ptr
, SAM_BACKEND_ENTRY
*backend_entry
)
189 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
190 SAM_METHODS
*methods
;
193 DEBUG(5,("make_sam_methods_backend_entry: %d\n", __LINE__
));
195 if (!NT_STATUS_IS_OK(nt_status
= make_sam_methods(context
->mem_ctx
, methods_ptr
))) {
199 methods
= *methods_ptr
;
200 methods
->backendname
= talloc_strdup(context
->mem_ctx
, backend_entry
->module_name
);
201 methods
->domain_name
= talloc_strdup(context
->mem_ctx
, backend_entry
->domain_name
);
202 sid_copy(&methods
->domain_sid
, backend_entry
->domain_sid
);
203 methods
->parent
= context
;
205 DEBUG(5,("Attempting to find sam backend %s\n", backend_entry
->module_name
));
206 for (i
= 0; builtin_sam_init_functions
[i
].module_name
; i
++)
208 if (strequal(builtin_sam_init_functions
[i
].module_name
, backend_entry
->module_name
))
210 DEBUG(5,("Found sam backend %s (at pos %d)\n", backend_entry
->module_name
, i
));
211 DEBUGADD(5,("initialising it with options=%s for domain %s\n", backend_entry
->module_params
, sid_string_static(backend_entry
->domain_sid
)));
212 nt_status
= builtin_sam_init_functions
[i
].init(methods
, backend_entry
->module_params
);
213 if (NT_STATUS_IS_OK(nt_status
)) {
214 DEBUG(5,("sam backend %s has a valid init\n", backend_entry
->module_name
));
216 DEBUG(2,("sam backend %s did not correctly init (error was %s)\n",
217 backend_entry
->module_name
, nt_errstr(nt_status
)));
223 DEBUG(2,("could not find backend %s\n", backend_entry
->module_name
));
225 return NT_STATUS_INVALID_PARAMETER
;
228 static NTSTATUS
sam_context_check_default_backends(SAM_CONTEXT
*context
)
230 SAM_BACKEND_ENTRY entry
;
231 DOM_SID
*global_sam_sid
= get_global_sam_sid(); /* lp_workgroup doesn't play nicely with multiple domains */
232 SAM_METHODS
*methods
, *tmpmethods
;
235 DEBUG(5,("sam_context_check_default_backends: %d\n", __LINE__
));
237 /* Make sure domain lp_workgroup() is available */
239 ntstatus
= sam_get_methods_by_sid(context
, &methods
, &global_sid_Builtin
);
241 if (NT_STATUS_EQUAL(ntstatus
, NT_STATUS_NO_SUCH_DOMAIN
)) {
242 DEBUG(4,("There was no backend specified for domain %s(%s); using %s\n",
243 lp_workgroup(), sid_string_static(global_sam_sid
), SAM_DEFAULT_BACKEND
));
245 SAM_ASSERT(global_sam_sid
);
247 entry
.module_name
= SAM_DEFAULT_BACKEND
;
248 entry
.module_params
= NULL
;
249 entry
.domain_name
= lp_workgroup();
250 entry
.domain_sid
= (DOM_SID
*)malloc(sizeof(DOM_SID
));
251 sid_copy(entry
.domain_sid
, global_sam_sid
);
253 if (!NT_STATUS_IS_OK(ntstatus
= make_sam_methods_backend_entry(context
, &methods
, &entry
))) {
254 DEBUG(4,("make_sam_methods_backend_entry failed\n"));
258 DLIST_ADD_END(context
->methods
, methods
, tmpmethods
);
260 } else if (!NT_STATUS_IS_OK(ntstatus
)) {
261 DEBUG(2, ("sam_get_methods_by_sid failed for %s\n", lp_workgroup()));
265 /* Make sure the BUILTIN domain is available */
267 ntstatus
= sam_get_methods_by_sid(context
, &methods
, global_sam_sid
);
269 if (NT_STATUS_EQUAL(ntstatus
, NT_STATUS_NO_SUCH_DOMAIN
)) {
270 DEBUG(4,("There was no backend specified for domain BUILTIN; using %s\n",
271 SAM_DEFAULT_BACKEND
));
272 entry
.module_name
= SAM_DEFAULT_BACKEND
;
273 entry
.module_params
= NULL
;
274 entry
.domain_name
= "BUILTIN";
275 entry
.domain_sid
= (DOM_SID
*)malloc(sizeof(DOM_SID
));
276 sid_copy(entry
.domain_sid
, &global_sid_Builtin
);
278 if (!NT_STATUS_IS_OK(ntstatus
= make_sam_methods_backend_entry(context
, &methods
, &entry
))) {
279 DEBUG(4,("make_sam_methods_backend_entry failed\n"));
283 DLIST_ADD_END(context
->methods
, methods
, tmpmethods
);
284 } else if (!NT_STATUS_IS_OK(ntstatus
)) {
285 DEBUG(2, ("sam_get_methods_by_sid failed for BUILTIN\n"));
292 static NTSTATUS
check_duplicate_backend_entries(SAM_BACKEND_ENTRY
**backend_entries
, int *nBackends
)
296 DEBUG(5,("check_duplicate_backend_entries: %d\n", __LINE__
));
298 for (i
= 0; i
< *nBackends
; i
++) {
299 for (j
= i
+ 1; j
< *nBackends
; j
++) {
300 if (sid_equal((*backend_entries
)[i
].domain_sid
, (*backend_entries
)[j
].domain_sid
)) {
301 DEBUG(0,("two backend modules claim the same domain %s\n",
302 sid_string_static((*backend_entries
)[j
].domain_sid
)));
303 return NT_STATUS_INVALID_PARAMETER
;
311 NTSTATUS
make_sam_context_list(SAM_CONTEXT
**context
, char **sam_backends_param
)
314 SAM_METHODS
*curmethods
, *tmpmethods
;
316 SAM_BACKEND_ENTRY
*backends
= NULL
;
317 NTSTATUS nt_status
= NT_STATUS_UNSUCCESSFUL
;
319 DEBUG(5,("make_sam_context_from_conf: %d\n", __LINE__
));
321 if (!sam_backends_param
) {
322 DEBUG(1, ("no SAM backeds specified!\n"));
323 return NT_STATUS_INVALID_PARAMETER
;
326 if (!NT_STATUS_IS_OK(nt_status
= make_sam_context(context
))) {
327 DEBUG(4,("make_sam_context failed\n"));
331 while (sam_backends_param
[nBackends
])
334 DEBUG(6,("There are %d domains listed with their backends\n", nBackends
));
336 if ((backends
= (SAM_BACKEND_ENTRY
*)malloc(sizeof(*backends
)*nBackends
)) == NULL
) {
337 DEBUG(0,("make_sam_context_list: failed to allocate backends\n"));
338 return NT_STATUS_NO_MEMORY
;
341 memset(backends
, '\0', sizeof(*backends
)*nBackends
);
343 for (i
= 0; i
< nBackends
; i
++) {
344 DEBUG(8,("processing %s\n",sam_backends_param
[i
]));
345 if (!NT_STATUS_IS_OK(nt_status
= make_backend_entry(&backends
[i
], sam_backends_param
[i
]))) {
346 DEBUG(4,("make_backend_entry failed\n"));
347 for (j
= 0; j
< nBackends
; j
++) SAFE_FREE(backends
[j
].domain_sid
);
349 free_sam_context(context
);
354 if (!NT_STATUS_IS_OK(nt_status
= check_duplicate_backend_entries(&backends
, &nBackends
))) {
355 DEBUG(4,("check_duplicate_backend_entries failed\n"));
356 for (j
= 0; j
< nBackends
; j
++) SAFE_FREE(backends
[j
].domain_sid
);
358 free_sam_context(context
);
362 for (i
= 0; i
< nBackends
; i
++) {
363 if (!NT_STATUS_IS_OK(nt_status
= make_sam_methods_backend_entry(*context
, &curmethods
, &backends
[i
]))) {
364 DEBUG(4,("make_sam_methods_backend_entry failed\n"));
365 for (j
= 0; j
< nBackends
; j
++) SAFE_FREE(backends
[j
].domain_sid
);
367 free_sam_context(context
);
370 DLIST_ADD_END((*context
)->methods
, curmethods
, tmpmethods
);
373 for (i
= 0; i
< nBackends
; i
++) SAFE_FREE(backends
[i
].domain_sid
);
379 /******************************************************************
380 Make a sam_context from scratch.
381 *******************************************************************/
383 NTSTATUS
make_sam_context(SAM_CONTEXT
**context
)
387 mem_ctx
= talloc_init("sam_context internal allocation context");
390 DEBUG(0, ("make_sam_context: talloc init failed!\n"));
391 return NT_STATUS_NO_MEMORY
;
394 *context
= talloc(mem_ctx
, sizeof(**context
));
396 DEBUG(0, ("make_sam_context: talloc failed!\n"));
397 return NT_STATUS_NO_MEMORY
;
400 ZERO_STRUCTP(*context
);
402 (*context
)->mem_ctx
= mem_ctx
;
404 (*context
)->free_fn
= free_sam_context
;
409 /******************************************************************
410 Return an already initialised sam_context, to facilitate backward
411 compatibility (see functions below).
412 *******************************************************************/
414 static struct sam_context
*sam_get_static_context(BOOL reload
)
416 static SAM_CONTEXT
*sam_context
= NULL
;
418 if ((sam_context
) && (reload
)) {
419 sam_context
->free_fn(&sam_context
);
424 if (!NT_STATUS_IS_OK(make_sam_context_list(&sam_context
, lp_sam_backend()))) {
425 DEBUG(4,("make_sam_context_list failed\n"));
429 /* Make sure the required domains (default domain, builtin) are available */
430 if (!NT_STATUS_IS_OK(sam_context_check_default_backends(sam_context
))) {
431 DEBUG(4,("sam_context_check_default_backends failed\n"));
439 /***************************************************************
440 Initialize the static context (at smbd startup etc).
442 If uninitialised, context will auto-init on first use.
443 ***************************************************************/
445 BOOL
initialize_sam(BOOL reload
)
447 return (sam_get_static_context(reload
) != NULL
);
451 /**************************************************************
452 External API. This is what the rest of the world calls...
453 ***************************************************************/
455 /******************************************************************
456 sam_* functions are used to link the external SAM interface
457 with the internal backends. These functions lookup the appropriate
458 backends for the domain and pass on to the function in sam_methods
459 in the selected backend
461 When the context parmater is NULL, the default is used.
462 *******************************************************************/
464 #define SAM_SETUP_CONTEXT if (!context) \
465 context = sam_get_static_context(False);\
467 return NT_STATUS_UNSUCCESSFUL; \
472 NTSTATUS
sam_get_sec_desc(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const DOM_SID
*sid
, SEC_DESC
**sd
)
474 SAM_METHODS
*tmp_methods
;
477 DEBUG(5,("sam_get_sec_desc: %d\n", __LINE__
));
481 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, sid
))) {
482 DEBUG(4,("sam_get_methods_by_sid failed\n"));
486 if (!tmp_methods
->sam_get_sec_desc
) {
487 DEBUG(3, ("sam_get_sec_desc: sam_methods of the domain did not specify sam_get_sec_desc\n"));
488 return NT_STATUS_NOT_IMPLEMENTED
;
491 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_sec_desc(tmp_methods
, access_token
, sid
, sd
))) {
492 DEBUG(4,("sam_get_sec_desc for %s in backend %s failed\n", sid_string_static(sid
), tmp_methods
->backendname
));
499 NTSTATUS
sam_set_sec_desc(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const DOM_SID
*sid
, const SEC_DESC
*sd
)
501 SAM_METHODS
*tmp_methods
;
504 DEBUG(5,("sam_set_sec_desc: %d\n", __LINE__
));
508 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, sid
))) {
509 DEBUG(4,("sam_get_methods_by_sid failed\n"));
513 if (!tmp_methods
->sam_set_sec_desc
) {
514 DEBUG(3, ("sam_set_sec_desc: sam_methods of the domain did not specify sam_set_sec_desc\n"));
515 return NT_STATUS_NOT_IMPLEMENTED
;
518 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_set_sec_desc(tmp_methods
, access_token
, sid
, sd
))) {
519 DEBUG(4,("sam_set_sec_desc for %s in backend %s failed\n", sid_string_static(sid
), tmp_methods
->backendname
));
527 NTSTATUS
sam_lookup_name(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const char *domain
, const char *name
, DOM_SID
*sid
, uint32
*type
)
529 SAM_METHODS
*tmp_methods
;
532 DEBUG(5,("sam_lookup_name: %d\n", __LINE__
));
536 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_name(context
, &tmp_methods
, domain
))) {
537 DEBUG(4,("sam_get_methods_by_name failed\n"));
541 if (!tmp_methods
->sam_lookup_name
) {
542 DEBUG(3, ("sam_lookup_name: sam_methods of the domain did not specify sam_lookup_name\n"));
543 return NT_STATUS_NOT_IMPLEMENTED
;
546 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_lookup_name(tmp_methods
, access_token
, name
, sid
, type
))) {
547 DEBUG(4,("sam_lookup_name for %s\\%s in backend %s failed\n",
548 tmp_methods
->domain_name
, name
, tmp_methods
->backendname
));
555 NTSTATUS
sam_lookup_sid(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, TALLOC_CTX
*mem_ctx
, const DOM_SID
*sid
, char **name
, uint32
*type
)
557 SAM_METHODS
*tmp_methods
;
562 DEBUG(5,("sam_lookup_sid: %d\n", __LINE__
));
566 sid_copy(&domainsid
, sid
);
567 if (!sid_split_rid(&domainsid
, &rid
)) {
568 DEBUG(3,("sam_lookup_sid: failed to split the sid\n"));
569 return NT_STATUS_INVALID_SID
;
572 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, &domainsid
))) {
573 DEBUG(4,("sam_get_methods_by_sid failed\n"));
577 if (!tmp_methods
->sam_lookup_sid
) {
578 DEBUG(3, ("sam_lookup_sid: sam_methods of the domain did not specify sam_lookup_sid\n"));
579 return NT_STATUS_NOT_IMPLEMENTED
;
582 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_lookup_sid(tmp_methods
, access_token
, mem_ctx
, sid
, name
, type
))) {
583 DEBUG(4,("sam_lookup_name for %s in backend %s failed\n",
584 sid_string_static(sid
), tmp_methods
->backendname
));
592 NTSTATUS
sam_update_domain(const SAM_CONTEXT
*context
, const SAM_DOMAIN_HANDLE
*domain
)
594 const SAM_METHODS
*tmp_methods
;
597 DEBUG(5,("sam_update_domain: %d\n", __LINE__
));
601 /* invalid domain specified */
602 SAM_ASSERT(domain
&& domain
->current_sam_methods
);
604 tmp_methods
= domain
->current_sam_methods
;
606 if (!tmp_methods
->sam_update_domain
) {
607 DEBUG(3, ("sam_update_domain: sam_methods of the domain did not specify sam_update_domain\n"));
608 return NT_STATUS_NOT_IMPLEMENTED
;
611 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_update_domain(tmp_methods
, domain
))){
612 DEBUG(4,("sam_update_domain in backend %s failed\n",
613 tmp_methods
->backendname
));
620 NTSTATUS
sam_enum_domains(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, int32
*domain_count
, DOM_SID
**domains
, char ***domain_names
)
622 SAM_METHODS
*tmp_methods
;
630 DEBUG(5,("sam_enum_domains: %d\n", __LINE__
));
634 /* invalid parmaters specified */
635 SAM_ASSERT(domain_count
&& domains
&& domain_names
);
637 if (!NT_STATUS_IS_OK(nt_status
= samr_make_sam_obj_sd(context
->mem_ctx
, &sd
, &sd_size
))) {
638 DEBUG(4,("samr_make_sam_obj_sd failed\n"));
642 if (!se_access_check(sd
, access_token
, SA_RIGHT_SAM_ENUM_DOMAINS
, &acc_granted
, &nt_status
)) {
643 DEBUG(3,("sam_enum_domains: ACCESS DENIED\n"));
647 tmp_methods
= context
->methods
;
650 while (tmp_methods
) {
652 tmp_methods
= tmp_methods
->next
;
655 DEBUG(6,("sam_enum_domains: enumerating %d domains\n", (*domain_count
)));
657 tmp_methods
= context
->methods
;
659 if (((*domains
) = malloc( sizeof(DOM_SID
) * (*domain_count
))) == NULL
) {
660 DEBUG(0,("sam_enum_domains: Out of memory allocating domain SID list\n"));
661 return NT_STATUS_NO_MEMORY
;
664 if (((*domain_names
) = malloc( sizeof(char*) * (*domain_count
))) == NULL
) {
665 DEBUG(0,("sam_enum_domains: Out of memory allocating domain name list\n"));
666 SAFE_FREE((*domains
));
667 return NT_STATUS_NO_MEMORY
;
670 while (tmp_methods
) {
671 DEBUGADD(7,(" [%d] %s: %s\n", i
, tmp_methods
->domain_name
, sid_string_static(&tmp_methods
->domain_sid
)));
672 sid_copy(domains
[i
],&tmp_methods
->domain_sid
);
673 *domain_names
[i
] = smb_xstrdup(tmp_methods
->domain_name
);
675 tmp_methods
= tmp_methods
->next
;
681 NTSTATUS
sam_lookup_domain(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const char *domain
, DOM_SID
**domainsid
)
683 SAM_METHODS
*tmp_methods
;
690 DEBUG(5,("sam_lookup_domain: %d\n", __LINE__
));
694 /* invalid paramters */
695 SAM_ASSERT(access_token
&& domain
&& domainsid
);
697 if (!NT_STATUS_IS_OK(nt_status
= samr_make_sam_obj_sd(context
->mem_ctx
, &sd
, &sd_size
))) {
698 DEBUG(4,("samr_make_sam_obj_sd failed\n"));
702 if (!se_access_check(sd
, access_token
, SA_RIGHT_SAM_OPEN_DOMAIN
, &acc_granted
, &nt_status
)) {
703 DEBUG(3,("sam_lookup_domain: ACCESS DENIED\n"));
707 tmp_methods
= context
->methods
;
709 while (tmp_methods
) {
710 if (strcmp(domain
, tmp_methods
->domain_name
) == 0) {
711 (*domainsid
) = (DOM_SID
*)malloc(sizeof(DOM_SID
));
712 sid_copy((*domainsid
), &tmp_methods
->domain_sid
);
715 tmp_methods
= tmp_methods
->next
;
718 return NT_STATUS_NO_SUCH_DOMAIN
;
722 NTSTATUS
sam_get_domain_by_sid(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const DOM_SID
*domainsid
, SAM_DOMAIN_HANDLE
**domain
)
724 SAM_METHODS
*tmp_methods
;
727 DEBUG(5,("sam_get_domain_by_sid: %d\n", __LINE__
));
731 SAM_ASSERT(access_token
&& domainsid
&& domain
);
733 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, domainsid
))) {
734 DEBUG(4,("sam_get_methods_by_sid failed\n"));
738 if (!tmp_methods
->sam_get_domain_handle
) {
739 DEBUG(3, ("sam_get_domain_by_sid: sam_methods of the domain did not specify sam_get_domain_handle\n"));
740 return NT_STATUS_NOT_IMPLEMENTED
;
743 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_domain_handle(tmp_methods
, access_token
, access_desired
, domain
))) {
744 DEBUG(4,("sam_get_domain_handle for %s in backend %s failed\n",
745 sid_string_static(domainsid
), tmp_methods
->backendname
));
752 NTSTATUS
sam_create_account(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const DOM_SID
*domainsid
, const char *account_name
, uint16 acct_ctrl
, SAM_ACCOUNT_HANDLE
**account
)
754 SAM_METHODS
*tmp_methods
;
757 DEBUG(5,("sam_create_account: %d\n", __LINE__
));
761 /* invalid parmaters */
762 SAM_ASSERT(access_token
&& domainsid
&& account_name
&& account
);
764 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, domainsid
))) {
765 DEBUG(4,("sam_get_methods_by_sid failed\n"));
769 if (!tmp_methods
->sam_create_account
) {
770 DEBUG(3, ("sam_create_account: sam_methods of the domain did not specify sam_create_account\n"));
771 return NT_STATUS_NOT_IMPLEMENTED
;
774 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_create_account(tmp_methods
, access_token
, access_desired
, account_name
, acct_ctrl
, account
))) {
775 DEBUG(4,("sam_create_account in backend %s failed\n",
776 tmp_methods
->backendname
));
783 NTSTATUS
sam_add_account(const SAM_CONTEXT
*context
, const SAM_ACCOUNT_HANDLE
*account
)
786 const DOM_SID
*accountsid
;
787 SAM_METHODS
*tmp_methods
;
791 DEBUG(5,("sam_add_account: %d\n", __LINE__
));
795 /* invalid parmaters */
798 if (!NT_STATUS_IS_OK(nt_status
= sam_get_account_sid(account
, &accountsid
))) {
799 DEBUG(0,("Can't get account SID\n"));
803 sid_copy(&domainsid
, accountsid
);
804 if (!sid_split_rid(&domainsid
, &rid
)) {
805 DEBUG(3,("sam_get_account_by_sid: failed to split the sid\n"));
806 return NT_STATUS_INVALID_SID
;
809 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, &domainsid
))) {
810 DEBUG(4,("sam_get_methods_by_sid failed\n"));
814 if (!tmp_methods
->sam_add_account
) {
815 DEBUG(3, ("sam_add_account: sam_methods of the domain did not specify sam_add_account\n"));
816 return NT_STATUS_NOT_IMPLEMENTED
;
819 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_add_account(tmp_methods
, account
))){
820 DEBUG(4,("sam_add_account in backend %s failed\n",
821 tmp_methods
->backendname
));
828 NTSTATUS
sam_update_account(const SAM_CONTEXT
*context
, const SAM_ACCOUNT_HANDLE
*account
)
830 const SAM_METHODS
*tmp_methods
;
833 DEBUG(5,("sam_update_account: %d\n", __LINE__
));
837 /* invalid account specified */
838 SAM_ASSERT(account
&& account
->current_sam_methods
);
840 tmp_methods
= account
->current_sam_methods
;
842 if (!tmp_methods
->sam_update_account
) {
843 DEBUG(3, ("sam_update_account: sam_methods of the domain did not specify sam_update_account\n"));
844 return NT_STATUS_NOT_IMPLEMENTED
;
847 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_update_account(tmp_methods
, account
))){
848 DEBUG(4,("sam_update_account in backend %s failed\n",
849 tmp_methods
->backendname
));
856 NTSTATUS
sam_delete_account(const SAM_CONTEXT
*context
, const SAM_ACCOUNT_HANDLE
*account
)
858 const SAM_METHODS
*tmp_methods
;
861 DEBUG(5,("sam_delete_account: %d\n", __LINE__
));
865 /* invalid account specified */
866 SAM_ASSERT(account
&& account
->current_sam_methods
);
868 tmp_methods
= account
->current_sam_methods
;
870 if (!tmp_methods
->sam_delete_account
) {
871 DEBUG(3, ("sam_delete_account: sam_methods of the domain did not specify sam_delete_account\n"));
872 return NT_STATUS_NOT_IMPLEMENTED
;
875 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_delete_account(tmp_methods
, account
))){
876 DEBUG(4,("sam_delete_account in backend %s failed\n",
877 tmp_methods
->backendname
));
884 NTSTATUS
sam_enum_accounts(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const DOM_SID
*domainsid
, uint16 acct_ctrl
, int32
*account_count
, SAM_ACCOUNT_ENUM
**accounts
)
886 SAM_METHODS
*tmp_methods
;
889 DEBUG(5,("sam_enum_accounts: %d\n", __LINE__
));
893 SAM_ASSERT(access_token
&& domainsid
&& account_count
&& accounts
);
895 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, domainsid
))) {
896 DEBUG(4,("sam_get_methods_by_sid failed\n"));
900 if (!tmp_methods
->sam_enum_accounts
) {
901 DEBUG(3, ("sam_enum_accounts: sam_methods of the domain did not specify sam_enum_accounts\n"));
902 return NT_STATUS_NOT_IMPLEMENTED
;
905 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_enum_accounts(tmp_methods
, access_token
, acct_ctrl
, account_count
, accounts
))) {
906 DEBUG(4,("sam_enum_accounts for domain %s in backend %s failed\n",
907 tmp_methods
->domain_name
, tmp_methods
->backendname
));
915 NTSTATUS
sam_get_account_by_sid(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const DOM_SID
*accountsid
, SAM_ACCOUNT_HANDLE
**account
)
917 SAM_METHODS
*tmp_methods
;
922 DEBUG(5,("sam_get_account_by_sid: %d\n", __LINE__
));
926 SAM_ASSERT(access_token
&& accountsid
&& account
);
928 sid_copy(&domainsid
, accountsid
);
929 if (!sid_split_rid(&domainsid
, &rid
)) {
930 DEBUG(3,("sam_get_account_by_sid: failed to split the sid\n"));
931 return NT_STATUS_INVALID_SID
;
935 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, &domainsid
))) {
936 DEBUG(4,("sam_get_methods_by_sid failed\n"));
940 if (!tmp_methods
->sam_get_account_by_sid
) {
941 DEBUG(3, ("sam_get_account_by_sid: sam_methods of the domain did not specify sam_get_account_by_sid\n"));
942 return NT_STATUS_NOT_IMPLEMENTED
;
945 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_account_by_sid(tmp_methods
, access_token
, access_desired
, accountsid
, account
))) {
946 DEBUG(4,("sam_get_account_by_sid for %s in backend %s failed\n",
947 sid_string_static(accountsid
), tmp_methods
->backendname
));
954 NTSTATUS
sam_get_account_by_name(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const char *domain
, const char *name
, SAM_ACCOUNT_HANDLE
**account
)
956 SAM_METHODS
*tmp_methods
;
959 DEBUG(5,("sam_get_account_by_name: %d\n", __LINE__
));
963 SAM_ASSERT(access_token
&& domain
&& name
&& account
);
965 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_name(context
, &tmp_methods
, domain
))) {
966 DEBUG(4,("sam_get_methods_by_name failed\n"));
970 if (!tmp_methods
->sam_get_account_by_name
) {
971 DEBUG(3, ("sam_get_account_by_name: sam_methods of the domain did not specify sam_get_account_by_name\n"));
972 return NT_STATUS_NOT_IMPLEMENTED
;
975 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_account_by_name(tmp_methods
, access_token
, access_desired
, name
, account
))) {
976 DEBUG(4,("sam_get_account_by_name for %s\\%s in backend %s failed\n",
977 domain
, name
, tmp_methods
->backendname
));
984 NTSTATUS
sam_create_group(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const DOM_SID
*domainsid
, const char *group_name
, uint16 group_ctrl
, SAM_GROUP_HANDLE
**group
)
986 SAM_METHODS
*tmp_methods
;
989 DEBUG(5,("sam_create_group: %d\n", __LINE__
));
993 SAM_ASSERT(access_token
&& domainsid
&& group_name
&& group
);
995 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, domainsid
))) {
996 DEBUG(4,("sam_get_methods_by_sid failed\n"));
1000 if (!tmp_methods
->sam_create_group
) {
1001 DEBUG(3, ("sam_create_group: sam_methods of the domain did not specify sam_create_group\n"));
1002 return NT_STATUS_UNSUCCESSFUL
;
1005 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_create_group(tmp_methods
, access_token
, access_desired
, group_name
, group_ctrl
, group
))) {
1006 DEBUG(4,("sam_create_group in backend %s failed\n",
1007 tmp_methods
->backendname
));
1011 return NT_STATUS_OK
;
1014 NTSTATUS
sam_add_group(const SAM_CONTEXT
*context
, const SAM_GROUP_HANDLE
*group
)
1017 const DOM_SID
*groupsid
;
1018 SAM_METHODS
*tmp_methods
;
1022 DEBUG(5,("sam_add_group: %d\n", __LINE__
));
1028 if (!NT_STATUS_IS_OK(nt_status
= sam_get_group_sid(group
, &groupsid
))) {
1029 DEBUG(0,("Can't get group SID\n"));
1033 sid_copy(&domainsid
, groupsid
);
1034 if (!sid_split_rid(&domainsid
, &rid
)) {
1035 DEBUG(3,("sam_get_group_by_sid: failed to split the sid\n"));
1036 return NT_STATUS_INVALID_SID
;
1039 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, &domainsid
))) {
1040 DEBUG(4,("sam_get_methods_by_sid failed\n"));
1044 if (!tmp_methods
->sam_add_group
) {
1045 DEBUG(3, ("sam_add_group: sam_methods of the domain did not specify sam_add_group\n"));
1046 return NT_STATUS_NOT_IMPLEMENTED
;
1049 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_add_group(tmp_methods
, group
))){
1050 DEBUG(4,("sam_add_group in backend %s failed\n",
1051 tmp_methods
->backendname
));
1055 return NT_STATUS_OK
;
1058 NTSTATUS
sam_update_group(const SAM_CONTEXT
*context
, const SAM_GROUP_HANDLE
*group
)
1060 const SAM_METHODS
*tmp_methods
;
1063 DEBUG(5,("sam_update_group: %d\n", __LINE__
));
1067 /* invalid group specified */
1068 SAM_ASSERT(group
&& group
->current_sam_methods
);
1070 tmp_methods
= group
->current_sam_methods
;
1072 if (!tmp_methods
->sam_update_group
) {
1073 DEBUG(3, ("sam_update_group: sam_methods of the domain did not specify sam_update_group\n"));
1074 return NT_STATUS_NOT_IMPLEMENTED
;
1077 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_update_group(tmp_methods
, group
))){
1078 DEBUG(4,("sam_update_group in backend %s failed\n",
1079 tmp_methods
->backendname
));
1083 return NT_STATUS_OK
;
1086 NTSTATUS
sam_delete_group(const SAM_CONTEXT
*context
, const SAM_GROUP_HANDLE
*group
)
1088 const SAM_METHODS
*tmp_methods
;
1091 DEBUG(5,("sam_delete_group: %d\n", __LINE__
));
1095 /* invalid group specified */
1096 SAM_ASSERT(group
&& group
->current_sam_methods
);
1098 tmp_methods
= group
->current_sam_methods
;
1100 if (!tmp_methods
->sam_delete_group
) {
1101 DEBUG(3, ("sam_delete_group: sam_methods of the domain did not specify sam_delete_group\n"));
1102 return NT_STATUS_NOT_IMPLEMENTED
;
1105 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_delete_group(tmp_methods
, group
))){
1106 DEBUG(4,("sam_delete_group in backend %s failed\n",
1107 tmp_methods
->backendname
));
1111 return NT_STATUS_OK
;
1114 NTSTATUS
sam_enum_groups(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const DOM_SID
*domainsid
, uint16 group_ctrl
, uint32
*groups_count
, SAM_GROUP_ENUM
**groups
)
1116 SAM_METHODS
*tmp_methods
;
1119 DEBUG(5,("sam_enum_groups: %d\n", __LINE__
));
1123 SAM_ASSERT(access_token
&& domainsid
&& groups_count
&& groups
);
1125 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, domainsid
))) {
1126 DEBUG(4,("sam_get_methods_by_sid failed\n"));
1130 if (!tmp_methods
->sam_enum_accounts
) {
1131 DEBUG(3, ("sam_enum_groups: sam_methods of the domain did not specify sam_enum_groups\n"));
1132 return NT_STATUS_NOT_IMPLEMENTED
;
1135 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_enum_groups(tmp_methods
, access_token
, group_ctrl
, groups_count
, groups
))) {
1136 DEBUG(4,("sam_enum_groups for domain %s in backend %s failed\n",
1137 tmp_methods
->domain_name
, tmp_methods
->backendname
));
1141 return NT_STATUS_OK
;
1144 NTSTATUS
sam_get_group_by_sid(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const DOM_SID
*groupsid
, SAM_GROUP_HANDLE
**group
)
1146 SAM_METHODS
*tmp_methods
;
1151 DEBUG(5,("sam_get_group_by_sid: %d\n", __LINE__
));
1155 SAM_ASSERT(access_token
&& groupsid
&& group
);
1157 sid_copy(&domainsid
, groupsid
);
1158 if (!sid_split_rid(&domainsid
, &rid
)) {
1159 DEBUG(3,("sam_get_group_by_sid: failed to split the sid\n"));
1160 return NT_STATUS_INVALID_SID
;
1164 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_sid(context
, &tmp_methods
, &domainsid
))) {
1165 DEBUG(4,("sam_get_methods_by_sid failed\n"));
1169 if (!tmp_methods
->sam_get_group_by_sid
) {
1170 DEBUG(3, ("sam_get_group_by_sid: sam_methods of the domain did not specify sam_get_group_by_sid\n"));
1171 return NT_STATUS_NOT_IMPLEMENTED
;
1174 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_group_by_sid(tmp_methods
, access_token
, access_desired
, groupsid
, group
))) {
1175 DEBUG(4,("sam_get_group_by_sid for %s in backend %s failed\n",
1176 sid_string_static(groupsid
), tmp_methods
->backendname
));
1180 return NT_STATUS_OK
;
1183 NTSTATUS
sam_get_group_by_name(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, uint32 access_desired
, const char *domain
, const char *name
, SAM_GROUP_HANDLE
**group
)
1185 SAM_METHODS
*tmp_methods
;
1188 DEBUG(5,("sam_get_group_by_name: %d\n", __LINE__
));
1192 SAM_ASSERT(access_token
&& domain
&& name
&& group
);
1194 if (!NT_STATUS_IS_OK(nt_status
= sam_get_methods_by_name(context
, &tmp_methods
, domain
))) {
1195 DEBUG(4,("sam_get_methods_by_name failed\n"));
1199 if (!tmp_methods
->sam_get_group_by_name
) {
1200 DEBUG(3, ("sam_get_group_by_name: sam_methods of the domain did not specify sam_get_group_by_name\n"));
1201 return NT_STATUS_NOT_IMPLEMENTED
;
1204 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_group_by_name(tmp_methods
, access_token
, access_desired
, name
, group
))) {
1205 DEBUG(4,("sam_get_group_by_name for %s\\%s in backend %s failed\n",
1206 domain
, name
, tmp_methods
->backendname
));
1210 return NT_STATUS_OK
;
1213 NTSTATUS
sam_add_member_to_group(const SAM_CONTEXT
*context
, const SAM_GROUP_HANDLE
*group
, const SAM_GROUP_MEMBER
*member
)
1215 const SAM_METHODS
*tmp_methods
;
1220 /* invalid group or member specified */
1221 SAM_ASSERT(group
&& group
->current_sam_methods
&& member
);
1223 tmp_methods
= group
->current_sam_methods
;
1225 if (!tmp_methods
->sam_add_member_to_group
) {
1226 DEBUG(3, ("sam_add_member_to_group: sam_methods of the domain did not specify sam_add_member_to_group\n"));
1227 return NT_STATUS_NOT_IMPLEMENTED
;
1230 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_add_member_to_group(tmp_methods
, group
, member
))) {
1231 DEBUG(4,("sam_add_member_to_group in backend %s failed\n", tmp_methods
->backendname
));
1235 return NT_STATUS_OK
;
1239 NTSTATUS
sam_delete_member_from_group(const SAM_CONTEXT
*context
, const SAM_GROUP_HANDLE
*group
, const SAM_GROUP_MEMBER
*member
)
1241 const SAM_METHODS
*tmp_methods
;
1246 /* invalid group or member specified */
1247 SAM_ASSERT(group
&& group
->current_sam_methods
&& member
);
1249 tmp_methods
= group
->current_sam_methods
;
1251 if (!tmp_methods
->sam_delete_member_from_group
) {
1252 DEBUG(3, ("sam_delete_member_from_group: sam_methods of the domain did not specify sam_delete_member_from_group\n"));
1253 return NT_STATUS_NOT_IMPLEMENTED
;
1256 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_delete_member_from_group(tmp_methods
, group
, member
))) {
1257 DEBUG(4,("sam_delete_member_from_group in backend %s failed\n", tmp_methods
->backendname
));
1261 return NT_STATUS_OK
;
1264 NTSTATUS
sam_enum_groupmembers(const SAM_CONTEXT
*context
, const SAM_GROUP_HANDLE
*group
, uint32
*members_count
, SAM_GROUP_MEMBER
**members
)
1266 const SAM_METHODS
*tmp_methods
;
1271 /* invalid group specified */
1272 SAM_ASSERT(group
&& group
->current_sam_methods
&& members_count
&& members
);
1274 tmp_methods
= group
->current_sam_methods
;
1276 if (!tmp_methods
->sam_enum_groupmembers
) {
1277 DEBUG(3, ("sam_enum_groupmembers: sam_methods of the domain did not specify sam_enum_group_members\n"));
1278 return NT_STATUS_NOT_IMPLEMENTED
;
1281 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_enum_groupmembers(tmp_methods
, group
, members_count
, members
))) {
1282 DEBUG(4,("sam_enum_groupmembers in backend %s failed\n", tmp_methods
->backendname
));
1286 return NT_STATUS_OK
;
1289 NTSTATUS
sam_get_groups_of_sid(const SAM_CONTEXT
*context
, const NT_USER_TOKEN
*access_token
, const DOM_SID
**sids
, uint16 group_ctrl
, uint32
*group_count
, SAM_GROUP_ENUM
**groups
)
1291 SAM_METHODS
*tmp_methods
;
1294 uint32 tmp_group_count
;
1295 SAM_GROUP_ENUM
*tmp_groups
;
1297 DEBUG(5,("sam_get_groups_of_sid: %d\n", __LINE__
));
1301 /* invalid sam_context specified */
1302 SAM_ASSERT(access_token
&& sids
&& context
&& context
->methods
);
1308 tmp_methods
= context
->methods
;
1310 while (tmp_methods
) {
1311 DEBUG(5,("getting groups from domain \n"));
1312 if (!tmp_methods
->sam_get_groups_of_sid
) {
1313 DEBUG(3, ("sam_get_groups_of_sid: sam_methods of domain did not specify sam_get_groups_of_sid\n"));
1315 return NT_STATUS_NOT_IMPLEMENTED
;
1318 if (!NT_STATUS_IS_OK(nt_status
= tmp_methods
->sam_get_groups_of_sid(tmp_methods
, access_token
, sids
, group_ctrl
, &tmp_group_count
, &tmp_groups
))) {
1319 DEBUG(4,("sam_get_groups_of_sid in backend %s failed\n", tmp_methods
->backendname
));
1324 *groups
= Realloc(*groups
, ((*group_count
) + tmp_group_count
) * sizeof(SAM_GROUP_ENUM
));
1326 memcpy(&(*groups
)[*group_count
], tmp_groups
, tmp_group_count
);
1328 SAFE_FREE(tmp_groups
);
1330 *group_count
+= tmp_group_count
;
1332 tmp_methods
= tmp_methods
->next
;
1335 return NT_STATUS_OK
;