]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/findlib/attribs.c
651547b3067dcb493ebc7f8bb7a8d5dc8b5a5ff3
[bacula/bacula] / bacula / src / findlib / attribs.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *  Encode and decode standard Unix attributes and
21  *   Extended attributes for Win32 and
22  *   other non-Unix systems, or Unix systems with ACLs, ...
23  *
24  *    Kern Sibbald, October MMII
25  *
26  */
27
28 //#define _POSIX_C_SOURCE 200809L
29 //#define _BSD_SOURCE 1
30
31 #include "bacula.h"
32 #include "find.h"
33 #include "ch.h"
34
35 static uid_t my_uid = 1;
36 static gid_t my_gid = 1;
37 static bool uid_set = false;
38
39 /*
40  * For old systems that don't have lchown() or lchmod()
41  */
42 #ifndef HAVE_LCHOWN
43 #define lchown chown
44 #endif
45 #ifndef HAVE_LCHMOD
46 #define lchmod chmod
47 #endif
48
49 /*=============================================================*/
50 /*                                                             */
51 /*             ***  A l l  S y s t e m s ***                   */
52 /*                                                             */
53 /*=============================================================*/
54
55 /*
56  * To turn off use of fchown(), fchmod(), or futimes(),
57  *   uncomment one or more of the following.
58  */
59 //#undef HAVE_FCHOWN
60 //#undef HAVE_FCHMOD
61 //#undef HAVE_FUTIMES
62
63 /*
64  * Print errors only if debug level defined or we are root.
65  *  root should not get errors.  Errors for users causes
66  *  too much output.
67  */
68 #define print_error (chk_dbglvl(100) || my_uid == 0)
69
70 bool set_mod_own_time(JCR *jcr, BFILE *ofd, ATTR *attr)
71 {
72    bool ok = true;
73    struct utimbuf ut;
74
75    /* Do not try to set rights with f functions when using a plugin */
76    if (is_bopen(ofd) && !ofd->cmd_plugin) { /* TODO: Look with opt_plugin */
77       /*
78        * The #ifdefing is a bit ugly, but it is the only
79        *  way we can ensure this works on older systems.
80        */
81 #ifdef HAVE_FCHOWN
82       if (fchown(ofd->fid, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
83 #else
84       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
85 #endif
86          berrno be;
87          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
88             attr->ofname, be.bstrerror());
89          ok = false;
90       }
91
92 #ifdef HAVE_FCHMOD
93       if (fchmod(ofd->fid, attr->statp.st_mode) < 0 && print_error) {
94 #else
95       if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
96 #endif
97          berrno be;
98          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
99             attr->ofname, be.bstrerror());
100          ok = false;
101       }
102
103 #ifdef HAVE_FUTIMES
104       struct timeval times[2];
105       times[0].tv_sec = attr->statp.st_atime;
106       times[0].tv_usec = 0;
107       times[1].tv_sec = attr->statp.st_mtime;
108       times[1].tv_usec = 0;
109       if (futimes(ofd->fid, times) < 0 && print_error) {
110 #else
111       ut.actime = attr->statp.st_atime;
112       ut.modtime = attr->statp.st_mtime;
113       //bclose(ofd);
114       if (utime(attr->ofname, &ut) < 0 && print_error) {
115 #endif
116          berrno be;
117          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
118             attr->ofname, be.bstrerror());
119          ok = false;
120       }
121    } else {
122       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
123          berrno be;
124          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
125             attr->ofname, be.bstrerror());
126          ok = false;
127       }
128       if (lchmod(attr->ofname, attr->statp.st_mode) < 0 && print_error) {
129          berrno be;
130          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file modes %s: ERR=%s\n"),
131             attr->ofname, be.bstrerror());
132          ok = false;
133       }
134       /*
135        * Reset file times.
136        */
137       ut.actime = attr->statp.st_atime;
138       ut.modtime = attr->statp.st_mtime;
139
140       if (utime(attr->ofname, &ut) < 0 && print_error) {
141          berrno be;
142          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
143             attr->ofname, be.bstrerror());
144          ok = false;
145       }
146    }
147    return ok;
148 }
149
150 /*
151  * Return the data stream that will be used
152  */
153 int select_data_stream(FF_PKT *ff_pkt)
154 {
155    int stream;
156
157    /* This is a plugin special restore object */
158    if (ff_pkt->type == FT_RESTORE_FIRST) {
159       ff_pkt->flags = 0;
160       return STREAM_FILE_DATA;
161    }
162
163    /*
164     *  Fix all incompatible options
165     */
166    /* No sparse option for encrypted data */
167    if (ff_pkt->flags & FO_ENCRYPT) {
168       ff_pkt->flags &= ~FO_SPARSE;
169    }
170
171    /* Note, no sparse option for win32_data */
172    if (!is_portable_backup(&ff_pkt->bfd)) {
173       stream = STREAM_WIN32_DATA;
174       ff_pkt->flags &= ~FO_SPARSE;
175    } else if (ff_pkt->flags & FO_SPARSE) {
176       stream = STREAM_SPARSE_DATA;
177    } else {
178       stream = STREAM_FILE_DATA;
179    }
180    if (ff_pkt->flags & FO_OFFSETS) {
181       stream = STREAM_SPARSE_DATA;
182    }
183
184    /* Encryption is only supported for file data */
185    if (stream != STREAM_FILE_DATA && stream != STREAM_WIN32_DATA &&
186          stream != STREAM_MACOS_FORK_DATA) {
187       ff_pkt->flags &= ~FO_ENCRYPT;
188    }
189
190    /* Compression is not supported for Mac fork data */
191    if (stream == STREAM_MACOS_FORK_DATA) {
192       ff_pkt->flags &= ~FO_COMPRESS;
193    }
194
195    /*
196     * Handle compression and encryption options
197     */
198 #if defined(HAVE_LIBZ) || defined(HAVE_LZO)
199    if (ff_pkt->flags & FO_COMPRESS) {
200       #ifdef HAVE_LIBZ
201          if(ff_pkt->Compress_algo == COMPRESS_GZIP) {
202             switch (stream) {
203             case STREAM_WIN32_DATA:
204                   stream = STREAM_WIN32_GZIP_DATA;
205                break;
206             case STREAM_SPARSE_DATA:
207                   stream = STREAM_SPARSE_GZIP_DATA;
208                break;
209             case STREAM_FILE_DATA:
210                   stream = STREAM_GZIP_DATA;
211                break;
212             default:
213                /*
214                 * All stream types that do not support compression should clear out
215                 * FO_COMPRESS above, and this code block should be unreachable.
216                 */
217                ASSERT(!(ff_pkt->flags & FO_COMPRESS));
218                return STREAM_NONE;
219             }
220          }
221       #endif
222       #ifdef HAVE_LZO
223          if(ff_pkt->Compress_algo == COMPRESS_LZO1X) {
224             switch (stream) {
225             case STREAM_WIN32_DATA:
226                   stream = STREAM_WIN32_COMPRESSED_DATA;
227                break;
228             case STREAM_SPARSE_DATA:
229                   stream = STREAM_SPARSE_COMPRESSED_DATA;
230                break;
231             case STREAM_FILE_DATA:
232                   stream = STREAM_COMPRESSED_DATA;
233                break;
234             default:
235                /*
236                 * All stream types that do not support compression should clear out
237                 * FO_COMPRESS above, and this code block should be unreachable.
238                 */
239                ASSERT(!(ff_pkt->flags & FO_COMPRESS));
240                return STREAM_NONE;
241             }
242          }
243       #endif
244    }
245 #endif
246 #ifdef HAVE_CRYPTO
247    if (ff_pkt->flags & FO_ENCRYPT) {
248       switch (stream) {
249       case STREAM_WIN32_DATA:
250          stream = STREAM_ENCRYPTED_WIN32_DATA;
251          break;
252       case STREAM_WIN32_GZIP_DATA:
253          stream = STREAM_ENCRYPTED_WIN32_GZIP_DATA;
254          break;
255       case STREAM_WIN32_COMPRESSED_DATA:
256          stream = STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA;
257          break;
258       case STREAM_FILE_DATA:
259          stream = STREAM_ENCRYPTED_FILE_DATA;
260          break;
261       case STREAM_GZIP_DATA:
262          stream = STREAM_ENCRYPTED_FILE_GZIP_DATA;
263          break;
264       case STREAM_COMPRESSED_DATA:
265          stream = STREAM_ENCRYPTED_FILE_COMPRESSED_DATA;
266          break;
267       default:
268          /* All stream types that do not support encryption should clear out
269           * FO_ENCRYPT above, and this code block should be unreachable. */
270          ASSERT(!(ff_pkt->flags & FO_ENCRYPT));
271          return STREAM_NONE;
272       }
273    }
274 #endif
275
276    return stream;
277 }
278
279
280 /*
281  * Encode a stat structure into a base64 character string
282  *   All systems must create such a structure.
283  *   In addition, we tack on the LinkFI, which is non-zero in
284  *   the case of a hard linked file that has no data.  This
285  *   is a File Index pointing to the link that does have the
286  *   data (always the first one encountered in a save).
287  * You may piggyback attributes on this packet by encoding
288  *   them in the encode_attribsEx() subroutine, but this is
289  *   not recommended.
290  */
291 void encode_stat(char *buf, struct stat *statp, int stat_size, int32_t LinkFI, int data_stream)
292 {
293    char *p = buf;
294    /*
295     * We read the stat packet so make sure the caller's conception
296     *  is the same as ours.  They can be different if LARGEFILE is not
297     *  the same when compiling this library and the calling program.
298     */
299    ASSERT(stat_size == (int)sizeof(struct stat));
300
301    /*
302     *  Encode a stat packet.  I should have done this more intelligently
303     *   with a length so that it could be easily expanded.
304     */
305     p += to_base64((int64_t)statp->st_dev, p);
306    *p++ = ' ';                        /* separate fields with a space */
307     p += to_base64((int64_t)statp->st_ino, p);
308    *p++ = ' ';
309     p += to_base64((int64_t)statp->st_mode, p);
310    *p++ = ' ';
311     p += to_base64((int64_t)statp->st_nlink, p);
312    *p++ = ' ';
313     p += to_base64((int64_t)statp->st_uid, p);
314    *p++ = ' ';
315     p += to_base64((int64_t)statp->st_gid, p);
316    *p++ = ' ';
317     p += to_base64((int64_t)statp->st_rdev, p);
318    *p++ = ' ';
319     p += to_base64((int64_t)statp->st_size, p);
320    *p++ = ' ';
321 #ifndef HAVE_MINGW
322     p += to_base64((int64_t)statp->st_blksize, p);
323    *p++ = ' ';
324     p += to_base64((int64_t)statp->st_blocks, p);
325    *p++ = ' ';
326 #else
327     p += to_base64((int64_t)0, p); /* output place holder */
328    *p++ = ' ';
329     p += to_base64((int64_t)0, p); /* output place holder */
330    *p++ = ' ';
331 #endif
332     p += to_base64((int64_t)statp->st_atime, p);
333    *p++ = ' ';
334     p += to_base64((int64_t)statp->st_mtime, p);
335    *p++ = ' ';
336    p += to_base64((int64_t)statp->st_ctime, p);
337    *p++ = ' ';
338     p += to_base64((int64_t)LinkFI, p);
339    *p++ = ' ';
340
341 #ifdef HAVE_CHFLAGS
342    /* FreeBSD function */
343    p += to_base64((int64_t)statp->st_flags, p);  /* output st_flags */
344 #else
345    p += to_base64((int64_t)0, p);     /* output place holder */
346 #endif
347    *p++ = ' ';
348    p += to_base64((int64_t)data_stream, p);
349 #ifdef HAVE_MINGW
350    *p++ = ' ';
351    p += to_base64((int64_t)statp->st_fattrs, p);
352 #endif
353    *p = 0;
354    return;
355 }
356
357 /* Do casting according to unknown type to keep compiler happy */
358 #ifdef HAVE_TYPEOF
359   #define plug(st, val) st = (typeof st)val
360 #else
361   #if !HAVE_GCC & HAVE_SUN_OS
362     /* Sun compiler does not handle templates correctly */
363     #define plug(st, val) st = val
364   #elif __sgi
365     #define plug(st, val) st = val
366   #else
367     /* Use templates to do the casting */
368     template <class T> void plug(T &st, uint64_t val)
369       { st = static_cast<T>(val); }
370   #endif
371 #endif
372
373
374 /*
375  * Decode a stat packet from base64 characters
376  * returns: data_stream
377  */
378 int decode_stat(char *buf, struct stat *statp, int stat_size, int32_t *LinkFI)
379 {
380    char *p = buf;
381    int64_t val;
382    int data_stream;
383
384    /*
385     * We store into the stat packet so make sure the caller's conception
386     *  is the same as ours.  They can be different if LARGEFILE is not
387     *  the same when compiling this library and the calling program.
388     */
389    ASSERT(stat_size == (int)sizeof(struct stat));
390
391    p += from_base64(&val, p);
392    plug(statp->st_dev, val);
393    p++;
394    p += from_base64(&val, p);
395    plug(statp->st_ino, val);
396    p++;
397    p += from_base64(&val, p);
398    plug(statp->st_mode, val);
399    p++;
400    p += from_base64(&val, p);
401    plug(statp->st_nlink, val);
402    p++;
403    p += from_base64(&val, p);
404    plug(statp->st_uid, val);
405    p++;
406    p += from_base64(&val, p);
407    plug(statp->st_gid, val);
408    p++;
409    p += from_base64(&val, p);
410    plug(statp->st_rdev, val);
411    p++;
412    p += from_base64(&val, p);
413    plug(statp->st_size, val);
414    p++;
415 #ifndef HAVE_MINGW
416    p += from_base64(&val, p);
417    plug(statp->st_blksize, val);
418    p++;
419    p += from_base64(&val, p);
420    plug(statp->st_blocks, val);
421    p++;
422 #else
423    p += from_base64(&val, p);
424 //   plug(statp->st_blksize, val);
425    p++;
426    p += from_base64(&val, p);
427 //   plug(statp->st_blocks, val);
428    p++;
429 #endif
430    p += from_base64(&val, p);
431    plug(statp->st_atime, val);
432    p++;
433    p += from_base64(&val, p);
434    plug(statp->st_mtime, val);
435    p++;
436    p += from_base64(&val, p);
437    plug(statp->st_ctime, val);
438
439    /* Optional FileIndex of hard linked file data */
440    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
441       p++;
442       p += from_base64(&val, p);
443       *LinkFI = (uint32_t)val;
444    } else {
445       *LinkFI = 0;
446       return 0;
447    }
448
449    /* FreeBSD user flags */
450    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
451       p++;
452       p += from_base64(&val, p);
453 #ifdef HAVE_CHFLAGS
454       plug(statp->st_flags, val);
455    } else {
456       statp->st_flags  = 0;
457 #endif
458    }
459
460    /* Look for data stream id */
461    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
462       p++;
463       p += from_base64(&val, p);
464    } else {
465       val = 0;
466    }
467    data_stream = val;
468 #ifdef HAVE_MINGW
469    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
470       p++;
471       p += from_base64(&val, p);
472       plug(statp->st_fattrs, val);
473    } else {
474       statp->st_fattrs = 0;
475       val = 0;
476    }
477 #endif
478    return data_stream;
479 }
480
481 /* Decode a LinkFI field of encoded stat packet */
482 int32_t decode_LinkFI(char *buf, struct stat *statp, int stat_size)
483 {
484    char *p = buf;
485    int64_t val;
486    /*
487     * We store into the stat packet so make sure the caller's conception
488     *  is the same as ours.  They can be different if LARGEFILE is not
489     *  the same when compiling this library and the calling program.
490     */
491    ASSERT(stat_size == (int)sizeof(struct stat));
492
493    skip_nonspaces(&p);                /* st_dev */
494    p++;                               /* skip space */
495    skip_nonspaces(&p);                /* st_ino */
496    p++;
497    p += from_base64(&val, p);
498    plug(statp->st_mode, val);         /* st_mode */
499    p++;
500    skip_nonspaces(&p);                /* st_nlink */
501    p++;
502    skip_nonspaces(&p);                /* st_uid */
503    p++;
504    skip_nonspaces(&p);                /* st_gid */
505    p++;
506    skip_nonspaces(&p);                /* st_rdev */
507    p++;
508    skip_nonspaces(&p);                /* st_size */
509    p++;
510    skip_nonspaces(&p);                /* st_blksize */
511    p++;
512    skip_nonspaces(&p);                /* st_blocks */
513    p++;
514    skip_nonspaces(&p);                /* st_atime */
515    p++;
516    skip_nonspaces(&p);                /* st_mtime */
517    p++;
518    skip_nonspaces(&p);                /* st_ctime */
519
520    /* Optional FileIndex of hard linked file data */
521    if (*p == ' ' || (*p != 0 && *(p+1) == ' ')) {
522       p++;
523       p += from_base64(&val, p);
524       return (int32_t)val;
525    }
526    return 0;
527 }
528
529 /*
530  * Set file modes, permissions and times
531  *
532  *  fname is the original filename
533  *  ofile is the output filename (may be in a different directory)
534  *
535  * Returns:  true  on success
536  *           false on failure
537  */
538 bool set_attributes(JCR *jcr, ATTR *attr, BFILE *ofd)
539 {
540    mode_t old_mask;
541    bool ok = true;
542    boffset_t fsize;
543
544    if (!uid_set) {
545       my_uid = getuid();
546       my_gid = getgid();
547       uid_set = true;
548    }
549
550    old_mask = umask(0);
551    if (is_bopen(ofd)) {
552       char ec1[50], ec2[50];
553       fsize = blseek(ofd, 0, SEEK_END);
554       if (attr->type == FT_REG && fsize > 0 && attr->statp.st_size > 0 &&
555                         fsize != (boffset_t)attr->statp.st_size) {
556          Jmsg3(jcr, M_ERROR, 0, _("File size of restored file %s not correct. Original %s, restored %s.\n"),
557             attr->ofname, edit_uint64(attr->statp.st_size, ec1),
558             edit_uint64(fsize, ec2));
559       }
560    }
561
562    /*
563     * We do not restore sockets, so skip trying to restore their
564     *   attributes.
565     */
566    if (attr->type == FT_SPEC && S_ISSOCK(attr->statp.st_mode)) {
567       goto bail_out;
568    }
569
570    /* ***FIXME**** optimize -- don't do if already correct */
571    /*
572     * For link, change owner of link using lchown, but don't
573     *   try to do a chmod as that will update the file behind it.
574     */
575    if (attr->type == FT_LNK) {
576 #ifdef HAVE_LCHOWN
577       /* Change owner of link, not of real file */
578       if (lchown(attr->ofname, attr->statp.st_uid, attr->statp.st_gid) < 0 && print_error) {
579          berrno be;
580          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file owner %s: ERR=%s\n"),
581             attr->ofname, be.bstrerror());
582          ok = false;
583       }
584 #endif
585 #ifdef HAVE_LUTIMES
586       struct timeval times[2];
587       times[0].tv_sec = attr->statp.st_atime;
588       times[0].tv_usec = 0;
589       times[1].tv_sec = attr->statp.st_mtime;
590       times[1].tv_usec = 0;
591       if (lutimes(attr->ofname, times) < 0 && print_error) {
592          berrno be;
593          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file times %s: ERR=%s\n"),
594             attr->ofname, be.bstrerror());
595          ok = false;
596       }
597 #endif
598    } else {
599       /*
600        * At this point, we have a file that is not a LINK
601        */
602       ok = set_mod_own_time(jcr, ofd, attr);
603
604 #ifdef HAVE_CHFLAGS
605       /*
606        * FreeBSD user flags
607        *
608        * Note, this should really be done before the utime() above,
609        *  but if the immutable bit is set, it will make the utimes()
610        *  fail.
611        */
612       if (chflags(attr->ofname, attr->statp.st_flags) < 0 && print_error) {
613          berrno be;
614          Jmsg2(jcr, M_ERROR, 0, _("Unable to set file flags %s: ERR=%s\n"),
615             attr->ofname, be.bstrerror());
616          ok = false;
617       }
618 #endif
619    }
620
621 bail_out:
622    if (is_bopen(ofd)) {
623       bclose(ofd);
624    }
625    pm_strcpy(attr->ofname, "*none*");
626    umask(old_mask);
627    return ok;
628 }
629
630
631 /*=============================================================*/
632 /*                                                             */
633 /*                 * * *  U n i x * * * *                      */
634 /*                                                             */
635 /*=============================================================*/
636
637 #ifndef HAVE_WIN32
638
639 /*
640  * It is possible to piggyback additional data e.g. ACLs on
641  *   the encode_stat() data by returning the extended attributes
642  *   here.  They must be "self-contained" (i.e. you keep track
643  *   of your own length), and they must be in ASCII string
644  *   format. Using this feature is not recommended.
645  * The code below shows how to return nothing.  See the Win32
646  *   code below for returning something in the attributes.
647  */
648 int encode_attribsEx(JCR *jcr, char *attribsEx, FF_PKT *ff_pkt)
649 {
650 #ifdef HAVE_DARWIN_OS
651    /*
652     * We save the Mac resource fork length so that on a
653     * restore, we can be sure we put back the whole resource.
654     */
655    char *p;
656
657    *attribsEx = 0;                 /* no extended attributes (yet) */
658    if (jcr->cmd_plugin || ff_pkt->type == FT_DELETED) {
659       return STREAM_UNIX_ATTRIBUTES;
660    }
661    p = attribsEx;
662    if (ff_pkt->flags & FO_HFSPLUS) {
663       p += to_base64((uint64_t)(ff_pkt->hfsinfo.rsrclength), p);
664    }
665    *p = 0;
666 #else
667    *attribsEx = 0;                    /* no extended attributes */
668 #endif
669    return STREAM_UNIX_ATTRIBUTES;
670 }
671
672 #endif