From 3b11a53304df29ebe2f2bfdeb5a6f0bf66553013 Mon Sep 17 00:00:00 2001 From: Wilco Baan Hofman Date: Tue, 27 Apr 2010 21:06:11 +0200 Subject: Add fetch function for GPO which fetches all relevant files from the sysvol share. Signed-off-by: Jelmer Vernooij --- source4/lib/policy/gp_filesys.c | 263 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 source4/lib/policy/gp_filesys.c (limited to 'source4/lib/policy/gp_filesys.c') diff --git a/source4/lib/policy/gp_filesys.c b/source4/lib/policy/gp_filesys.c new file mode 100644 index 0000000000..bb42fa2984 --- /dev/null +++ b/source4/lib/policy/gp_filesys.c @@ -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 . + */ +#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 +#include + +#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; +} -- cgit