LCOV - code coverage report
Current view: top level - src - bfile.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 51 98 52.0 %
Date: 2025-12-23 21:59:50 Functions: 9 11 81.8 %

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

Generated by: LCOV version 1.16