Add fetch function for GPO which fetches all relevant files from the sysvol share.
authorWilco Baan Hofman <wilco@baanhofman.nl>
Tue, 27 Apr 2010 19:06:11 +0000 (21:06 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Sun, 20 Jun 2010 15:19:11 +0000 (17:19 +0200)
Signed-off-by: Jelmer Vernooij <jelmer@samba.org>
source4/lib/policy/config.mk
source4/lib/policy/gp_filesys.c [new file with mode: 0644]
source4/lib/policy/gp_ldap.c
source4/lib/policy/policy.h
source4/lib/policy/wscript_build
source4/utils/net/net_gpo.c

index 01bd1f4f284679c042aa1dfedaeefc168332d154..74403f8565a64726092979d1cd25209a975982d7 100644 (file)
@@ -1,6 +1,6 @@
 [SUBSYSTEM::policy]
 PRIVATE_DEPENDENCIES = LIBLDB LIBSAMBA-NET
 
-policy_OBJ_FILES = $(policydir)/gp_ldap.o
+policy_OBJ_FILES = $(policydir)/gp_ldap.o $(policydir)/gp_filesys.c
 
 PC_FILES += $(policydir)/policy.pc
diff --git a/source4/lib/policy/gp_filesys.c b/source4/lib/policy/gp_filesys.c
new file mode 100644 (file)
index 0000000..bb42fa2
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *  Unix SMB/CIFS implementation.
+ *  Group Policy Object Support
+ *  Copyright (C) Wilco Baan Hofman 2008-2010
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+#include "includes.h"
+#include "lib/policy/policy.h"
+#include "libcli/raw/smb.h"
+#include "libcli/libcli.h"
+#include "param/param.h"
+#include "libcli/resolve/resolve.h"
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#define GP_MAX_DEPTH 25
+
+struct gp_list_state {
+       struct gp_context *gp_ctx;
+       uint8_t depth;
+       const char *cur_rel_path;
+       const char *share_path;
+       const char *local_path;
+};
+
+static NTSTATUS gp_do_list(const char *, struct gp_list_state *);
+
+/* Create a temporary policy directory */
+static const char *gp_tmpdir(TALLOC_CTX *mem_ctx)
+{
+       const char *gp_dir = talloc_asprintf(mem_ctx, "%s/policy", tmpdir());
+       struct stat st;
+
+       if (stat(gp_dir, &st) != 0) {
+               mkdir(gp_dir, 0755);
+       }
+
+       return gp_dir;
+}
+
+/* This function is called by the smbcli_list function */
+static void gp_list_helper (struct clilist_file_info *info, const char *mask, void *list_state_ptr)
+{
+       struct gp_list_state *state = list_state_ptr;
+       const char *rel_path, *full_remote_path;
+       char *local_rel_path, *full_local_path;
+       unsigned int i;
+       int fh_remote, fh_local;
+       uint8_t *buf;
+       size_t nread = 0;
+       size_t buf_size = 1024;
+
+       /* If the relative path is empty, then avoid the extra slash */
+       if (state->cur_rel_path[0] != '\0') {
+               /* Get local path by replacing backslashes with slashes */
+               local_rel_path = talloc_strdup(state, state->cur_rel_path);
+               for (i = 0; local_rel_path[i] != '\0'; i++) {
+                       if (local_rel_path[i] == '\\') {
+                               local_rel_path[i] = '/';
+                       }
+               }
+               full_local_path = talloc_asprintf(state, "%s/%s/%s", state->local_path, local_rel_path, info->name);
+       } else {
+               full_local_path = talloc_asprintf(state, "%s/%s", state->local_path, info->name);
+       }
+
+       /* Directory */
+       if (info->attrib & FILE_ATTRIBUTE_DIRECTORY) {
+               if (state->depth >= GP_MAX_DEPTH)
+                       return;
+               if (strcmp(info->name, ".") == 0 || strcmp(info->name, "..") == 0)
+                       return;
+
+               mkdir(full_local_path, 0755);
+
+               /* If the relative path is empty, then avoid the extra backslash */
+               if (state->cur_rel_path[0] != '\0') {
+                       rel_path = info->name;
+               } else {
+                       rel_path = talloc_asprintf(state, "%s\\%s", state->cur_rel_path, info->name);
+               }
+
+               /* Recurse into this directory */
+               gp_do_list(rel_path, state);
+               return;
+       }
+
+       /* If the relative path is empty, then avoid the extra backslash */
+       if (state->cur_rel_path[0] != '\0') {
+               full_remote_path = talloc_asprintf(state, "%s\\%s\\%s", state->share_path, state->cur_rel_path, info->name);
+       } else {
+               full_remote_path = talloc_asprintf(state, "%s\\%s", state->share_path, info->name);
+       }
+
+       /* Open the remote file */
+       fh_remote = smbcli_open(state->gp_ctx->cli->tree, full_remote_path, O_RDONLY, DENY_NONE);
+       if (fh_remote == -1) {
+               DEBUG(0, ("Failed to open remote file: %s\n", full_remote_path));
+               return;
+       }
+
+       /* Open the local file */
+       fh_local = open(full_local_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+       if (fh_local == -1) {
+               DEBUG(0, ("Failed to open local file: %s\n", full_local_path));
+               return;
+       }
+
+       /* Copy the contents of the file */
+       buf = talloc_zero_array(state, uint8_t, buf_size);
+       while (1) {
+               int n = smbcli_read(state->gp_ctx->cli->tree, fh_remote, buf, nread, buf_size);
+               if (n <= 0) {
+                       break;
+               }
+               if (write(fh_local, buf, n) != n) {
+                       DEBUG(0, ("Short write while copying file.\n"));
+                       return;
+               }
+               nread += n;
+       }
+       /* Close the files */
+       smbcli_close(state->gp_ctx->cli->tree, fh_remote);
+       close(fh_local);
+
+       return;
+}
+
+static NTSTATUS gp_do_list (const char *rel_path, struct gp_list_state *state)
+{
+       uint16_t attributes;
+       int success;
+       char *mask;
+       const char *old_rel_path;
+
+       attributes = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY;
+
+       /* Update the relative paths, while buffering the parent */
+       old_rel_path = state->cur_rel_path;
+       state->cur_rel_path = rel_path;
+       state->depth++;
+
+       /* Get the current mask */
+       mask = talloc_asprintf(state, "%s\\%s\\*", state->share_path, rel_path);
+       success = smbcli_list(state->gp_ctx->cli->tree, mask, attributes, gp_list_helper, state);
+       talloc_free(mask);
+
+       /* Go back to the state of the parent */
+       state->cur_rel_path = old_rel_path;
+       state->depth--;
+
+       if (!success)
+               return NT_STATUS_UNSUCCESSFUL;
+
+       return NT_STATUS_OK;
+}
+
+static NTSTATUS gp_cli_connect(struct gp_context *gp_ctx)
+{
+       struct smbcli_options options;
+        struct smbcli_session_options session_options;
+
+       if (gp_ctx->cli != NULL)
+               return NT_STATUS_OK;
+
+       gp_ctx->cli = smbcli_state_init(gp_ctx);
+
+       lp_smbcli_options(gp_ctx->lp_ctx, &options);
+       lp_smbcli_session_options(gp_ctx->lp_ctx, &session_options);
+
+
+       return smbcli_full_connection(gp_ctx,
+                       &gp_ctx->cli,
+                       gp_ctx->active_dc.name,
+                       lp_smb_ports(gp_ctx->lp_ctx),
+                       "sysvol",
+                       NULL,
+                       lp_socket_options(gp_ctx->lp_ctx),
+                       gp_ctx->credentials,
+                       lp_resolve_context(gp_ctx->lp_ctx),
+                       gp_ctx->ev_ctx,
+                       &options,
+                       &session_options,
+                       lp_iconv_convenience(gp_ctx->lp_ctx),
+                       lp_gensec_settings(gp_ctx, gp_ctx->lp_ctx));
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS gp_fetch_gpo (struct gp_context *gp_ctx, struct gp_object *gpo, const char **ret_local_path)
+{
+       TALLOC_CTX *mem_ctx;
+       struct gp_list_state *state;
+       NTSTATUS status;
+       unsigned int i, bkslash_cnt;
+       struct stat st;
+       int rv;
+
+       /* Create a forked memory context, as a base for everything here */
+       mem_ctx = talloc_new(gp_ctx);
+
+
+       if (gp_ctx->cli == NULL) {
+               status = gp_cli_connect(gp_ctx);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("Failed to create cli connection to DC\n"));
+                       talloc_free(mem_ctx);
+                       return status;
+               }
+       }
+
+       /* Prepare the state structure */
+       state = talloc_zero(mem_ctx, struct gp_list_state);
+       state->gp_ctx = gp_ctx;
+       state->local_path = talloc_asprintf(gp_ctx, "%s/%s", gp_tmpdir(mem_ctx), gpo->name);
+
+       /* Get the path from the share down (\\..\..\(this\stuff) */
+       for (i = 0, bkslash_cnt = 0; gpo->file_sys_path[i] != '\0'; i++) {
+               if (gpo->file_sys_path[i] == '\\')
+                       bkslash_cnt++;
+
+               if (bkslash_cnt == 4) {
+                       state->share_path = talloc_strdup(mem_ctx, &gpo->file_sys_path[i]);
+                       break;
+               }
+       }
+
+       /* Create the GPO dir if it does not exist */
+       if (stat(state->local_path, &st) != 0) {
+               rv = mkdir(state->local_path, 755);
+               if (rv < 0) {
+                       DEBUG(0, ("Could not create local path\n"));
+                       talloc_free(mem_ctx);
+                       return NT_STATUS_UNSUCCESSFUL;
+               }
+       }
+
+       /* Copy the files */
+       status = gp_do_list("", state);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("Could not list GPO files on remote server\n"));
+               talloc_free(mem_ctx);
+               return status;
+       }
+
+       /* Return the local path to the gpo */
+       *ret_local_path = state->local_path;
+
+       talloc_free(mem_ctx);
+       return NT_STATUS_OK;
+}
index f8806e964300855162b2f011f78c02371464bc48..a7d5eb6158f03185c7ec63e880c49018ada133fe 100644 (file)
@@ -160,14 +160,16 @@ NTSTATUS gp_init(TALLOC_CTX *mem_ctx,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       /* We don't need to keep the libnet context */
-       talloc_free(net_ctx);
 
        *gp_ctx = talloc_zero(mem_ctx, struct gp_context);
        (*gp_ctx)->lp_ctx = lp_ctx;
        (*gp_ctx)->credentials = credentials;
        (*gp_ctx)->ev_ctx = ev_ctx;
        (*gp_ctx)->ldb_ctx = ldb_ctx;
+       (*gp_ctx)->active_dc = io->out.dcs[0];
+
+       /* We don't need to keep the libnet context */
+       talloc_free(net_ctx);
        return NT_STATUS_OK;
 }
 
index 2811abf608d560b4cbedb57f5ff2da6059780c4a..c02253f3775c1a71d5e99aab62e5b8a549b75642 100644 (file)
@@ -20,7 +20,7 @@
 
 #ifndef __GPO_H__
 #define __GPO_H__
-
+#include "libcli/libcli.h"
 
 #define GPLINK_OPT_DISABLE             (1 << 0)
 #define GPLINK_OPT_ENFORCE             (1 << 1)
@@ -41,6 +41,8 @@ struct gp_context {
        struct loadparm_context *lp_ctx;
        struct cli_credentials *credentials;
        struct tevent_context *ev_ctx;
+       struct smbcli_state *cli;
+       struct nbt_dc_name active_dc;
 };
 
 struct gp_object {
@@ -70,6 +72,8 @@ NTSTATUS gp_init(TALLOC_CTX *mem_ctx,
                                struct cli_credentials *creds,
                                struct tevent_context *ev_ctx,
                                struct gp_context **gp_ctx);
+
+/* LDAP functions */
 NTSTATUS gp_list_all_gpos(struct gp_context *gp_ctx, struct gp_object ***ret);
 NTSTATUS gp_get_gplinks(struct gp_context *gp_ctx, const char *req_dn, struct gp_link ***ret);
 NTSTATUS gp_list_gpos(struct gp_context *gp_ctx, struct security_token *token, const char ***ret);
@@ -87,4 +91,7 @@ NTSTATUS gp_del_gplink(struct gp_context *gp_ctx, const char *dn_str, const char
 NTSTATUS gp_get_inheritance(struct gp_context *gp_ctx, const char *dn_str, enum gpo_inheritance *inheritance);
 NTSTATUS gp_set_inheritance(struct gp_context *gp_ctx, const char *dn_str, enum gpo_inheritance inheritance);
 
+/* File system functions */
+NTSTATUS gp_fetch_gpo (struct gp_context *gp_ctx, struct gp_object *gpo, const char **path);
+
 #endif
index 8575f902dd0dd8955cd45334097ceedc863ddcda..d47be384cba3872a2ca58314a631bb604730f1e7 100644 (file)
@@ -1,7 +1,7 @@
 #!/usr/bin/env python
 
 bld.SAMBA_LIBRARY('policy',
-       source='gp_ldap.c',
+       source='gp_ldap.c gp_filesys.c',
        pc_files='policy.pc',
        public_deps='LIBLDB LIBSAMBA-NET',
        public_headers='policy.h',
index bfcb0f0ad297590d316d8e84de6e6583501597b2..386c48662a9286e046d771d0f6103725e98d3c5f 100644 (file)
@@ -440,6 +440,35 @@ static int net_gpo_inheritance_set(struct net_context *ctx, int argc, const char
        return 0;
 }
 
+static int net_gpo_fetch(struct net_context *ctx, int argc, const char **argv)
+{
+       struct gp_context *gp_ctx;
+       struct gp_object *gpo;
+       const char *path;
+       NTSTATUS rv;
+
+       rv = gp_init(ctx, ctx->lp_ctx, ctx->credentials, ctx->event_ctx, &gp_ctx);
+       if (!NT_STATUS_IS_OK(rv)) {
+               DEBUG(0, ("Failed to connect to DC's LDAP: %s\n", get_friendly_nt_error_msg(rv)));
+               return 1;
+       }
+
+       rv = gp_get_gpo_info(gp_ctx, argv[0], &gpo);
+       if (!NT_STATUS_IS_OK(rv)) {
+               DEBUG(0, ("Failed to get GPO: %s\n", get_friendly_nt_error_msg(rv)));
+               return 1;
+       }
+
+       rv = gp_fetch_gpo(gp_ctx, gpo, &path);
+       if (!NT_STATUS_IS_OK(rv)) {
+               DEBUG(0, ("Failed to fetch GPO: %s\n", get_friendly_nt_error_msg(rv)));
+               return 1;
+       }
+       d_printf("%s\n", path);
+
+       return 0;
+}
+
 static const struct net_functable net_gpo_functable[] = {
        { "listall", "List all GPO's on a DC\n", net_gpo_list_all, net_gpo_list_all_usage },
        { "getgpo", "List specificied GPO\n", net_gpo_get_gpo, net_gpo_get_gpo_usage },
@@ -449,6 +478,7 @@ static const struct net_functable net_gpo_functable[] = {
        { "getinheritance", "Get inheritance flag from a container\n", net_gpo_inheritance_get, net_gpo_inheritance_get_usage },
        { "setinheritance", "Set inheritance flag on a container\n", net_gpo_inheritance_set, net_gpo_inheritance_set_usage },
        { "list", "List all GPO's for a machine/user\n", net_gpo_list, net_gpo_list_usage },
+       { "fetch", "Download a GPO\n", net_gpo_fetch, net_gpo_usage },
 /*     { "apply", "Apply GPO to container\n", net_gpo_apply, net_gpo_usage }, */
 //     { "refresh", "List all GPO's for machine/user and download them\n", net_gpo_refresh, net_gpo_refresh_usage },
        { NULL, NULL }