diff options
-rw-r--r-- | source4/lib/policy/config.mk | 2 | ||||
-rw-r--r-- | source4/lib/policy/gp_filesys.c | 263 | ||||
-rw-r--r-- | source4/lib/policy/gp_ldap.c | 6 | ||||
-rw-r--r-- | source4/lib/policy/policy.h | 9 | ||||
-rw-r--r-- | source4/lib/policy/wscript_build | 2 | ||||
-rw-r--r-- | source4/utils/net/net_gpo.c | 30 |
6 files changed, 307 insertions, 5 deletions
diff --git a/source4/lib/policy/config.mk b/source4/lib/policy/config.mk index 01bd1f4f28..74403f8565 100644 --- a/source4/lib/policy/config.mk +++ b/source4/lib/policy/config.mk @@ -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 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 <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; +} diff --git a/source4/lib/policy/gp_ldap.c b/source4/lib/policy/gp_ldap.c index f8806e9643..a7d5eb6158 100644 --- a/source4/lib/policy/gp_ldap.c +++ b/source4/lib/policy/gp_ldap.c @@ -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; } diff --git a/source4/lib/policy/policy.h b/source4/lib/policy/policy.h index 2811abf608..c02253f377 100644 --- a/source4/lib/policy/policy.h +++ b/source4/lib/policy/policy.h @@ -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 diff --git a/source4/lib/policy/wscript_build b/source4/lib/policy/wscript_build index 8575f902dd..d47be384cb 100644 --- a/source4/lib/policy/wscript_build +++ b/source4/lib/policy/wscript_build @@ -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', diff --git a/source4/utils/net/net_gpo.c b/source4/utils/net/net_gpo.c index bfcb0f0ad2..386c48662a 100644 --- a/source4/utils/net/net_gpo.c +++ b/source4/utils/net/net_gpo.c @@ -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 } |