2 * Unix SMB/CIFS implementation.
3 * Group Policy Object Support
4 * Copyright (C) Guenther Deschner 2005
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /****************************************************************
26 parse the raw extension string into a GP_EXT structure
27 ****************************************************************/
29 ADS_STATUS
ads_parse_gp_ext(TALLOC_CTX
*mem_ctx
,
30 const char *extension_raw
,
31 struct GP_EXT
*gp_ext
)
34 char **ext_strings
= NULL
;
37 DEBUG(20,("ads_parse_gp_ext: %s\n", extension_raw
));
39 ext_list
= str_list_make_talloc(mem_ctx
, extension_raw
, "]");
40 if (ext_list
== NULL
) {
44 for (i
= 0; ext_list
[i
] != NULL
; i
++) {
50 if (gp_ext
->num_exts
) {
51 gp_ext
->extensions
= TALLOC_ZERO_ARRAY(mem_ctx
, char *, gp_ext
->num_exts
);
52 gp_ext
->extensions_guid
= TALLOC_ZERO_ARRAY(mem_ctx
, char *, gp_ext
->num_exts
);
53 gp_ext
->snapins
= TALLOC_ZERO_ARRAY(mem_ctx
, char *, gp_ext
->num_exts
);
54 gp_ext
->snapins_guid
= TALLOC_ZERO_ARRAY(mem_ctx
, char *, gp_ext
->num_exts
);
56 gp_ext
->extensions
= NULL
;
57 gp_ext
->extensions_guid
= NULL
;
58 gp_ext
->snapins
= NULL
;
59 gp_ext
->snapins_guid
= NULL
;
62 if (gp_ext
->extensions
== NULL
|| gp_ext
->extensions_guid
== NULL
||
63 gp_ext
->snapins
== NULL
|| gp_ext
->snapins_guid
== NULL
||
64 gp_ext
->gp_extension
== NULL
) {
68 gp_ext
->gp_extension
= talloc_strdup(mem_ctx
, extension_raw
);
70 for (i
= 0; ext_list
[i
] != NULL
; i
++) {
75 DEBUGADD(10,("extension #%d\n", i
));
83 ext_strings
= str_list_make_talloc(mem_ctx
, p
, "}");
84 if (ext_strings
== NULL
) {
88 for (k
= 0; ext_strings
[k
] != NULL
; k
++) {
98 gp_ext
->extensions
[i
] = talloc_strdup(mem_ctx
, cse_gpo_guid_string_to_name(q
));
99 gp_ext
->extensions_guid
[i
] = talloc_strdup(mem_ctx
, q
);
101 /* we might have no name for the guid */
102 if (gp_ext
->extensions_guid
[i
] == NULL
) {
106 for (k
= 1; ext_strings
[k
] != NULL
; k
++) {
108 char *m
= ext_strings
[k
];
114 /* FIXME: theoretically there could be more than one snapin per extension */
115 gp_ext
->snapins
[i
] = talloc_strdup(mem_ctx
, cse_snapin_gpo_guid_string_to_name(m
));
116 gp_ext
->snapins_guid
[i
] = talloc_strdup(mem_ctx
, m
);
118 /* we might have no name for the guid */
119 if (gp_ext
->snapins_guid
[i
] == NULL
) {
126 str_list_free_talloc(mem_ctx
, &ext_list
);
129 str_list_free_talloc(mem_ctx
, &ext_strings
);
132 return ADS_ERROR(LDAP_SUCCESS
);
136 str_list_free_talloc(mem_ctx
, &ext_list
);
139 str_list_free_talloc(mem_ctx
, &ext_strings
);
142 return ADS_ERROR(LDAP_NO_MEMORY
);
145 /****************************************************************
146 parse the raw link string into a GP_LINK structure
147 ****************************************************************/
149 ADS_STATUS
ads_parse_gplink(TALLOC_CTX
*mem_ctx
,
150 const char *gp_link_raw
,
152 struct GP_LINK
*gp_link
)
157 DEBUG(10,("ads_parse_gplink: gPLink: %s\n", gp_link_raw
));
159 link_list
= str_list_make_talloc(mem_ctx
, gp_link_raw
, "]");
160 if (link_list
== NULL
) {
164 for (i
= 0; link_list
[i
] != NULL
; i
++) {
168 gp_link
->gp_opts
= options
;
169 gp_link
->num_links
= i
;
171 if (gp_link
->num_links
) {
172 gp_link
->link_names
= TALLOC_ZERO_ARRAY(mem_ctx
, char *, gp_link
->num_links
);
173 gp_link
->link_opts
= TALLOC_ZERO_ARRAY(mem_ctx
, uint32
, gp_link
->num_links
);
175 gp_link
->link_names
= NULL
;
176 gp_link
->link_opts
= NULL
;
179 gp_link
->gp_link
= talloc_strdup(mem_ctx
, gp_link_raw
);
181 if (gp_link
->link_names
== NULL
|| gp_link
->link_opts
== NULL
|| gp_link
->gp_link
== NULL
) {
185 for (i
= 0; link_list
[i
] != NULL
; i
++) {
189 DEBUGADD(10,("ads_parse_gplink: processing link #%d\n", i
));
202 gp_link
->link_names
[i
] = talloc_strdup(mem_ctx
, q
);
203 if (gp_link
->link_names
[i
] == NULL
) {
206 gp_link
->link_names
[i
][PTR_DIFF(p
, q
)] = 0;
208 gp_link
->link_opts
[i
] = atoi(p
+ 1);
210 DEBUGADD(10,("ads_parse_gplink: link: %s\n", gp_link
->link_names
[i
]));
211 DEBUGADD(10,("ads_parse_gplink: opt: %d\n", gp_link
->link_opts
[i
]));
216 str_list_free_talloc(mem_ctx
, &link_list
);
219 return ADS_ERROR(LDAP_SUCCESS
);
223 str_list_free_talloc(mem_ctx
, &link_list
);
226 return ADS_ERROR(LDAP_NO_MEMORY
);
229 /****************************************************************
230 helper call to get a GP_LINK structure from a linkdn
231 ****************************************************************/
233 ADS_STATUS
ads_get_gpo_link(ADS_STRUCT
*ads
,
236 struct GP_LINK
*gp_link_struct
)
239 const char *attrs
[] = {"gPLink", "gPOptions", NULL
};
240 LDAPMessage
*res
= NULL
;
244 ZERO_STRUCTP(gp_link_struct
);
246 status
= ads_search_dn(ads
, &res
, link_dn
, attrs
);
247 if (!ADS_ERR_OK(status
)) {
248 DEBUG(10,("ads_get_gpo_link: search failed with %s\n", ads_errstr(status
)));
252 if (ads_count_replies(ads
, res
) != 1) {
253 DEBUG(10,("ads_get_gpo_link: no result\n"));
254 ads_msgfree(ads
, res
);
255 return ADS_ERROR(LDAP_NO_SUCH_OBJECT
);
258 gp_link
= ads_pull_string(ads
, mem_ctx
, res
, "gPLink");
259 if (gp_link
== NULL
) {
260 DEBUG(10,("ads_get_gpo_link: no 'gPLink' attribute found\n"));
261 ads_msgfree(ads
, res
);
262 return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE
);
265 /* perfectly leggal to have no options */
266 if (!ads_pull_uint32(ads
, res
, "gPOptions", &gp_options
)) {
267 DEBUG(10,("ads_get_gpo_link: no 'gPOptions' attribute found\n"));
271 ads_msgfree(ads
, res
);
273 return ads_parse_gplink(mem_ctx
, gp_link
, gp_options
, gp_link_struct
);
276 /****************************************************************
277 helper call to add a gp link
278 ****************************************************************/
280 ADS_STATUS
ads_add_gpo_link(ADS_STRUCT
*ads
,
287 const char *attrs
[] = {"gPLink", NULL
};
288 LDAPMessage
*res
= NULL
;
289 const char *gp_link
, *gp_link_new
;
292 /* although ADS allows to set anything here, we better check here if
293 * the gpo_dn is sane */
295 if (!strnequal(gpo_dn
, "LDAP://CN={", strlen("LDAP://CN={")) != 0) {
296 return ADS_ERROR(LDAP_INVALID_DN_SYNTAX
);
299 status
= ads_search_dn(ads
, &res
, link_dn
, attrs
);
300 if (!ADS_ERR_OK(status
)) {
301 DEBUG(10,("ads_add_gpo_link: search failed with %s\n", ads_errstr(status
)));
305 if (ads_count_replies(ads
, res
) != 1) {
306 DEBUG(10,("ads_add_gpo_link: no result\n"));
307 ads_msgfree(ads
, res
);
308 return ADS_ERROR(LDAP_NO_SUCH_OBJECT
);
311 gp_link
= ads_pull_string(ads
, mem_ctx
, res
, "gPLink");
312 if (gp_link
== NULL
) {
313 gp_link_new
= talloc_asprintf(mem_ctx
, "[%s;%d]", gpo_dn
, gpo_opt
);
315 gp_link_new
= talloc_asprintf(mem_ctx
, "%s[%s;%d]", gp_link
, gpo_dn
, gpo_opt
);
318 ads_msgfree(ads
, res
);
319 ADS_ERROR_HAVE_NO_MEMORY(gp_link_new
);
321 mods
= ads_init_mods(mem_ctx
);
322 ADS_ERROR_HAVE_NO_MEMORY(mods
);
324 status
= ads_mod_str(mem_ctx
, &mods
, "gPLink", gp_link_new
);
325 if (!ADS_ERR_OK(status
)) {
329 return ads_gen_mod(ads
, link_dn
, mods
);
332 /****************************************************************
333 helper call to delete add a gp link
334 ****************************************************************/
336 /* untested & broken */
337 ADS_STATUS
ads_delete_gpo_link(ADS_STRUCT
*ads
,
343 const char *attrs
[] = {"gPLink", NULL
};
344 LDAPMessage
*res
= NULL
;
345 const char *gp_link
, *gp_link_new
= NULL
;
348 /* check for a sane gpo_dn */
349 if (gpo_dn
[0] != '[') {
350 DEBUG(10,("ads_delete_gpo_link: first char not: [\n"));
351 return ADS_ERROR(LDAP_INVALID_DN_SYNTAX
);
354 if (gpo_dn
[strlen(gpo_dn
)] != ']') {
355 DEBUG(10,("ads_delete_gpo_link: last char not: ]\n"));
356 return ADS_ERROR(LDAP_INVALID_DN_SYNTAX
);
359 status
= ads_search_dn(ads
, &res
, link_dn
, attrs
);
360 if (!ADS_ERR_OK(status
)) {
361 DEBUG(10,("ads_delete_gpo_link: search failed with %s\n", ads_errstr(status
)));
365 if (ads_count_replies(ads
, res
) != 1) {
366 DEBUG(10,("ads_delete_gpo_link: no result\n"));
367 ads_msgfree(ads
, res
);
368 return ADS_ERROR(LDAP_NO_SUCH_OBJECT
);
371 gp_link
= ads_pull_string(ads
, mem_ctx
, res
, "gPLink");
372 if (gp_link
== NULL
) {
373 return ADS_ERROR(LDAP_NO_SUCH_ATTRIBUTE
);
376 /* find link to delete */
377 /* gp_link_new = talloc_asprintf(mem_ctx, "%s[%s;%d]", gp_link, gpo_dn, gpo_opt); */
379 ads_msgfree(ads
, res
);
380 ADS_ERROR_HAVE_NO_MEMORY(gp_link_new
);
382 mods
= ads_init_mods(mem_ctx
);
383 ADS_ERROR_HAVE_NO_MEMORY(mods
);
385 status
= ads_mod_str(mem_ctx
, &mods
, "gPLink", gp_link_new
);
386 if (!ADS_ERR_OK(status
)) {
390 return ads_gen_mod(ads
, link_dn
, mods
);
393 /****************************************************************
394 parse a GROUP_POLICY_OBJECT structure from an LDAPMessage result
395 ****************************************************************/
397 ADS_STATUS
ads_parse_gpo(ADS_STRUCT
*ads
,
401 struct GROUP_POLICY_OBJECT
*gpo
)
405 ADS_ERROR_HAVE_NO_MEMORY(res
);
408 gpo
->ds_path
= talloc_strdup(mem_ctx
, gpo_dn
);
410 gpo
->ds_path
= ads_get_dn(ads
, res
);
413 ADS_ERROR_HAVE_NO_MEMORY(gpo
->ds_path
);
415 if (!ads_pull_uint32(ads
, res
, "versionNumber", &gpo
->version
)) {
416 return ADS_ERROR(LDAP_NO_MEMORY
);
420 if (!ads_pull_uint32(ads
, res
, "flags", &gpo
->options
)) {
421 return ADS_ERROR(LDAP_NO_MEMORY
);
424 gpo
->file_sys_path
= ads_pull_string(ads
, mem_ctx
, res
, "gPCFileSysPath");
425 ADS_ERROR_HAVE_NO_MEMORY(gpo
->file_sys_path
);
427 gpo
->display_name
= ads_pull_string(ads
, mem_ctx
, res
, "displayName");
428 ADS_ERROR_HAVE_NO_MEMORY(gpo
->display_name
);
430 gpo
->name
= ads_pull_string(ads
, mem_ctx
, res
, "name");
431 ADS_ERROR_HAVE_NO_MEMORY(gpo
->name
);
433 /* ???, this is optional to have and what does it depend on, the 'flags' ?) */
434 gpo
->machine_extensions
= ads_pull_string(ads
, mem_ctx
, res
, "gPCMachineExtensionNames");
435 gpo
->user_extensions
= ads_pull_string(ads
, mem_ctx
, res
, "gPCUserExtensionNames");
437 return ADS_ERROR(LDAP_SUCCESS
);
440 /****************************************************************
441 get a GROUP_POLICY_OBJECT structure based on different input paramters
442 ****************************************************************/
444 ADS_STATUS
ads_get_gpo(ADS_STRUCT
*ads
,
447 const char *display_name
,
448 const char *guid_name
,
449 struct GROUP_POLICY_OBJECT
*gpo
)
452 LDAPMessage
*res
= NULL
;
455 const char *attrs
[] = { "cn", "displayName", "flags", "gPCFileSysPath",
456 "gPCFunctionalityVersion", "gPCMachineExtensionNames",
457 "gPCUserExtensionNames", "gPCWQLFilter", "name",
458 "versionNumber", NULL
};
462 if (!gpo_dn
&& !display_name
&& !guid_name
) {
463 return ADS_ERROR(LDAP_NO_SUCH_OBJECT
);
468 if (strnequal(gpo_dn
, "LDAP://", strlen("LDAP://")) != 0) {
469 gpo_dn
= gpo_dn
+ strlen("LDAP://");
472 status
= ads_search_dn(ads
, &res
, gpo_dn
, attrs
);
474 } else if (display_name
|| guid_name
) {
476 filter
= talloc_asprintf(mem_ctx
,
477 "(&(objectclass=groupPolicyContainer)(%s=%s))",
478 display_name
? "displayName" : "name",
479 display_name
? display_name
: guid_name
);
480 ADS_ERROR_HAVE_NO_MEMORY(filter
);
482 status
= ads_do_search_all(ads
, ads
->config
.bind_path
,
483 LDAP_SCOPE_SUBTREE
, filter
,
487 if (!ADS_ERR_OK(status
)) {
488 DEBUG(10,("ads_get_gpo: search failed with %s\n", ads_errstr(status
)));
492 if (ads_count_replies(ads
, res
) != 1) {
493 DEBUG(10,("ads_get_gpo: no result\n"));
494 ads_msgfree(ads
, res
);
495 return ADS_ERROR(LDAP_NO_SUCH_OBJECT
);
498 dn
= ads_get_dn(ads
, res
);
500 ads_msgfree(ads
, res
);
501 return ADS_ERROR(LDAP_NO_MEMORY
);
504 status
= ads_parse_gpo(ads
, mem_ctx
, res
, dn
, gpo
);
505 ads_msgfree(ads
, res
);
506 ads_memfree(ads
, dn
);
511 /****************************************************************
512 add a gplink to the GROUP_POLICY_OBJECT linked list
513 ****************************************************************/
515 ADS_STATUS
add_gplink_to_gpo_list(ADS_STRUCT
*ads
,
517 struct GROUP_POLICY_OBJECT
**gpo_list
,
519 struct GP_LINK
*gp_link
,
520 enum GPO_LINK_TYPE link_type
,
521 BOOL only_add_forced_gpos
)
526 for (i
= 0; i
< gp_link
->num_links
; i
++) {
528 struct GROUP_POLICY_OBJECT
*new_gpo
= NULL
;
530 if (gp_link
->link_opts
[i
] & GPO_LINK_OPT_DISABLED
) {
531 DEBUG(10,("skipping disabled GPO\n"));
535 if (only_add_forced_gpos
) {
537 if (! (gp_link
->link_opts
[i
] & GPO_LINK_OPT_ENFORCED
)) {
538 DEBUG(10,("skipping nonenforced GPO link because GPOPTIONS_BLOCK_INHERITANCE has been set\n"));
541 DEBUG(10,("adding enforced GPO link although the GPOPTIONS_BLOCK_INHERITANCE has been set\n"));
545 new_gpo
= TALLOC_P(mem_ctx
, struct GROUP_POLICY_OBJECT
);
546 ADS_ERROR_HAVE_NO_MEMORY(new_gpo
);
548 ZERO_STRUCTP(new_gpo
);
550 status
= ads_get_gpo(ads
, mem_ctx
, gp_link
->link_names
[i
], NULL
, NULL
, new_gpo
);
551 if (!ADS_ERR_OK(status
)) {
555 new_gpo
->link
= link_dn
;
556 new_gpo
->link_type
= link_type
;
558 DLIST_ADD(*gpo_list
, new_gpo
);
560 DEBUG(10,("add_gplink_to_gplist: added GPLINK #%d %s to GPO list\n",
561 i
, gp_link
->link_names
[i
]));
564 return ADS_ERROR(LDAP_SUCCESS
);
567 /****************************************************************
568 get the full list of GROUP_POLICY_OBJECTs for a given dn
569 ****************************************************************/
571 ADS_STATUS
ads_get_gpo_list(ADS_STRUCT
*ads
,
575 struct GROUP_POLICY_OBJECT
**gpo_list
)
577 /* (L)ocal (S)ite (D)omain (O)rganizational(U)nit */
580 struct GP_LINK gp_link
;
581 const char *parent_dn
, *site_dn
, *tmp_dn
;
582 BOOL add_only_forced_gpos
= False
;
584 ZERO_STRUCTP(gpo_list
);
586 DEBUG(10,("ads_get_gpo_list: getting GPO list for [%s]\n", dn
));
593 /* are site GPOs valid for users as well ??? */
594 if (flags
& GPO_LIST_FLAG_MACHINE
) {
596 status
= ads_site_dn_for_machine(ads
, mem_ctx
, ads
->config
.ldap_server_name
, &site_dn
);
597 if (!ADS_ERR_OK(status
)) {
601 DEBUG(10,("ads_get_gpo_list: query SITE: [%s] for GPOs\n", site_dn
));
603 status
= ads_get_gpo_link(ads
, mem_ctx
, site_dn
, &gp_link
);
604 if (ADS_ERR_OK(status
)) {
606 if (DEBUGLEVEL
>= 100) {
607 dump_gplink(ads
, mem_ctx
, &gp_link
);
610 status
= add_gplink_to_gpo_list(ads
, mem_ctx
, gpo_list
,
611 site_dn
, &gp_link
, GP_LINK_SITE
,
612 add_only_forced_gpos
);
613 if (!ADS_ERR_OK(status
)) {
617 if (flags
& GPO_LIST_FLAG_SITEONLY
) {
618 return ADS_ERROR(LDAP_SUCCESS
);
621 /* inheritance can't be blocked at the site level */
627 while ( (parent_dn
= ads_parent_dn(tmp_dn
)) &&
628 (!strequal(parent_dn
, ads_parent_dn(ads
->config
.bind_path
))) ) {
632 /* An account can just be a member of one domain */
633 if (strncmp(parent_dn
, "DC=", strlen("DC=")) == 0) {
635 DEBUG(10,("ads_get_gpo_list: query DC: [%s] for GPOs\n", parent_dn
));
637 status
= ads_get_gpo_link(ads
, mem_ctx
, parent_dn
, &gp_link
);
638 if (ADS_ERR_OK(status
)) {
640 if (DEBUGLEVEL
>= 100) {
641 dump_gplink(ads
, mem_ctx
, &gp_link
);
644 /* block inheritance from now on */
645 if (gp_link
.gp_opts
& GPOPTIONS_BLOCK_INHERITANCE
) {
646 add_only_forced_gpos
= True
;
649 status
= add_gplink_to_gpo_list(ads
, mem_ctx
,
651 &gp_link
, GP_LINK_DOMAIN
,
652 add_only_forced_gpos
);
653 if (!ADS_ERR_OK(status
)) {
665 while ( (parent_dn
= ads_parent_dn(tmp_dn
)) &&
666 (!strequal(parent_dn
, ads_parent_dn(ads
->config
.bind_path
))) ) {
669 /* (O)rganizational(U)nit */
671 /* An account can be a member of more OUs */
672 if (strncmp(parent_dn
, "OU=", strlen("OU=")) == 0) {
674 DEBUG(10,("ads_get_gpo_list: query OU: [%s] for GPOs\n", parent_dn
));
676 status
= ads_get_gpo_link(ads
, mem_ctx
, parent_dn
, &gp_link
);
677 if (ADS_ERR_OK(status
)) {
679 if (DEBUGLEVEL
>= 100) {
680 dump_gplink(ads
, mem_ctx
, &gp_link
);
683 /* block inheritance from now on */
684 if (gp_link
.gp_opts
& GPOPTIONS_BLOCK_INHERITANCE
) {
685 add_only_forced_gpos
= True
;
688 status
= add_gplink_to_gpo_list(ads
, mem_ctx
,
690 &gp_link
, GP_LINK_OU
,
691 add_only_forced_gpos
);
692 if (!ADS_ERR_OK(status
)) {
702 return ADS_ERROR(LDAP_SUCCESS
);
705 #endif /* HAVE_LDAP */