r23354: Fix build warning.
[tprouty/samba.git] / source / libgpo / gpo_util.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  Group Policy Object Support
4  *  Copyright (C) Guenther Deschner 2005-2006
5  *  
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *  
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *  
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20
21 #include "includes.h"
22
23 #ifdef HAVE_LDAP
24
25 #define DEFAULT_DOMAIN_POLICY "Default Domain Policy"
26 #define DEFAULT_DOMAIN_CONTROLLERS_POLICY "Default Domain Controllers Policy"
27
28 /* should we store a parsed guid ? */
29 struct gpo_table {
30         const char *name;
31         const char *guid_string;
32 };
33
34 struct snapin_table {
35         const char *name;
36         const char *guid_string;
37         ADS_STATUS (*snapin_fn)(ADS_STRUCT *, TALLOC_CTX *mem_ctx, const char *, const char *);
38 };
39
40 #if 0 /* unused */
41 static struct gpo_table gpo_default_policy[] = {
42         { DEFAULT_DOMAIN_POLICY, 
43                 "31B2F340-016D-11D2-945F-00C04FB984F9" },
44         { DEFAULT_DOMAIN_CONTROLLERS_POLICY, 
45                 "6AC1786C-016F-11D2-945F-00C04fB984F9" },
46         { NULL, NULL }
47 };
48 #endif
49
50 /* the following is seen in gPCMachineExtensionNames or gPCUserExtensionNames */
51
52 static struct gpo_table gpo_cse_extensions[] = {
53         { "Administrative Templates Extension", 
54                 "35378EAC-683F-11D2-A89A-00C04FBBCFA2" }, /* Registry Policy ? */
55         { "Microsoft Disc Quota", 
56                 "3610EDA5-77EF-11D2-8DC5-00C04FA31A66" },
57         { "EFS recovery", 
58                 "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A" },
59         { "Folder Redirection", 
60                 "25537BA6-77A8-11D2-9B6C-0000F8080861" },
61         { "IP Security", 
62                 "E437BC1C-AA7D-11D2-A382-00C04F991E27" },
63         { "Internet Explorer Branding", 
64                 "A2E30F80-D7DE-11d2-BBDE-00C04F86AE3B" },
65         { "QoS Packet Scheduler", 
66                 "426031c0-0b47-4852-b0ca-ac3d37bfcb39" },
67         { "Scripts", 
68                 "42B5FAAE-6536-11D2-AE5A-0000F87571E3" },
69         { "Security", 
70                 "827D319E-6EAC-11D2-A4EA-00C04F79F83A" },
71         { "Software Installation", 
72                 "C6DC5466-785A-11D2-84D0-00C04FB169F7" },
73         { "Wireless Group Policy", 
74                 "0ACDD40C-75AC-BAA0-BF6DE7E7FE63" },
75         { NULL, NULL }
76 };
77
78 /* guess work */
79 static struct snapin_table gpo_cse_snapin_extensions[] = {
80         { "Administrative Templates", 
81                 "0F6B957D-509E-11D1-A7CC-0000F87571E3", gpo_snapin_handler_none },
82         { "Certificates", 
83                 "53D6AB1D-2488-11D1-A28C-00C04FB94F17", gpo_snapin_handler_none },
84         { "EFS recovery policy processing", 
85                 "B1BE8D72-6EAC-11D2-A4EA-00C04F79F83A", gpo_snapin_handler_none },
86         { "Folder Redirection policy processing", 
87                 "25537BA6-77A8-11D2-9B6C-0000F8080861", gpo_snapin_handler_none },
88         { "Folder Redirection", 
89                 "88E729D6-BDC1-11D1-BD2A-00C04FB9603F", gpo_snapin_handler_none },
90         { "Registry policy processing", 
91                 "35378EAC-683F-11D2-A89A-00C04FBBCFA2", gpo_snapin_handler_none },
92         { "Remote Installation Services", 
93                 "3060E8CE-7020-11D2-842D-00C04FA372D4", gpo_snapin_handler_none },
94         { "Security Settings", 
95                 "803E14A0-B4FB-11D0-A0D0-00A0C90F574B", gpo_snapin_handler_security_settings },
96         { "Security policy processing", 
97                 "827D319E-6EAC-11D2-A4EA-00C04F79F83A", gpo_snapin_handler_security_settings },
98         { "unknown", 
99                 "3060E8D0-7020-11D2-842D-00C04FA372D4", gpo_snapin_handler_none },
100         { "unknown2", 
101                 "53D6AB1B-2488-11D1-A28C-00C04FB94F17", gpo_snapin_handler_none },
102         { NULL, NULL, NULL }
103 };
104
105 static const char *name_to_guid_string(const char *name, struct gpo_table *table)
106 {
107         int i;
108
109         for (i = 0; table[i].name; i++) {
110                 if (strequal(name, table[i].name)) {
111                         return table[i].guid_string;
112                 }
113         }
114         
115         return NULL;
116 }
117
118 static const char *guid_string_to_name(const char *guid_string, struct gpo_table *table)
119 {
120         int i;
121
122         for (i = 0; table[i].guid_string; i++) {
123                 if (strequal(guid_string, table[i].guid_string)) {
124                         return table[i].name;
125                 }
126         }
127         
128         return NULL;
129 }
130
131 static const char *snapin_guid_string_to_name(const char *guid_string, 
132                                               struct snapin_table *table)
133 {
134         int i;
135         for (i = 0; table[i].guid_string; i++) {
136                 if (strequal(guid_string, table[i].guid_string)) {
137                         return table[i].name;
138                 }
139         }
140         return NULL;
141 }
142
143 #if 0 /* unused */
144 static const char *default_gpo_name_to_guid_string(const char *name)
145 {
146         return name_to_guid_string(name, gpo_default_policy);
147 }
148
149 static const char *default_gpo_guid_string_to_name(const char *guid)
150 {
151         return guid_string_to_name(guid, gpo_default_policy);
152 }
153 #endif
154
155 const char *cse_gpo_guid_string_to_name(const char *guid)
156 {
157         return guid_string_to_name(guid, gpo_cse_extensions);
158 }
159
160 static const char *cse_gpo_name_to_guid_string(const char *name)
161 {
162         return name_to_guid_string(name, gpo_cse_extensions);
163 }
164
165 const char *cse_snapin_gpo_guid_string_to_name(const char *guid)
166 {
167         return snapin_guid_string_to_name(guid, gpo_cse_snapin_extensions);
168 }
169
170 void dump_gp_ext(struct GP_EXT *gp_ext, int debuglevel)
171 {
172         int lvl = debuglevel;
173         int i;
174
175         if (gp_ext == NULL) {
176                 return;
177         }
178
179         DEBUG(lvl,("\t---------------------\n\n"));
180         DEBUGADD(lvl,("\tname:\t\t\t%s\n", gp_ext->gp_extension));
181
182         for (i=0; i< gp_ext->num_exts; i++) {
183
184                 DEBUGADD(lvl,("\textension:\t\t\t%s\n", gp_ext->extensions_guid[i]));
185                 DEBUGADD(lvl,("\textension (name):\t\t\t%s\n", gp_ext->extensions[i]));
186                 
187                 DEBUGADD(lvl,("\tsnapin:\t\t\t%s\n", gp_ext->snapins_guid[i]));
188                 DEBUGADD(lvl,("\tsnapin (name):\t\t\t%s\n", gp_ext->snapins[i]));
189         }
190 }
191
192 void dump_gpo(TALLOC_CTX *mem_ctx, struct GROUP_POLICY_OBJECT *gpo, int debuglevel) 
193 {
194         int lvl = debuglevel;
195
196         if (gpo == NULL) {
197                 return;
198         }
199
200         DEBUG(lvl,("---------------------\n\n"));
201
202         DEBUGADD(lvl,("name:\t\t\t%s\n", gpo->name));
203         DEBUGADD(lvl,("displayname:\t\t%s\n", gpo->display_name));
204         DEBUGADD(lvl,("version:\t\t%d (0x%08x)\n", gpo->version, gpo->version));
205         DEBUGADD(lvl,("version_user:\t\t%d (0x%04x)\n", GPO_VERSION_USER(gpo->version), 
206                                                         GPO_VERSION_USER(gpo->version)));
207         DEBUGADD(lvl,("version_machine:\t%d (0x%04x)\n", GPO_VERSION_MACHINE(gpo->version), 
208                                                          GPO_VERSION_MACHINE(gpo->version)));
209         DEBUGADD(lvl,("filesyspath:\t\t%s\n", gpo->file_sys_path));
210         DEBUGADD(lvl,("dspath:\t\t%s\n", gpo->ds_path));
211
212         DEBUGADD(lvl,("options:\t\t%d ", gpo->options));
213         if (gpo->options & GPFLAGS_USER_SETTINGS_DISABLED) {
214                 DEBUGADD(lvl,("GPFLAGS_USER_SETTINGS_DISABLED ")); 
215         }
216         if (gpo->options & GPFLAGS_MACHINE_SETTINGS_DISABLED) {
217                 DEBUGADD(lvl,("GPFLAGS_MACHINE_SETTINGS_DISABLED")); 
218         }
219         DEBUGADD(lvl,("\n"));
220
221         DEBUGADD(lvl,("link:\t\t\t%s\n", gpo->link));
222         DEBUGADD(lvl,("link_type:\t\t%d ", gpo->link_type));
223         switch (gpo->link_type) {
224         case GP_LINK_UNKOWN:
225                 DEBUGADD(lvl,("GP_LINK_UNKOWN\n"));
226                 break;
227         case GP_LINK_OU:
228                 DEBUGADD(lvl,("GP_LINK_OU\n"));
229                 break;
230         case GP_LINK_DOMAIN:
231                 DEBUGADD(lvl,("GP_LINK_DOMAIN\n"));
232                 break;
233         case GP_LINK_SITE:
234                 DEBUGADD(lvl,("GP_LINK_SITE\n"));
235                 break;
236         case GP_LINK_MACHINE:
237                 DEBUGADD(lvl,("GP_LINK_MACHINE\n"));
238                 break;
239         default:
240                 break;
241         }
242
243         if (gpo->machine_extensions) {
244
245                 struct GP_EXT gp_ext;
246                 ADS_STATUS status;
247
248                 DEBUGADD(lvl,("machine_extensions:\t%s\n", gpo->machine_extensions));
249
250                 status = ads_parse_gp_ext(mem_ctx, gpo->machine_extensions, &gp_ext);
251                 if (!ADS_ERR_OK(status)) {
252                         return;
253                 }
254                 dump_gp_ext(&gp_ext, lvl);
255         }
256         
257         if (gpo->user_extensions) {
258         
259                 struct GP_EXT gp_ext;
260                 ADS_STATUS status;
261                 
262                 DEBUGADD(lvl,("user_extensions:\t%s\n", gpo->user_extensions));
263
264                 status = ads_parse_gp_ext(mem_ctx, gpo->user_extensions, &gp_ext);
265                 if (!ADS_ERR_OK(status)) {
266                         return;
267                 }
268                 dump_gp_ext(&gp_ext, lvl);
269         }
270 }
271
272 void dump_gplink(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, struct GP_LINK *gp_link)
273 {
274         ADS_STATUS status;
275         int i;
276         int lvl = 10;
277
278         if (gp_link == NULL) {
279                 return;
280         }
281
282         DEBUG(lvl,("---------------------\n\n"));
283
284         DEBUGADD(lvl,("gplink: %s\n", gp_link->gp_link));
285         DEBUGADD(lvl,("gpopts: %d ", gp_link->gp_opts));
286         switch (gp_link->gp_opts) {
287         case GPOPTIONS_INHERIT:
288                 DEBUGADD(lvl,("GPOPTIONS_INHERIT\n"));
289                 break;
290         case GPOPTIONS_BLOCK_INHERITANCE:
291                 DEBUGADD(lvl,("GPOPTIONS_BLOCK_INHERITANCE\n"));
292                 break;
293         default:
294                 break;
295         }
296
297         DEBUGADD(lvl,("num links: %d\n", gp_link->num_links));
298
299         for (i = 0; i < gp_link->num_links; i++) {
300         
301                 DEBUGADD(lvl,("---------------------\n\n"));
302         
303                 DEBUGADD(lvl,("link: #%d\n", i + 1));
304                 DEBUGADD(lvl,("name: %s\n", gp_link->link_names[i]));
305
306                 DEBUGADD(lvl,("opt: %d ", gp_link->link_opts[i]));
307                 if (gp_link->link_opts[i] & GPO_LINK_OPT_ENFORCED) {
308                         DEBUGADD(lvl,("GPO_LINK_OPT_ENFORCED "));
309                 }
310                 if (gp_link->link_opts[i] & GPO_LINK_OPT_DISABLED) {
311                         DEBUGADD(lvl,("GPO_LINK_OPT_DISABLED"));
312                 }
313                 DEBUGADD(lvl,("\n"));
314
315                 if (ads != NULL && mem_ctx != NULL) {
316
317                         struct GROUP_POLICY_OBJECT gpo;
318
319                         status = ads_get_gpo(ads, mem_ctx, gp_link->link_names[i], NULL, NULL, &gpo);
320                         if (!ADS_ERR_OK(status)) {
321                                 DEBUG(lvl,("get gpo for %s failed: %s\n", gp_link->link_names[i], ads_errstr(status)));
322                                 return;
323                         }
324                         dump_gpo(mem_ctx, &gpo, lvl);
325                 }
326         }
327 }
328
329 ADS_STATUS process_extension_with_snapin(ADS_STRUCT *ads,
330                                          TALLOC_CTX *mem_ctx,
331                                          const char *extension_guid,
332                                          const char *snapin_guid)
333 {
334         int i;
335
336         for (i=0; gpo_cse_snapin_extensions[i].guid_string; i++) {
337         
338                 if (strcmp(gpo_cse_snapin_extensions[i].guid_string, snapin_guid) == 0) {
339                 
340                         return gpo_cse_snapin_extensions[i].snapin_fn(ads, mem_ctx, 
341                                                                       extension_guid, snapin_guid);
342                 }
343         }
344
345         DEBUG(10,("process_extension_with_snapin: no snapin handler for extension %s (%s) found\n", 
346                 extension_guid, snapin_guid));
347
348         return ADS_SUCCESS;
349 }
350
351 ADS_STATUS gpo_process_a_gpo(ADS_STRUCT *ads,
352                              TALLOC_CTX *mem_ctx,
353                              struct GROUP_POLICY_OBJECT *gpo,
354                              const char *extension_guid,
355                              uint32 flags)
356 {
357         ADS_STATUS status;
358         struct GP_EXT gp_ext;
359         int i;
360         
361         if (flags & GPO_LIST_FLAG_MACHINE) {
362
363                 if (gpo->machine_extensions) {
364
365                         status = ads_parse_gp_ext(mem_ctx, gpo->machine_extensions, &gp_ext);
366
367                         if (!ADS_ERR_OK(status)) {
368                                 return status;
369                         }
370
371                 } else {
372                         /* nothing to apply */
373                         return ADS_SUCCESS;
374                 }
375         
376         } else {
377
378                 if (gpo->user_extensions) {
379                 
380                         status = ads_parse_gp_ext(mem_ctx, gpo->user_extensions, &gp_ext);
381
382                         if (!ADS_ERR_OK(status)) {
383                                 return status;
384                         }
385                 } else {
386                         /* nothing to apply */
387                         return ADS_SUCCESS;
388                 }
389         }
390
391         for (i=0; i<gp_ext.num_exts; i++) {
392
393                 if (extension_guid && !strequal(extension_guid, gp_ext.extensions_guid[i])) {
394                         continue;
395                 }
396
397                 status = process_extension_with_snapin(ads, mem_ctx, gp_ext.extensions_guid[i], 
398                                                        gp_ext.snapins_guid[i]);
399                 if (!ADS_ERR_OK(status)) {
400                         return status;
401                 }
402         }
403
404         return ADS_SUCCESS;
405 }
406
407 ADS_STATUS gpo_process_gpo_list(ADS_STRUCT *ads,
408                                 TALLOC_CTX *mem_ctx,
409                                 struct GROUP_POLICY_OBJECT **gpo_list,
410                                 const char *extensions_guid,
411                                 uint32 flags)
412 {
413         ADS_STATUS status;
414         struct GROUP_POLICY_OBJECT *gpo = *gpo_list;
415
416         for (gpo = *gpo_list; gpo; gpo = gpo->next) {
417         
418                 status = gpo_process_a_gpo(ads, mem_ctx, gpo, 
419                                            extensions_guid, flags);
420         
421                 if (!ADS_ERR_OK(status)) {
422                         return status;
423                 }
424
425         }
426
427         return ADS_SUCCESS;
428 }
429
430 ADS_STATUS gpo_snapin_handler_none(ADS_STRUCT *ads, 
431                                    TALLOC_CTX *mem_ctx, 
432                                    const char *extension_guid, 
433                                    const char *snapin_guid)
434 {
435         DEBUG(10,("gpo_snapin_handler_none\n"));
436
437         return ADS_SUCCESS;
438 }
439
440 ADS_STATUS gpo_snapin_handler_security_settings(ADS_STRUCT *ads, 
441                                                 TALLOC_CTX *mem_ctx, 
442                                                 const char *extension_guid, 
443                                                 const char *snapin_guid)
444 {
445         DEBUG(10,("gpo_snapin_handler_security_settings\n"));
446
447         return ADS_SUCCESS;
448 }
449
450 ADS_STATUS gpo_lockout_policy(ADS_STRUCT *ads,
451                               TALLOC_CTX *mem_ctx,
452                               const char *hostname,
453                               SAM_UNK_INFO_12 *lockout_policy)
454 {
455         return ADS_ERROR_NT(NT_STATUS_NOT_IMPLEMENTED);
456 }
457
458 ADS_STATUS gpo_password_policy(ADS_STRUCT *ads,
459                                TALLOC_CTX *mem_ctx,
460                                const char *hostname,
461                                SAM_UNK_INFO_1 *password_policy)
462 {
463         ADS_STATUS status;
464         struct GROUP_POLICY_OBJECT *gpo_list;
465         const char *attrs[] = {"distinguishedName", "userAccountControl", NULL};
466         char *filter, *dn;
467         LDAPMessage *res = NULL;
468         uint32 uac;
469
470         filter = talloc_asprintf(mem_ctx, "(&(objectclass=user)(sAMAccountName=%s))", hostname);
471         if (filter == NULL) {
472                 return ADS_ERROR(LDAP_NO_MEMORY);
473         }
474
475         status = ads_do_search_all(ads, ads->config.bind_path,
476                                    LDAP_SCOPE_SUBTREE,
477                                    filter, attrs, &res);
478         
479         if (!ADS_ERR_OK(status)) {
480                 return status;
481         }
482
483         if (ads_count_replies(ads, res) != 1) {
484                 ads_msgfree(ads, res);
485                 return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
486         }
487
488         dn = ads_get_dn(ads, res);
489         if (dn == NULL) {
490                 ads_msgfree(ads, res);
491                 return ADS_ERROR(LDAP_NO_MEMORY);
492         }
493
494         if (!ads_pull_uint32(ads, res, "userAccountControl", &uac)) {
495                 ads_msgfree(ads, res);
496                 ads_memfree(ads, dn);
497                 return ADS_ERROR(LDAP_NO_MEMORY);
498         }
499
500         ads_msgfree(ads, res);
501
502         if (!(uac & UF_WORKSTATION_TRUST_ACCOUNT)) {
503                 ads_memfree(ads, dn);
504                 return ADS_ERROR(LDAP_NO_SUCH_OBJECT);
505         }
506
507         status = ads_get_gpo_list(ads, mem_ctx, dn, GPO_LIST_FLAG_MACHINE, &gpo_list);
508         if (!ADS_ERR_OK(status)) {
509                 ads_memfree(ads, dn);
510                 return status;
511         }
512
513         ads_memfree(ads, dn);
514
515         status = gpo_process_gpo_list(ads, mem_ctx, &gpo_list, 
516                                       cse_gpo_name_to_guid_string("Security"), 
517                                       GPO_LIST_FLAG_MACHINE); 
518         if (!ADS_ERR_OK(status)) {
519                 return status;
520         }
521
522         return ADS_SUCCESS;
523 }
524
525 /****************************************************************
526  check wether the version number in a GROUP_POLICY_OBJECT match those of the
527  locally stored version. If not, fetch the required policy via CIFS
528 ****************************************************************/
529
530 NTSTATUS check_refresh_gpo(ADS_STRUCT *ads, 
531                            TALLOC_CTX *mem_ctx,
532                            struct GROUP_POLICY_OBJECT *gpo,
533                            struct cli_state **cli_out)
534 {
535         NTSTATUS result;
536         char *server, *share, *nt_path, *unix_path;
537         uint32 sysvol_gpt_version = 0;
538         char *display_name;
539         struct cli_state *cli = NULL;
540
541         result = ads_gpo_explode_filesyspath(ads, mem_ctx, gpo->file_sys_path, 
542                                              &server, &share, &nt_path, &unix_path);
543
544         if (!NT_STATUS_IS_OK(result)) {
545                 goto out;
546         }
547
548         result = ads_gpo_get_sysvol_gpt_version(ads, mem_ctx, 
549                                                 unix_path,
550                                                 &sysvol_gpt_version,
551                                                 &display_name); 
552         if (!NT_STATUS_IS_OK(result) && 
553             !NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_FILE)) {
554                 DEBUG(10,("check_refresh_gpo: failed to get local gpt version: %s\n", 
555                         nt_errstr(result)));
556                 goto out;
557         }
558
559         while (gpo->version > sysvol_gpt_version) {
560
561                 DEBUG(1,("check_refresh_gpo: need to refresh GPO\n"));
562
563                 if (*cli_out == NULL) {
564
565                         result = cli_full_connection(&cli, global_myname(), 
566                                                      server, /* ads->config.ldap_server_name, */
567                                                      NULL, 0,
568                                                      share, "A:",
569                                                      ads->auth.user_name, NULL, ads->auth.password,
570                                                      CLI_FULL_CONNECTION_USE_KERBEROS,
571                                                      Undefined, NULL);
572                         if (!NT_STATUS_IS_OK(result)) {
573                                 DEBUG(10,("check_refresh_gpo: failed to connect: %s\n", nt_errstr(result)));
574                                 goto out;
575                         }
576
577                         *cli_out = cli;
578                 }
579
580                 result = ads_fetch_gpo_files(ads, mem_ctx, *cli_out, gpo);
581                 if (!NT_STATUS_IS_OK(result)) {
582                         goto out;
583                 }
584
585                 result = ads_gpo_get_sysvol_gpt_version(ads, mem_ctx, 
586                                                         unix_path, 
587                                                         &sysvol_gpt_version,
588                                                         &display_name); 
589                 if (!NT_STATUS_IS_OK(result)) {
590                         DEBUG(10,("check_refresh_gpo: failed to get local gpt version: %s\n", 
591                                 nt_errstr(result)));
592                         goto out;
593                 }
594                 
595                 if (gpo->version == sysvol_gpt_version) {
596                         break;
597                 }
598         } 
599
600         DEBUG(10,("Name:\t\t\t%s\n", gpo->display_name));
601         DEBUGADD(10,("sysvol GPT version:\t%d (user: %d, machine: %d)\n", 
602                 sysvol_gpt_version, 
603                 GPO_VERSION_USER(sysvol_gpt_version), 
604                 GPO_VERSION_MACHINE(sysvol_gpt_version))); 
605         DEBUGADD(10,("LDAP GPO version:\t%d (user: %d, machine: %d)\n", 
606                 gpo->version,
607                 GPO_VERSION_USER(gpo->version),
608                 GPO_VERSION_MACHINE(gpo->version)));
609
610         result = NT_STATUS_OK;
611
612  out:
613         return result;
614
615 }
616
617 /****************************************************************
618  check wether the version numbers in the gpo_list match the locally stored, if
619  not, go and get each required GPO via CIFS
620  ****************************************************************/
621
622 NTSTATUS check_refresh_gpo_list(ADS_STRUCT *ads, 
623                                 TALLOC_CTX *mem_ctx, 
624                                 struct GROUP_POLICY_OBJECT *gpo_list)
625 {
626         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
627         struct cli_state *cli = NULL;
628         struct GROUP_POLICY_OBJECT *gpo;
629
630         for (gpo = gpo_list; gpo; gpo = gpo->next) {
631
632                 result = check_refresh_gpo(ads, mem_ctx, gpo, &cli);
633                 if (!NT_STATUS_IS_OK(result)) {
634                         goto out;
635                 }
636         }
637
638         result = NT_STATUS_OK;
639
640  out:
641         if (cli) {
642                 cli_shutdown(cli);
643         }
644
645         return result;
646 }
647
648 #endif /* HAVE_LDAP */