1/* 2 * Unix SMB/CIFS implementation. 3 * Group Policy Object Support 4 * Copyright (C) Guenther Deschner 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 3 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, see <http://www.gnu.org/licenses/>. 18 */ 19 20#include "includes.h" 21 22struct sync_context { 23 TALLOC_CTX *mem_ctx; 24 struct cli_state *cli; 25 char *remote_path; 26 char *local_path; 27 char *mask; 28 uint16_t attribute; 29}; 30 31static void gpo_sync_func(const char *mnt, 32 file_info *info, 33 const char *mask, 34 void *state); 35 36NTSTATUS gpo_copy_file(TALLOC_CTX *mem_ctx, 37 struct cli_state *cli, 38 const char *nt_path, 39 const char *unix_path) 40{ 41 NTSTATUS result; 42 uint16_t fnum; 43 int fd = -1; 44 char *data = NULL; 45 static int io_bufsize = 64512; 46 int read_size = io_bufsize; 47 off_t nread = 0; 48 49 result = cli_open(cli, nt_path, O_RDONLY, DENY_NONE, &fnum); 50 if (!NT_STATUS_IS_OK(result)) { 51 goto out; 52 } 53 54 if ((fd = sys_open(unix_path, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1) { 55 result = map_nt_error_from_unix(errno); 56 goto out; 57 } 58 59 if ((data = (char *)SMB_MALLOC(read_size)) == NULL) { 60 result = NT_STATUS_NO_MEMORY; 61 goto out; 62 } 63 64 while (1) { 65 66 int n = cli_read(cli, fnum, data, nread, read_size); 67 68 if (n <= 0) 69 break; 70 71 if (write(fd, data, n) != n) { 72 break; 73 } 74 75 nread += n; 76 } 77 78 result = NT_STATUS_OK; 79 80 out: 81 SAFE_FREE(data); 82 if (fnum) { 83 cli_close(cli, fnum); 84 } 85 if (fd != -1) { 86 close(fd); 87 } 88 89 return result; 90} 91 92/**************************************************************** 93 copy dir 94****************************************************************/ 95 96static NTSTATUS gpo_copy_dir(const char *unix_path) 97{ 98 if ((mkdir(unix_path, 0644)) < 0 && errno != EEXIST) { 99 return NT_STATUS_ACCESS_DENIED; 100 } 101 102 return NT_STATUS_OK; 103} 104 105/**************************************************************** 106 sync files 107****************************************************************/ 108 109static bool gpo_sync_files(struct sync_context *ctx) 110{ 111 DEBUG(3,("calling cli_list with mask: %s\n", ctx->mask)); 112 113 if (cli_list(ctx->cli, 114 ctx->mask, 115 ctx->attribute, 116 gpo_sync_func, 117 ctx) == -1) { 118 DEBUG(1,("listing [%s] failed with error: %s\n", 119 ctx->mask, cli_errstr(ctx->cli))); 120 return false; 121 } 122 123 return true; 124} 125 126/**************************************************************** 127 syncronisation call back 128****************************************************************/ 129 130static void gpo_sync_func(const char *mnt, 131 file_info *info, 132 const char *mask, 133 void *state) 134{ 135 NTSTATUS result; 136 struct sync_context *ctx; 137 fstring nt_filename, unix_filename; 138 fstring nt_dir, unix_dir; 139 char *old_nt_dir, *old_unix_dir; 140 141 ctx = (struct sync_context *)state; 142 143 if (strequal(info->name, ".") || strequal(info->name, "..")) { 144 return; 145 } 146 147 DEBUG(5,("gpo_sync_func: got mask: [%s], name: [%s]\n", 148 mask, info->name)); 149 150 if (info->mode & aDIR) { 151 152 DEBUG(3,("got dir: [%s]\n", info->name)); 153 154 fstrcpy(nt_dir, ctx->remote_path); 155 fstrcat(nt_dir, "\\"); 156 fstrcat(nt_dir, info->name); 157 158 fstrcpy(unix_dir, ctx->local_path); 159 fstrcat(unix_dir, "/"); 160 fstrcat(unix_dir, info->name); 161 162 result = gpo_copy_dir(unix_dir); 163 if (!NT_STATUS_IS_OK(result)) { 164 DEBUG(1,("failed to copy dir: %s\n", 165 nt_errstr(result))); 166 } 167 168 old_nt_dir = ctx->remote_path; 169 ctx->remote_path = talloc_strdup(ctx->mem_ctx, nt_dir); 170 171 old_unix_dir = ctx->local_path; 172 ctx->local_path = talloc_strdup(ctx->mem_ctx, unix_dir); 173 174 ctx->mask = talloc_asprintf(ctx->mem_ctx, 175 "%s\\*", 176 nt_dir); 177 if (!ctx->local_path || !ctx->mask || !ctx->remote_path) { 178 DEBUG(0,("gpo_sync_func: ENOMEM\n")); 179 return; 180 } 181 if (!gpo_sync_files(ctx)) { 182 DEBUG(0,("could not sync files\n")); 183 } 184 185 ctx->remote_path = old_nt_dir; 186 ctx->local_path = old_unix_dir; 187 return; 188 } 189 190 DEBUG(3,("got file: [%s]\n", info->name)); 191 192 fstrcpy(nt_filename, ctx->remote_path); 193 fstrcat(nt_filename, "\\"); 194 fstrcat(nt_filename, info->name); 195 196 fstrcpy(unix_filename, ctx->local_path); 197 fstrcat(unix_filename, "/"); 198 fstrcat(unix_filename, info->name); 199 200 result = gpo_copy_file(ctx->mem_ctx, ctx->cli, 201 nt_filename, unix_filename); 202 if (!NT_STATUS_IS_OK(result)) { 203 DEBUG(1,("failed to copy file: %s\n", 204 nt_errstr(result))); 205 } 206} 207 208 209/**************************************************************** 210 list a remote directory and download recursivly 211****************************************************************/ 212 213NTSTATUS gpo_sync_directories(TALLOC_CTX *mem_ctx, 214 struct cli_state *cli, 215 const char *nt_path, 216 const char *local_path) 217{ 218 struct sync_context ctx; 219 220 ctx.mem_ctx = mem_ctx; 221 ctx.cli = cli; 222 ctx.remote_path = CONST_DISCARD(char *, nt_path); 223 ctx.local_path = CONST_DISCARD(char *, local_path); 224 ctx.attribute = (aSYSTEM | aHIDDEN | aDIR); 225 226 ctx.mask = talloc_asprintf(mem_ctx, 227 "%s\\*", 228 nt_path); 229 if (!ctx.mask) { 230 return NT_STATUS_NO_MEMORY; 231 } 232 233 if (!gpo_sync_files(&ctx)) { 234 return NT_STATUS_NO_SUCH_FILE; 235 } 236 237 return NT_STATUS_OK; 238} 239