LCOV - code coverage report
Current view: top level - src - attribs.c (source / functions) Hit Total Coverage
Test: burp-coverage-clean.info Lines: 139 163 85.3 %
Date: 2021-07-02 04:40:54 Functions: 5 6 83.3 %

          Line data    Source code
       1             : /*
       2             :    Bacula® - The Network Backup Solution
       3             : 
       4             :    Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
       5             : 
       6             :    The main author of Bacula is Kern Sibbald, with contributions from
       7             :    many others, a complete list can be found in the file AUTHORS.
       8             :    This program is Free Software; you can redistribute it and/or
       9             :    modify it under the terms of version three of the GNU Affero General Public
      10             :    License as published by the Free Software Foundation and included
      11             :    in the file LICENSE.
      12             : 
      13             :    This program is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :    General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU Affero General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :    02110-1301, USA.
      22             : 
      23             :    Bacula® is a registered trademark of Kern Sibbald.
      24             :    The licensor of Bacula is the Free Software Foundation Europe
      25             :    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
      26             :    Switzerland, email:ftf@fsfeurope.org.
      27             : */
      28             : /*
      29             :  *  Encode and decode standard Unix attributes and
      30             :  *   Extended attributes for Win32 and
      31             :  *   other non-Unix systems, ...
      32             :  */
      33             : /*
      34             :  *  Some of these functions come from src/findlib/attribs.c in bacula-5.0.3.
      35             :  *  Hence, the copyright notice above is retained.
      36             :  *   Graham Keeling, 2014
      37             :  */
      38             : 
      39             : #include "burp.h"
      40             : #include "attribs.h"
      41             : #include "alloc.h"
      42             : #include "base64.h"
      43             : #include "berrno.h"
      44             : #include "cmd.h"
      45             : #include "cntr.h"
      46             : #include "log.h"
      47             : #include "sbuf.h"
      48             : 
      49             : // Encode a stat structure into a base64 character string.
      50       95380 : int attribs_encode(struct sbuf *sb)
      51             : {
      52             :         static char *p;
      53             :         static struct stat *statp;
      54             : 
      55       95380 :         if(!sb->attr.buf)
      56             :         {
      57       95255 :                 sb->attr.cmd=CMD_ATTRIBS; // should not be needed
      58       95255 :                 if(!(sb->attr.buf=(char *)malloc_w(256, __func__)))
      59             :                         return -1;
      60             :         }
      61       95380 :         p=sb->attr.buf;
      62       95380 :         statp=&sb->statp;
      63             : 
      64       95380 :         if(sb->protocol2)
      65             :         {
      66             :                 // Protocol1 does not have this field.
      67       73445 :                 p += to_base64(sb->protocol2->index, p);
      68       73445 :                 *p++ = ' ';
      69             :                 // Protocol2 puts compression/encryption near the beginning.
      70       73445 :                 p += to_base64(sb->compression, p);
      71       73445 :                 *p++ = ' ';
      72       73445 :                 p += to_base64(sb->encryption, p);
      73       73445 :                 *p++ = ' ';
      74             :         }
      75       95380 :         p += to_base64(statp->st_dev, p);
      76       95380 :         *p++ = ' ';
      77       95380 :         p += to_base64(statp->st_ino, p);
      78       95380 :         *p++ = ' ';
      79       95380 :         p += to_base64(statp->st_mode, p);
      80       95380 :         *p++ = ' ';
      81       95380 :         p += to_base64(statp->st_nlink, p);
      82       95380 :         *p++ = ' ';
      83       95380 :         p += to_base64(statp->st_uid, p);
      84       95380 :         *p++ = ' ';
      85       95380 :         p += to_base64(statp->st_gid, p);
      86       95380 :         *p++ = ' ';
      87       95380 :         p += to_base64(statp->st_rdev, p);
      88       95380 :         *p++ = ' ';
      89       95380 :         p += to_base64(statp->st_size, p);
      90       95380 :         *p++ = ' ';
      91             : #ifdef HAVE_WIN32
      92             :         p += to_base64(0, p); // place holder
      93             :         *p++ = ' ';
      94             :         p += to_base64(0, p); // place holder
      95             : #else
      96       95380 :         p += to_base64(statp->st_blksize, p);
      97       95380 :         *p++ = ' ';
      98       95380 :         p += to_base64(statp->st_blocks, p);
      99             : #endif
     100       95380 :         *p++ = ' ';
     101       95380 :         p += to_base64(statp->st_atime, p);
     102       95380 :         *p++ = ' ';
     103       95380 :         p += to_base64(statp->st_mtime, p);
     104       95380 :         *p++ = ' ';
     105       95380 :         p += to_base64(statp->st_ctime, p);
     106       95380 :         *p++ = ' ';
     107             : 
     108             : #ifdef HAVE_CHFLAGS
     109             :         // chflags is a FreeBSD function.
     110             :         p += to_base64(statp->st_flags, p);
     111             : #else
     112       95380 :         p += to_base64(0, p); // place holder
     113             : #endif
     114       95380 :         *p++ = ' ';
     115             : 
     116       95380 :         p += to_base64(sb->winattr, p);
     117             : 
     118       95380 :         if(sb->protocol1)
     119             :         {
     120             :                 // Protocol1 puts compression/encryption at the end.
     121       21935 :                 *p++ = ' ';
     122       21935 :                 p += to_base64(sb->compression, p);
     123       21935 :                 *p++ = ' ';
     124       21935 :                 p += to_base64(sb->encryption, p);
     125       21935 :                 *p++ = ' ';
     126       21935 :                 p += to_base64(sb->protocol1->salt, p);
     127             :         }
     128             : 
     129       95380 :         *p = 0;
     130             : 
     131       95380 :         sb->attr.len=p-sb->attr.buf;
     132             : 
     133       95380 :         return 0;
     134             : }
     135             : 
     136             : // Do casting according to unknown type to keep compiler happy.
     137             : #define plug(st, val) st = (__typeof__(st))(val)
     138             : 
     139             : // Decode a stat packet from base64 characters.
     140       80764 : void attribs_decode(struct sbuf *sb)
     141             : {
     142             :         static const char *p;
     143             :         static int64_t val;
     144             :         static struct stat *statp;
     145             :         static int eaten;
     146             : 
     147       80764 :         if(!(p=sb->attr.buf)) return;
     148       80764 :         statp=&sb->statp;
     149             : 
     150       80764 :         if(sb->protocol2)
     151             :         {
     152             :                 // In protocol2, the first component (index) sometimes gets
     153             :                 // stripped off of the attributes, so look out for that.
     154       57098 :                 if(*p!=' ')
     155             :                 {
     156             :                         // Protocol1 does not have this field.
     157       10024 :                         if(!(eaten=from_base64(&val, p)))
     158             :                                 return;
     159       10024 :                         p+=eaten;
     160       10024 :                         sb->protocol2->index=val;
     161             :                 }
     162             : 
     163             :                 // Compression for protocol2.
     164       57098 :                 if(!(eaten=from_base64(&val, p)))
     165             :                         return;
     166       57098 :                 p+=eaten;
     167       57098 :                 sb->compression=val;
     168             : 
     169             :                 // Encryption for protocol2.
     170       57098 :                 if(!(eaten=from_base64(&val, p)))
     171             :                         return;
     172       57097 :                 p+=eaten;
     173       57097 :                 sb->encryption=val;
     174             :         }
     175             : 
     176       80763 :         if(!(eaten=from_base64(&val, p)))
     177             :                 return;
     178       80753 :         p+=eaten;
     179       80753 :         plug(statp->st_dev, val);
     180             : 
     181       80753 :         if(!(eaten=from_base64(&val, p)))
     182             :                 return;
     183       80752 :         p+=eaten;
     184       80752 :         plug(statp->st_ino, val);
     185             : 
     186       80752 :         if(!(eaten=from_base64(&val, p)))
     187             :                 return;
     188       80743 :         p+=eaten;
     189       80743 :         plug(statp->st_mode, val);
     190             : 
     191       80743 :         if(!(eaten=from_base64(&val, p)))
     192             :                 return;
     193       80743 :         p+=eaten;
     194       80743 :         plug(statp->st_nlink, val);
     195             : 
     196       80743 :         if(!(eaten=from_base64(&val, p)))
     197             :                 return;
     198       80743 :         p+=eaten;
     199       80743 :         plug(statp->st_uid, val);
     200             : 
     201       80743 :         if(!(eaten=from_base64(&val, p)))
     202             :                 return;
     203       80743 :         p+=eaten;
     204       80743 :         plug(statp->st_gid, val);
     205             : 
     206       80743 :         if(!(eaten=from_base64(&val, p)))
     207             :                 return;
     208       80743 :         p+=eaten;
     209       80743 :         plug(statp->st_rdev, val);
     210             : 
     211       80743 :         if(!(eaten=from_base64(&val, p)))
     212             :                 return;
     213       80743 :         p+=eaten;
     214       80743 :         plug(statp->st_size, val);
     215             : 
     216       80743 :         if(!(eaten=from_base64(&val, p)))
     217             :                 return;
     218       80743 :         p+=eaten;
     219             : #ifdef HAVE_WIN32
     220             :         //   plug(statp->st_blksize, val);
     221             : 
     222             :         if(!(eaten=from_base64(&val, p)))
     223             :                 return;
     224             :         p+=eaten;
     225             :         //   plug(statp->st_blocks, val);
     226             : #else
     227       80743 :         plug(statp->st_blksize, val);
     228             : 
     229       80743 :         if(!(eaten=from_base64(&val, p)))
     230             :                 return;
     231       80743 :         p+=eaten;
     232       80743 :         plug(statp->st_blocks, val);
     233             : #endif
     234             : 
     235       80743 :         if(!(eaten=from_base64(&val, p)))
     236             :                 return;
     237       80743 :         p+=eaten;
     238       80743 :         plug(statp->st_atime, val);
     239             : 
     240       80743 :         if(!(eaten=from_base64(&val, p)))
     241             :                 return;
     242       80743 :         p+=eaten;
     243       80743 :         plug(statp->st_mtime, val);
     244             : 
     245       80743 :         if(!(eaten=from_base64(&val, p)))
     246             :                 return;
     247       80743 :         p+=eaten;
     248       80743 :         plug(statp->st_ctime, val);
     249             : 
     250             :         // FreeBSD user flags.
     251       80743 :         if(!(eaten=from_base64(&val, p)))
     252             :                 return;
     253       80743 :         p+=eaten;
     254             : #ifdef HAVE_CHFLAGS
     255             :         statp->st_flags=0;
     256             :         plug(statp->st_flags, val);
     257             : #endif
     258             : 
     259             :         // Look for winattr.
     260       80743 :         sb->winattr=0;
     261       80743 :         if(!(eaten=from_base64(&val, p)))
     262             :                 return;
     263       80743 :         p+=eaten;
     264       80743 :         sb->winattr=val;
     265             : 
     266       80743 :         if(sb->protocol1)
     267             :         {
     268       23656 :                 sb->compression=-1;
     269       23656 :                 sb->encryption=ENCRYPTION_UNSET;
     270             : 
     271             :                 // Compression for protocol1.
     272       23656 :                 if(!(eaten=from_base64(&val, p)))
     273             :                         return;
     274       23656 :                 p+=eaten;
     275       23656 :                 sb->compression=val;
     276             : 
     277             :                 // Encryption for protocol1.
     278       23656 :                 if(!(eaten=from_base64(&val, p)))
     279             :                         return;
     280       23656 :                 p+=eaten;
     281       23656 :                 sb->encryption=val;
     282             : 
     283             :                 // Salt for protocol1.
     284       23656 :                 if(!(eaten=from_base64(&val, p)))
     285             :                         return;
     286       23656 :                 p+=eaten;
     287       23656 :                 sb->protocol1->salt=val;
     288             :         }
     289             : }
     290             : 
     291          28 : int attribs_set_file_times(struct asfd *asfd,
     292             :         const char *path, struct stat *statp,
     293             :         struct cntr *cntr)
     294             : {
     295             :         int e;
     296             : 
     297             : #ifdef HAVE_WIN32
     298             :         // You (probably) cannot set times on Windows junction points.
     299             :         if(statp->st_rdev==WIN32_JUNCTION_POINT)
     300             :                 return 0;
     301             : 
     302             :         // The mingw64 utime() appears not to work on read-only files.
     303             :         // Use the utime() from bacula instead.
     304             :         e=win32_utime(path, statp);
     305             : #elif HAVE_LUTIMES
     306             :         struct timeval t[2];
     307          28 :         t[0].tv_sec = statp->st_atime;
     308          28 :         t[0].tv_usec = 0;
     309          28 :         t[1].tv_sec = statp->st_mtime;
     310          28 :         t[1].tv_usec = 0;
     311          28 :         e=lutimes(path, t);
     312             : #else
     313             :         struct timespec ts[2];
     314             :         ts[0].tv_sec=statp->st_atime;
     315             :         ts[0].tv_nsec=0;
     316             :         ts[1].tv_sec=statp->st_mtime;
     317             :         ts[1].tv_nsec=0;
     318             :         e=utimensat(AT_FDCWD, path, ts, AT_SYMLINK_NOFOLLOW);
     319             : #endif
     320          28 :         if(e<0)
     321             :         {
     322             :                 struct berrno be;
     323           0 :                 berrno_init(&be);
     324           0 :                 logw(asfd, cntr, "Unable to set file times %s: ERR=%s\n",
     325           0 :                         path, berrno_bstrerror(&be, errno));
     326             :                 return -1;
     327             :         }
     328             :         return 0;
     329             : }
     330             : 
     331       17034 : uint64_t decode_file_no(struct iobuf *iobuf)
     332             : {
     333       17034 :         int64_t val=0;
     334       17034 :         from_base64(&val, iobuf->buf);
     335       17034 :         return (uint64_t)val;
     336             : }
     337             : 
     338           0 : uint64_t decode_file_no_and_save_path(struct iobuf *iobuf, char **save_path)
     339             : {
     340             :         int64_t val;
     341             :         int eaten;
     342           0 :         char *p=iobuf->buf;
     343           0 :         if(!(eaten=from_base64(&val, iobuf->buf)))
     344             :                 return 0;
     345           0 :         *save_path=p+eaten+1;
     346           0 :         return (uint64_t)val;
     347             : }
     348             : 
     349          28 : int attribs_set(struct asfd *asfd, const char *path,
     350             :         struct stat *statp, uint64_t winattr, struct cntr *cntr)
     351             : {
     352             : #ifdef HAVE_WIN32
     353             :         win32_chmod(path, statp->st_mode, winattr);
     354             :         attribs_set_file_times(asfd, path, statp, cntr);
     355             :         return 0;
     356             : #endif
     357             : 
     358          28 :         if(lchown(path, statp->st_uid, statp->st_gid)<0)
     359             :         {
     360             :                 struct berrno be;
     361           0 :                 berrno_init(&be);
     362           0 :                 char msg[256]="";
     363             : 
     364           0 :                 snprintf(msg, sizeof(msg),
     365             :                         "Unable to set file owner of %s to %d:%d: ERR=%s",
     366             :                         path, statp->st_uid, statp->st_gid,
     367           0 :                         berrno_bstrerror(&be, errno));
     368             : 
     369           0 :                 if(errno==EPERM)
     370             :                 {
     371             :                         static int do_owner_warning=1;
     372           0 :                         if(getuid()!=0)
     373             :                         {
     374           0 :                                 if(!do_owner_warning)
     375             :                                         return -1;
     376             : 
     377           0 :                                 logw(asfd, cntr, "%s - possibly because you are not root. Will suppress subsequent messages of this type.\n", msg);
     378           0 :                                 do_owner_warning=0;
     379           0 :                                 return -1;
     380             :                         }
     381             :                 }
     382           0 :                 logw(asfd, cntr, "%s\n", msg);
     383             : 
     384           0 :                 return -1;
     385             :         }
     386             : 
     387             :         /* Watch out, a metadata restore will have cmd set to CMD_METADATA or
     388             :            CMD_ENC_META, but that is OK at the moment because we are not doing
     389             :            meta stuff on links. */
     390          28 :         if(S_ISLNK(statp->st_mode))
     391             :         {
     392           0 :                 if(attribs_set_file_times(asfd, path, statp, cntr))
     393             :                         return -1;
     394             :         }
     395             :         else
     396             :         {
     397          28 :                 if(chmod(path, statp->st_mode) < 0)
     398             :                 {
     399             :                         struct berrno be;
     400           0 :                         berrno_init(&be);
     401           0 :                         logw(asfd, cntr,
     402             :                                 "Unable to set file modes %s: ERR=%s\n",
     403           0 :                                 path, berrno_bstrerror(&be, errno));
     404             :                         return -1;
     405             :                 }
     406             : 
     407          28 :                 if(attribs_set_file_times(asfd, path, statp, cntr))
     408             :                         return -1;
     409             : #ifdef HAVE_CHFLAGS
     410             :                 /*
     411             :                  * FreeBSD user flags
     412             :                  *
     413             :                  * Note, this should really be done before the utime() above,
     414             :                  *  but if the immutable bit is set, it will make the utimes()
     415             :                  *  fail.
     416             :                  */
     417             :                 if(chflags(path, statp->st_flags)<0)
     418             :                 {
     419             :                         struct berrno be;
     420             :                         berrno_init(&be);
     421             :                         logw(asfd, cntr,
     422             :                                 "Unable to set file flags %s: ERR=%s\n",
     423             :                                 path, berrno_bstrerror(&be, errno));
     424             :                         return -1;
     425             :                 }
     426             : #endif
     427             :         }
     428             : 
     429             :         return 0;
     430             : }

Generated by: LCOV version 1.13