1 #include "burp.h"
2 #include "alloc.h"
3 #include "attribs.h"
4 #include "berrno.h"
5 #include "bfile.h"
6 #include "log.h"
7 
8 #ifdef HAVE_DARWIN_OS
9 #include <sys/paths.h>
10 #endif
11 
bfile_free(struct BFILE ** bfd)12 void bfile_free(struct BFILE **bfd)
13 {
14 	free_v((void **)bfd);
15 }
16 
17 #ifdef HAVE_WIN32
18 static ssize_t bfile_write_windows(struct BFILE *bfd, void *buf, size_t count);
19 #endif
20 
21 #define min(a,b) \
22    ({ __typeof__ (a) _a = (a); \
23        __typeof__ (b) _b = (b); \
24      _a < _b ? _a : _b; })
25 
setup_vss_strip(struct BFILE * bfd)26 static void setup_vss_strip(struct BFILE *bfd)
27 {
28 	memset(&bfd->mysid, 0, sizeof(struct mysid));
29 	bfd->mysid.needed_s=bsidsize;
30 }
31 
bfile_write_vss_strip(struct BFILE * bfd,void * buf,size_t count)32 static ssize_t bfile_write_vss_strip(struct BFILE *bfd, void *buf, size_t count)
33 {
34 	size_t mycount;
35 	struct mysid *mysid;
36 	struct bsid *sid;
37 
38 	mysid=&bfd->mysid;
39 	sid=&mysid->sid;
40 	char *cp=(char *)buf;
41 	mycount=count;
42 
43 	while(mycount)
44 	{
45 		if(mysid->needed_s)
46 		{
47 			size_t sidlen=bsidsize-mysid->needed_s;
48 			int got=min(mysid->needed_s, mycount);
49 
50 			memcpy(sid+sidlen, cp, got);
51 
52 			cp+=got;
53 			mycount-=got;
54 			mysid->needed_s-=got;
55 
56 			if(!mysid->needed_s)
57 				mysid->needed_d=sid->Size+sid->dwStreamNameSize;
58 		}
59 		if(mysid->needed_d)
60 		{
61 			size_t wrote;
62 			int got=min(mysid->needed_d, mycount);
63 
64 			if(sid->dwStreamId==1)
65 			{
66 #ifdef HAVE_WIN32
67 				if((wrote=bfile_write_windows(bfd,
68 					cp, got))<=0)
69 						return -1;
70 #else
71 				if((wrote=write(bfd->fd,
72 					cp, got))<=0)
73 						return -1;
74 #endif
75 			}
76 			else
77 				wrote=got;
78 
79 			cp+=wrote;
80 			mycount-=wrote;
81 			mysid->needed_d-=wrote;
82 			if(!mysid->needed_d)
83 				mysid->needed_s=bsidsize;
84 		}
85 	}
86 
87 	return count;
88 }
89 
90 #ifdef HAVE_WIN32
91 
92 char *unix_name_to_win32(char *name);
93 extern "C" HANDLE get_osfhandle(int fd);
94 
bfile_set_win32_api(struct BFILE * bfd,int on)95 static void bfile_set_win32_api(struct BFILE *bfd, int on)
96 {
97 	if(have_win32_api() && on)
98 		bfd->use_backup_api=1;
99 	else
100 		bfd->use_backup_api=0;
101 }
102 
have_win32_api(void)103 int have_win32_api(void)
104 {
105 	return p_BackupRead && p_BackupWrite;
106 }
107 
108 // Windows flags for the OpenEncryptedFileRaw functions
109 #define CREATE_FOR_EXPORT	0
110 // These are already defined
111 //#define CREATE_FOR_IMPORT	1
112 //#define CREATE_FOR_DIR	2
113 //#define OVERWRITE_HIDDEN	4
114 
115 // Return 0 for success, non zero for error.
bfile_open_encrypted(struct BFILE * bfd,const char * fname,int flags,mode_t mode)116 static int bfile_open_encrypted(struct BFILE *bfd,
117 	const char *fname, int flags, mode_t mode)
118 {
119 	ULONG ulFlags=0;
120 	char *win32_fname=NULL;
121 	char *win32_fname_wchar=NULL;
122 
123 	bfd->mode=BF_CLOSED;
124 	if(!(win32_fname_wchar=make_win32_path_UTF8_2_wchar_w(fname)))
125 	{
126 		logp("could not get widename!");
127 		goto end;
128 	}
129 	if(!(win32_fname=unix_name_to_win32((char *)fname)))
130 	{
131 		logp("could not get win32_fname of %s!", fname);
132 		goto end;
133 	}
134 
135 	if((flags & O_CREAT) /* Create */
136 	  || (flags & O_WRONLY)) /* Open existing for write */
137 	{
138 		ulFlags |= CREATE_FOR_IMPORT;
139 		ulFlags |= OVERWRITE_HIDDEN;
140 		if(bfd->winattr & FILE_ATTRIBUTE_DIRECTORY)
141 		{
142 			mkdir(fname, 0777);
143 			ulFlags |= CREATE_FOR_DIR;
144 		}
145 	}
146 	else
147 	{
148 		/* Open existing for read */
149 		ulFlags=CREATE_FOR_EXPORT;
150 	}
151 
152 	if(p_OpenEncryptedFileRawW((LPCWSTR)win32_fname_wchar,
153 		ulFlags, &(bfd->pvContext)))
154 			bfd->mode=BF_CLOSED;
155 	else
156 		bfd->mode=BF_READ;
157 
158 end:
159 	free_w(&win32_fname_wchar);
160 	free_w(&win32_fname);
161 	return bfd->mode==BF_CLOSED;
162 }
163 
bfile_error(struct BFILE * bfd)164 static int bfile_error(struct BFILE *bfd)
165 {
166 	if(bfd)
167 	{
168 		bfd->lerror=GetLastError();
169 		bfd->berrno=b_errno_win32;
170 	}
171 	errno=b_errno_win32;
172 	return -1;
173 }
174 
175 // Return 0 for success, non zero for error.
bfile_open(struct BFILE * bfd,struct asfd * asfd,const char * fname,int flags,mode_t mode)176 static int bfile_open(struct BFILE *bfd, struct asfd *asfd,
177 	const char *fname, int flags, mode_t mode)
178 {
179 	DWORD dwaccess;
180 	DWORD dwflags;
181 	DWORD dwshare;
182 	char *win32_fname=NULL;
183 	char *win32_fname_wchar=NULL;
184 
185 	bfd->mode=BF_CLOSED;
186 
187 	if(bfd->winattr & FILE_ATTRIBUTE_ENCRYPTED)
188 		return bfile_open_encrypted(bfd, fname, flags, mode);
189 
190 	if(!(win32_fname=unix_name_to_win32((char *)fname)))
191 	{
192 		logp("could not get win32_fname of %s!\n", fname);
193 		goto end;
194 	}
195 	if(!(win32_fname_wchar=make_win32_path_UTF8_2_wchar_w(fname)))
196 	{
197 		logp("could not get widename!");
198 		goto end;
199 	}
200 
201 	if(flags & O_CREAT)
202 	{
203 		/* Create */
204 
205 		if(bfd->winattr & FILE_ATTRIBUTE_DIRECTORY)
206 			mkdir(fname, 0777);
207 
208 		if(bfd->use_backup_api)
209 		{
210 			dwaccess=GENERIC_WRITE
211 				| FILE_ALL_ACCESS
212 				| WRITE_OWNER
213 				| WRITE_DAC
214 				| ACCESS_SYSTEM_SECURITY;
215 			dwflags=FILE_FLAG_BACKUP_SEMANTICS;
216 		}
217 		else
218 		{
219 			dwaccess=GENERIC_WRITE;
220 			dwflags=0;
221 		}
222 
223 		// unicode open for create write
224 		bfd->fh=p_CreateFileW((LPCWSTR)win32_fname_wchar,
225 			dwaccess,      /* Requested access */
226 			0,             /* Shared mode */
227 			NULL,          /* SecurityAttributes */
228 			CREATE_ALWAYS, /* CreationDisposition */
229 			dwflags,       /* Flags and attributes */
230 			NULL);         /* TemplateFile */
231 
232 		bfd->mode=BF_WRITE;
233 	}
234 	else if(flags & O_WRONLY)
235 	{
236 		/* Open existing for write */
237 		if(bfd->use_backup_api)
238 		{
239 			dwaccess=GENERIC_WRITE
240 				| WRITE_OWNER
241 				| WRITE_DAC;
242 			dwflags=FILE_FLAG_BACKUP_SEMANTICS
243 				| FILE_FLAG_OPEN_REPARSE_POINT;
244 		}
245 		else
246 		{
247 			dwaccess=GENERIC_WRITE;
248 			dwflags=0;
249 		}
250 
251 		// unicode open for open existing write
252 		bfd->fh=p_CreateFileW((LPCWSTR)win32_fname_wchar,
253 			dwaccess,      /* Requested access */
254 			0,             /* Shared mode */
255 			NULL,          /* SecurityAttributes */
256 			OPEN_EXISTING, /* CreationDisposition */
257 			dwflags,       /* Flags and attributes */
258 			NULL);         /* TemplateFile */
259 
260 		bfd->mode=BF_WRITE;
261 	}
262 	else
263 	{
264 		/* Read */
265 		if(bfd->use_backup_api)
266 		{
267 			dwaccess=GENERIC_READ|READ_CONTROL
268 				| ACCESS_SYSTEM_SECURITY;
269 			dwflags=FILE_FLAG_BACKUP_SEMANTICS
270 				| FILE_FLAG_SEQUENTIAL_SCAN
271 				| FILE_FLAG_OPEN_REPARSE_POINT;
272 			dwshare=FILE_SHARE_READ
273 				| FILE_SHARE_WRITE
274 				| FILE_SHARE_DELETE;
275 		}
276 		else
277 		{
278 			dwaccess=GENERIC_READ;
279 			dwflags=0;
280 			dwshare=FILE_SHARE_READ
281 				| FILE_SHARE_WRITE;
282 		}
283 
284 		// unicode open for open existing read
285 		bfd->fh=p_CreateFileW((LPCWSTR)win32_fname_wchar,
286 			dwaccess,      /* Requested access */
287 			dwshare,       /* Share modes */
288 			NULL,          /* SecurityAttributes */
289 			OPEN_EXISTING, /* CreationDisposition */
290 			dwflags,       /* Flags and attributes */
291 			NULL);         /* TemplateFile */
292 
293 		bfd->mode=BF_READ;
294 	}
295 
296 	if(bfd->fh==INVALID_HANDLE_VALUE)
297 	{
298 		bfile_error(bfd);
299 		bfd->mode=BF_CLOSED;
300 	}
301 	else
302 	{
303 		free_w(&bfd->path);
304 		if(!(bfd->path=strdup_w(fname, __func__)))
305 			goto end;
306 	}
307 end:
308 	bfd->lpContext=NULL;
309 	free_w(&win32_fname_wchar);
310 	free_w(&win32_fname);
311 
312 	if(bfd->vss_strip)
313 		setup_vss_strip(bfd);
314 
315 	return bfd->mode==BF_CLOSED;
316 }
317 
bfile_close_encrypted(struct BFILE * bfd,struct asfd * asfd)318 static int bfile_close_encrypted(struct BFILE *bfd, struct asfd *asfd)
319 {
320 	CloseEncryptedFileRaw(bfd->pvContext);
321 	if(bfd->mode==BF_WRITE && bfd->set_attribs_on_close)
322 		attribs_set(asfd,
323 			bfd->path, &bfd->statp, bfd->winattr, bfd->cntr);
324 	bfd->pvContext=NULL;
325 	bfd->mode=BF_CLOSED;
326 	free_w(&bfd->path);
327 	return 0;
328 }
329 
330 // Return 0 on success, -1 on error.
bfile_close(struct BFILE * bfd,struct asfd * asfd)331 static int bfile_close(struct BFILE *bfd, struct asfd *asfd)
332 {
333 	int ret=-1;
334 
335 	if(!bfd) return 0;
336 
337 	if(bfd->mode==BF_CLOSED)
338 	{
339 		ret=0;
340 		goto end;
341 	}
342 
343 	if(bfd->winattr & FILE_ATTRIBUTE_ENCRYPTED)
344 		return bfile_close_encrypted(bfd, asfd);
345 
346 	/*
347 	 * We need to tell the API to release the buffer it
348 	 * allocated in lpContext.  We do so by calling the
349 	 * API one more time, but with the Abort bit set.
350 	 */
351 	if(bfd->use_backup_api && bfd->mode==BF_READ)
352 	{
353 		BYTE buf[10];
354 		if(bfd->lpContext
355 		  && !p_BackupRead(bfd->fh,
356 			buf,              /* buffer */
357 			(DWORD)0,         /* bytes to read */
358 			&bfd->rw_bytes,   /* bytes read */
359 			1,                /* Abort */
360 			1,                /* ProcessSecurity */
361 			&bfd->lpContext)) /* Read context */
362 		{
363 			bfile_error(NULL);
364 			goto end;
365 		}
366 	}
367 	else if(bfd->use_backup_api && bfd->mode==BF_WRITE)
368 	{
369 		BYTE buf[10];
370 		if(bfd->lpContext
371 		  && !p_BackupWrite(bfd->fh,
372 			buf,              /* buffer */
373 			(DWORD)0,         /* bytes to read */
374 			&bfd->rw_bytes,   /* bytes written */
375 			1,                /* Abort */
376 			1,                /* ProcessSecurity */
377 			&bfd->lpContext)) /* Write context */
378 		{
379 			bfile_error(NULL);
380 			goto end;
381 		}
382 	}
383 	if(!CloseHandle(bfd->fh))
384 	{
385 		bfile_error(NULL);
386 		goto end;
387 	}
388 
389 	if(bfd->mode==BF_WRITE && bfd->set_attribs_on_close)
390 		attribs_set(asfd,
391 			bfd->path, &bfd->statp, bfd->winattr, bfd->cntr);
392 	bfd->lpContext=NULL;
393 	bfd->mode=BF_CLOSED;
394 
395 	ret=0;
396 end:
397 	free_w(&bfd->path);
398 	return ret;
399 }
400 
401 // Returns: bytes read on success, or 0 on EOF, -1 on error.
bfile_read(struct BFILE * bfd,void * buf,size_t count)402 static ssize_t bfile_read(struct BFILE *bfd, void *buf, size_t count)
403 {
404 	bfd->rw_bytes=0;
405 
406 	if(bfd->use_backup_api)
407 	{
408 		if(!p_BackupRead(bfd->fh,
409 			(BYTE *)buf,
410 			count,
411 			&bfd->rw_bytes,
412 			0,                /* no Abort */
413 			1,                /* Process Security */
414 			&bfd->lpContext)) /* Context */
415 				return bfile_error(bfd);
416 	}
417 	else
418 	{
419 		if(!ReadFile(bfd->fh,
420 			buf,
421 			count,
422 			&bfd->rw_bytes,
423 			NULL))
424 				return bfile_error(bfd);
425 	}
426 
427 	return (ssize_t)bfd->rw_bytes;
428 }
429 
bfile_write_windows(struct BFILE * bfd,void * buf,size_t count)430 static ssize_t bfile_write_windows(struct BFILE *bfd, void *buf, size_t count)
431 {
432 	bfd->rw_bytes = 0;
433 
434 	if(bfd->use_backup_api)
435 	{
436 		if(!p_BackupWrite(bfd->fh,
437 			(BYTE *)buf,
438 			count,
439 			&bfd->rw_bytes,
440 			0,                /* No abort */
441 			1,                /* Process Security */
442 			&bfd->lpContext)) /* Context */
443 				return bfile_error(bfd);
444 	}
445 	else
446 	{
447 		if(!WriteFile(bfd->fh,
448 			buf,
449 			count,
450 			&bfd->rw_bytes,
451 			NULL))
452 				return bfile_error(bfd);
453 	}
454 	return (ssize_t)bfd->rw_bytes;
455 }
456 
bfile_write(struct BFILE * bfd,void * buf,size_t count)457 static ssize_t bfile_write(struct BFILE *bfd, void *buf, size_t count)
458 {
459 	if(bfd->vss_strip)
460 		return bfile_write_vss_strip(bfd, buf, count);
461 	return bfile_write_windows(bfd, buf, count);
462 }
463 
464 #else
465 
bfile_close(struct BFILE * bfd,struct asfd * asfd)466 static int bfile_close(struct BFILE *bfd, struct asfd *asfd)
467 {
468 	if(!bfd || bfd->mode==BF_CLOSED) return 0;
469 
470 	if(!close(bfd->fd))
471 	{
472 		if(bfd->mode==BF_WRITE && bfd->set_attribs_on_close)
473 			attribs_set(asfd, bfd->path,
474 				&bfd->statp, bfd->winattr, bfd->cntr);
475 		bfd->mode=BF_CLOSED;
476 		bfd->fd=-1;
477 		free_w(&bfd->path);
478 		return 0;
479 	}
480 	free_w(&bfd->path);
481 	return -1;
482 }
483 
bfile_open(struct BFILE * bfd,struct asfd * asfd,const char * fname,int flags,mode_t mode)484 static int bfile_open(struct BFILE *bfd,
485 	struct asfd *asfd, const char *fname, int flags, mode_t mode)
486 {
487 	if(!bfd) return 0;
488 	if(bfd->mode!=BF_CLOSED && bfd->close(bfd, asfd))
489 		return -1;
490 	if((bfd->fd=open(fname, flags, mode))<0)
491 		return -1;
492 	if(flags & O_CREAT || flags & O_WRONLY)
493 		bfd->mode=BF_WRITE;
494 	else
495 		bfd->mode=BF_READ;
496 	free_w(&bfd->path);
497 	if(!(bfd->path=strdup_w(fname, __func__)))
498 		return -1;
499 	if(bfd->vss_strip)
500 		setup_vss_strip(bfd);
501 	return 0;
502 }
503 
bfile_read(struct BFILE * bfd,void * buf,size_t count)504 static ssize_t bfile_read(struct BFILE *bfd, void *buf, size_t count)
505 {
506 	return read(bfd->fd, buf, count);
507 }
508 
bfile_write(struct BFILE * bfd,void * buf,size_t count)509 static ssize_t bfile_write(struct BFILE *bfd, void *buf, size_t count)
510 {
511 	if(bfd->vss_strip)
512 		return bfile_write_vss_strip(bfd, buf, count);
513 
514 	return write(bfd->fd, buf, count);
515 }
516 
517 #endif
518 
bfile_open_for_send(struct BFILE * bfd,struct asfd * asfd,const char * fname,int64_t winattr,int atime,struct cntr * cntr,enum protocol protocol)519 static int bfile_open_for_send(struct BFILE *bfd, struct asfd *asfd,
520 	const char *fname, int64_t winattr, int atime,
521 	struct cntr *cntr, enum protocol protocol)
522 {
523 	if(protocol==PROTO_1
524 	  && bfd->mode!=BF_CLOSED)
525 	{
526 #ifdef HAVE_WIN32
527 		if(bfd->path && !strcmp(bfd->path, fname))
528 		{
529 			// Already open after reading the VSS data.
530 			// Time now for the actual file data.
531 			return 0;
532 		}
533 		else
534 		{
535 #endif
536 			// Close the open bfd so that it can be
537 			// used again
538 			bfd->close(bfd, asfd);
539 #ifdef HAVE_WIN32
540 		}
541 #endif
542 	}
543 
544 	bfile_init(bfd, winattr, cntr);
545 	if(bfile_open(bfd, asfd, fname, O_RDONLY|O_BINARY
546 #ifdef O_NOFOLLOW
547 		|O_NOFOLLOW
548 #endif
549 #ifdef O_NOATIME
550 		|(atime?0:O_NOATIME)
551 #endif
552 		, 0))
553 	{
554 		struct berrno be;
555 		berrno_init(&be);
556 		logw(asfd, cntr,
557 			"Could not open %s: %s\n",
558 			fname, berrno_bstrerror(&be, errno));
559 		return -1;
560 	}
561 	return 0;
562 }
563 
bfile_set_vss_strip(struct BFILE * bfd,int on)564 static void bfile_set_vss_strip(struct BFILE *bfd, int on)
565 {
566 	bfd->vss_strip=on;
567 }
568 
bfile_setup_funcs(struct BFILE * bfd)569 void bfile_setup_funcs(struct BFILE *bfd)
570 {
571 	bfd->open=bfile_open;
572 	bfd->close=bfile_close;
573 	bfd->read=bfile_read;
574 	bfd->write=bfile_write;
575 	bfd->open_for_send=bfile_open_for_send;
576 #ifdef HAVE_WIN32
577 	bfd->set_win32_api=bfile_set_win32_api;
578 #endif
579 	bfd->set_vss_strip=bfile_set_vss_strip;
580 }
581 
bfile_init(struct BFILE * bfd,int64_t winattr,struct cntr * cntr)582 void bfile_init(struct BFILE *bfd, int64_t winattr, struct cntr *cntr)
583 {
584 	memset(bfd, 0, sizeof(struct BFILE));
585 	bfd->mode=BF_CLOSED;
586 	bfd->winattr=winattr;
587 	bfd->cntr=cntr;
588 	if(!bfd->open) bfile_setup_funcs(bfd);
589 #ifdef HAVE_WIN32
590 	bfile_set_win32_api(bfd, 1);
591 #else
592 	bfd->fd=-1;
593 #endif
594 }
595 
bfile_alloc(void)596 struct BFILE *bfile_alloc(void)
597 {
598 	return (struct BFILE *)calloc_w(1, sizeof(struct BFILE), __func__);
599 }
600