s3:tldap: add tldap_extended*
[samba.git] / source3 / lib / adouble.c
1 /*
2  * Samba AppleDouble helpers
3  *
4  * Copyright (C) Ralph Boehme, 2019
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include "includes.h"
21 #include "adouble.h"
22 #include "MacExtensions.h"
23 #include "string_replace.h"
24 #include "smbd/smbd.h"
25 #include "system/filesys.h"
26 #include "libcli/security/security.h"
27 #include "lib/util_macstreams.h"
28 #include "auth.h"
29
30 /*
31    "._" AppleDouble Header File Layout:
32
33          MAGIC          0x00051607
34          VERSION        0x00020000
35          FILLER         0
36          COUNT          2
37      .-- AD ENTRY[0]    Finder Info Entry (must be first)
38   .--+-- AD ENTRY[1]    Resource Fork Entry (must be last)
39   |  |   /////////////
40   |  '-> FINDER INFO    Fixed Size Data (32 Bytes)
41   |      ~~~~~~~~~~~~~  2 Bytes Padding
42   |      EXT ATTR HDR   Fixed Size Data (36 Bytes)
43   |      /////////////
44   |      ATTR ENTRY[0] --.
45   |      ATTR ENTRY[1] --+--.
46   |      ATTR ENTRY[2] --+--+--.
47   |         ...          |  |  |
48   |      ATTR ENTRY[N] --+--+--+--.
49   |      ATTR DATA 0   <-'  |  |  |
50   |      ////////////       |  |  |
51   |      ATTR DATA 1   <----'  |  |
52   |      /////////////         |  |
53   |      ATTR DATA 2   <-------'  |
54   |      /////////////            |
55   |         ...                   |
56   |      ATTR DATA N   <----------'
57   |      /////////////
58   |         ...          Attribute Free Space
59   |
60   '----> RESOURCE FORK
61             ...          Variable Sized Data
62             ...
63 */
64
65 /* Number of actually used entries */
66 #define ADEID_NUM_XATTR      8
67 #define ADEID_NUM_DOT_UND    2
68 #define ADEID_NUM_RSRC_XATTR 1
69
70 /* Sizes of relevant entry bits */
71 #define ADEDLEN_MAGIC       4
72 #define ADEDLEN_VERSION     4
73 #define ADEDLEN_FILLER      16
74 #define AD_FILLER_TAG       "Netatalk        " /* should be 16 bytes */
75 #define AD_FILLER_TAG_OSX   "Mac OS X        " /* should be 16 bytes */
76 #define ADEDLEN_NENTRIES    2
77 #define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
78                              ADEDLEN_FILLER + ADEDLEN_NENTRIES) /* 26 */
79 #define AD_ENTRY_LEN_EID    4
80 #define AD_ENTRY_LEN_OFF    4
81 #define AD_ENTRY_LEN_LEN    4
82 #define AD_ENTRY_LEN (AD_ENTRY_LEN_EID + AD_ENTRY_LEN_OFF + AD_ENTRY_LEN_LEN)
83
84 /* Offsets */
85 #define ADEDOFF_MAGIC         0
86 #define ADEDOFF_VERSION       (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
87 #define ADEDOFF_FILLER        (ADEDOFF_VERSION + ADEDLEN_VERSION)
88 #define ADEDOFF_NENTRIES      (ADEDOFF_FILLER + ADEDLEN_FILLER)
89
90 #define ADEDOFF_FINDERI_XATTR    (AD_HEADER_LEN + \
91                                   (ADEID_NUM_XATTR * AD_ENTRY_LEN))
92 #define ADEDOFF_COMMENT_XATTR    (ADEDOFF_FINDERI_XATTR    + ADEDLEN_FINDERI)
93 #define ADEDOFF_FILEDATESI_XATTR (ADEDOFF_COMMENT_XATTR    + ADEDLEN_COMMENT)
94 #define ADEDOFF_AFPFILEI_XATTR   (ADEDOFF_FILEDATESI_XATTR + \
95                                   ADEDLEN_FILEDATESI)
96 #define ADEDOFF_PRIVDEV_XATTR    (ADEDOFF_AFPFILEI_XATTR   + ADEDLEN_AFPFILEI)
97 #define ADEDOFF_PRIVINO_XATTR    (ADEDOFF_PRIVDEV_XATTR    + ADEDLEN_PRIVDEV)
98 #define ADEDOFF_PRIVSYN_XATTR    (ADEDOFF_PRIVINO_XATTR    + ADEDLEN_PRIVINO)
99 #define ADEDOFF_PRIVID_XATTR     (ADEDOFF_PRIVSYN_XATTR    + ADEDLEN_PRIVSYN)
100
101 #define ADEDOFF_FINDERI_DOT_UND  (AD_HEADER_LEN + \
102                                   (ADEID_NUM_DOT_UND * AD_ENTRY_LEN))
103 #define ADEDOFF_RFORK_DOT_UND    (ADEDOFF_FINDERI_DOT_UND + ADEDLEN_FINDERI)
104
105 #define AD_DATASZ_XATTR (AD_HEADER_LEN + \
106                          (ADEID_NUM_XATTR * AD_ENTRY_LEN) + \
107                          ADEDLEN_FINDERI + ADEDLEN_COMMENT + \
108                          ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + \
109                          ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
110                          ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
111
112 #if AD_DATASZ_XATTR != 402
113 #error bad size for AD_DATASZ_XATTR
114 #endif
115
116 #define AD_DATASZ_DOT_UND (AD_HEADER_LEN + \
117                            (ADEID_NUM_DOT_UND * AD_ENTRY_LEN) + \
118                            ADEDLEN_FINDERI)
119 #if AD_DATASZ_DOT_UND != 82
120 #error bad size for AD_DATASZ_DOT_UND
121 #endif
122
123 #define AD_XATTR_HDR_MAGIC    0x41545452 /* 'ATTR' */
124 #define AD_XATTR_MAX_ENTRIES  1024 /* Some arbitrarily enforced limit */
125 #define AD_XATTR_HDR_SIZE     36
126 #define AD_XATTR_MAX_HDR_SIZE 65536
127 #define ADX_ENTRY_FIXED_SIZE  (4+4+2+1)
128
129 /*
130  * Both struct ad_xattr_header and struct ad_xattr_entry describe the in memory
131  * representation as well as the on-disk format.
132  *
133  * The ad_xattr_header follows the FinderInfo data in the FinderInfo entry if
134  * the length of the FinderInfo entry is larger then 32 bytes. It is then
135  * preceded with 2 bytes padding.
136  *
137  * Cf: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/vfs/vfs_xattr.c
138  */
139
140 struct ad_xattr_header {
141         uint32_t adx_magic;        /* ATTR_HDR_MAGIC */
142         uint32_t adx_debug_tag;    /* for debugging == file id of owning file */
143         uint32_t adx_total_size;   /* file offset of end of attribute header + entries + data */
144         uint32_t adx_data_start;   /* file offset to attribute data area */
145         uint32_t adx_data_length;  /* length of attribute data area */
146         uint32_t adx_reserved[3];
147         uint16_t adx_flags;
148         uint16_t adx_num_attrs;
149 };
150
151 /* On-disk entries are aligned on 4 byte boundaries */
152 struct ad_xattr_entry {
153         uint32_t adx_offset;    /* file offset to data */
154         uint32_t adx_length;    /* size of attribute data */
155         uint16_t adx_flags;
156         uint8_t  adx_namelen;   /* included the NULL terminator */
157         char    *adx_name;      /* NULL-terminated UTF-8 name */
158 };
159
160 struct ad_entry {
161         size_t ade_off;
162         size_t ade_len;
163 };
164
165 struct adouble {
166         files_struct             *ad_fsp;
167         bool                      ad_opened;
168         adouble_type_t            ad_type;
169         uint32_t                  ad_magic;
170         uint32_t                  ad_version;
171         uint8_t                   ad_filler[ADEDLEN_FILLER];
172         struct ad_entry           ad_eid[ADEID_MAX];
173         char                     *ad_data;
174         char                     *ad_rsrc_data;
175         struct ad_xattr_header    adx_header;
176         struct ad_xattr_entry    *adx_entries;
177         char                     *adx_data;
178 };
179
180 struct ad_entry_order {
181         uint32_t id, offset, len;
182 };
183
184 /* Netatalk AppleDouble metadata xattr */
185 static const
186 struct ad_entry_order entry_order_meta_xattr[ADEID_NUM_XATTR + 1] = {
187         {ADEID_FINDERI,    ADEDOFF_FINDERI_XATTR,    ADEDLEN_FINDERI},
188         {ADEID_COMMENT,    ADEDOFF_COMMENT_XATTR,    0},
189         {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_XATTR, ADEDLEN_FILEDATESI},
190         {ADEID_AFPFILEI,   ADEDOFF_AFPFILEI_XATTR,   ADEDLEN_AFPFILEI},
191         {ADEID_PRIVDEV,    ADEDOFF_PRIVDEV_XATTR,    0},
192         {ADEID_PRIVINO,    ADEDOFF_PRIVINO_XATTR,    0},
193         {ADEID_PRIVSYN,    ADEDOFF_PRIVSYN_XATTR,    0},
194         {ADEID_PRIVID,     ADEDOFF_PRIVID_XATTR,     0},
195         {0, 0, 0}
196 };
197
198 /* AppleDouble resource fork file (the ones prefixed by "._") */
199 static const
200 struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
201         {ADEID_FINDERI,    ADEDOFF_FINDERI_DOT_UND,  ADEDLEN_FINDERI},
202         {ADEID_RFORK,      ADEDOFF_RFORK_DOT_UND,    0},
203         {0, 0, 0}
204 };
205
206 /* Conversion from enumerated id to on-disk AppleDouble id */
207 #define AD_EID_DISK(a) (set_eid[a])
208 static const uint32_t set_eid[] = {
209         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
210         AD_DEV, AD_INO, AD_SYN, AD_ID
211 };
212
213 static char empty_resourcefork[] = {
214         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
215         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
216         0x54, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73,
217         0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x66, 0x6F,
218         0x72, 0x6B, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E,
219         0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x6C, 0x79,
220         0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x62, 0x6C,
221         0x61, 0x6E, 0x6B, 0x20, 0x20, 0x20, 0x00, 0x00,
222         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
240         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
241         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
242         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
245         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
246         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
247         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
248         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
249         0x00, 0x1C, 0x00, 0x1E, 0xFF, 0xFF
250 };
251
252 size_t ad_getentrylen(const struct adouble *ad, int eid)
253 {
254         return ad->ad_eid[eid].ade_len;
255 }
256
257 size_t ad_getentryoff(const struct adouble *ad, int eid)
258 {
259         return ad->ad_eid[eid].ade_off;
260 }
261
262 size_t ad_setentrylen(struct adouble *ad, int eid, size_t len)
263 {
264         return ad->ad_eid[eid].ade_len = len;
265 }
266
267 size_t ad_setentryoff(struct adouble *ad, int eid, size_t off)
268 {
269         return ad->ad_eid[eid].ade_off = off;
270 }
271
272 /*
273  * All entries besides FinderInfo and resource fork must fit into the
274  * buffer. FinderInfo is special as it may be larger then the default 32 bytes
275  * if it contains marshalled xattrs, which we will fixup that in
276  * ad_convert(). The first 32 bytes however must also be part of the buffer.
277  *
278  * The resource fork is never accessed directly by the ad_data buf.
279  */
280 static bool ad_entry_check_size(uint32_t eid,
281                                 size_t bufsize,
282                                 uint32_t off,
283                                 uint32_t got_len)
284 {
285         struct {
286                 off_t expected_len;
287                 bool fixed_size;
288                 bool minimum_size;
289         } ad_checks[] = {
290                 [ADEID_DFORK] = {-1, false, false}, /* not applicable */
291                 [ADEID_RFORK] = {-1, false, false}, /* no limit */
292                 [ADEID_NAME] = {ADEDLEN_NAME, false, false},
293                 [ADEID_COMMENT] = {ADEDLEN_COMMENT, false, false},
294                 [ADEID_ICONBW] = {ADEDLEN_ICONBW, true, false},
295                 [ADEID_ICONCOL] = {ADEDLEN_ICONCOL, false, false},
296                 [ADEID_FILEI] = {ADEDLEN_FILEI, true, false},
297                 [ADEID_FILEDATESI] = {ADEDLEN_FILEDATESI, true, false},
298                 [ADEID_FINDERI] = {ADEDLEN_FINDERI, false, true},
299                 [ADEID_MACFILEI] = {ADEDLEN_MACFILEI, true, false},
300                 [ADEID_PRODOSFILEI] = {ADEDLEN_PRODOSFILEI, true, false},
301                 [ADEID_MSDOSFILEI] = {ADEDLEN_MSDOSFILEI, true, false},
302                 [ADEID_SHORTNAME] = {ADEDLEN_SHORTNAME, false, false},
303                 [ADEID_AFPFILEI] = {ADEDLEN_AFPFILEI, true, false},
304                 [ADEID_DID] = {ADEDLEN_DID, true, false},
305                 [ADEID_PRIVDEV] = {ADEDLEN_PRIVDEV, true, false},
306                 [ADEID_PRIVINO] = {ADEDLEN_PRIVINO, true, false},
307                 [ADEID_PRIVSYN] = {ADEDLEN_PRIVSYN, true, false},
308                 [ADEID_PRIVID] = {ADEDLEN_PRIVID, true, false},
309         };
310
311         if (eid >= ADEID_MAX) {
312                 return false;
313         }
314         if (got_len == 0) {
315                 /* Entry present, but empty, allow */
316                 return true;
317         }
318         if (ad_checks[eid].expected_len == 0) {
319                 /*
320                  * Shouldn't happen: implicitly initialized to zero because
321                  * explicit initializer missing.
322                  */
323                 return false;
324         }
325         if (ad_checks[eid].expected_len == -1) {
326                 /* Unused or no limit */
327                 return true;
328         }
329         if (ad_checks[eid].fixed_size) {
330                 if (ad_checks[eid].expected_len != got_len) {
331                         /* Wrong size for fixed size entry. */
332                         return false;
333                 }
334         } else {
335                 if (ad_checks[eid].minimum_size) {
336                         if (got_len < ad_checks[eid].expected_len) {
337                                 /*
338                                  * Too small for variable sized entry with
339                                  * minimum size.
340                                  */
341                                 return false;
342                         }
343                 } else {
344                         if (got_len > ad_checks[eid].expected_len) {
345                                 /* Too big for variable sized entry. */
346                                 return false;
347                         }
348                 }
349         }
350         if (off + got_len < off) {
351                 /* wrap around */
352                 return false;
353         }
354         if (off + got_len > bufsize) {
355                 /* overflow */
356                 return false;
357         }
358         return true;
359 }
360
361 /**
362  * Return a pointer to an AppleDouble entry
363  *
364  * Returns NULL if the entry is not present
365  **/
366 char *ad_get_entry(const struct adouble *ad, int eid)
367 {
368         size_t bufsize = talloc_get_size(ad->ad_data);
369         off_t off = ad_getentryoff(ad, eid);
370         size_t len = ad_getentrylen(ad, eid);
371         bool valid;
372
373         valid = ad_entry_check_size(eid, bufsize, off, len);
374         if (!valid) {
375                 return NULL;
376         }
377
378         if (off == 0 || len == 0) {
379                 return NULL;
380         }
381
382         return ad->ad_data + off;
383 }
384
385 /**
386  * Get a date
387  **/
388 int ad_getdate(const struct adouble *ad, unsigned int dateoff, uint32_t *date)
389 {
390         bool xlate = (dateoff & AD_DATE_UNIX);
391         char *p = NULL;
392
393         dateoff &= AD_DATE_MASK;
394         p = ad_get_entry(ad, ADEID_FILEDATESI);
395         if (p == NULL) {
396                 return -1;
397         }
398
399         if (dateoff > AD_DATE_ACCESS) {
400             return -1;
401         }
402
403         memcpy(date, p + dateoff, sizeof(uint32_t));
404
405         if (xlate) {
406                 *date = AD_DATE_TO_UNIX(*date);
407         }
408         return 0;
409 }
410
411 /**
412  * Set a date
413  **/
414 int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
415 {
416         bool xlate = (dateoff & AD_DATE_UNIX);
417         char *p = NULL;
418
419         p = ad_get_entry(ad, ADEID_FILEDATESI);
420         if (p == NULL) {
421                 return -1;
422         }
423
424         dateoff &= AD_DATE_MASK;
425         if (xlate) {
426                 date = AD_DATE_FROM_UNIX(date);
427         }
428
429         if (dateoff > AD_DATE_ACCESS) {
430                 return -1;
431         }
432
433         memcpy(p + dateoff, &date, sizeof(date));
434
435         return 0;
436 }
437
438
439 /**
440  * Map on-disk AppleDouble id to enumerated id
441  **/
442 static uint32_t get_eid(uint32_t eid)
443 {
444         if (eid <= 15) {
445                 return eid;
446         }
447
448         switch (eid) {
449         case AD_DEV:
450                 return ADEID_PRIVDEV;
451         case AD_INO:
452                 return ADEID_PRIVINO;
453         case AD_SYN:
454                 return ADEID_PRIVSYN;
455         case AD_ID:
456                 return ADEID_PRIVID;
457         default:
458                 break;
459         }
460
461         return 0;
462 }
463
464 /*
465  * Move resourcefork data in an AppleDouble file
466  *
467  * This is supposed to make room in an AppleDouble file by moving the
468  * resourcefork data behind the space required for packing additional xattr data
469  * in the extended FinderInfo entry.
470  *
471  * When we're called we're expecting an AppleDouble file with just two entries
472  * (FinderInfo an Resourcefork) and the resourcefork is expected at a fixed
473  * offset of ADEDOFF_RFORK_DOT_UND.
474  */
475 static bool ad_pack_move_reso(struct vfs_handle_struct *handle,
476                               struct adouble *ad,
477                               files_struct *fsp)
478 {
479         size_t reso_len;
480         size_t reso_off;
481         size_t n;
482         bool ok;
483
484         reso_len = ad_getentrylen(ad, ADEID_RFORK);
485         reso_off = ad_getentryoff(ad, ADEID_RFORK);
486
487         if (reso_len == 0) {
488                 return true;
489         }
490
491         if (ad->ad_rsrc_data == NULL) {
492                 /*
493                  * This buffer is already set when converting a resourcefork
494                  * stream from vfs_streams_depot backend via ad_unconvert(). It
495                  * is NULL with vfs_streams_xattr where the resourcefork stream
496                  * is stored in an AppleDouble sidecar file vy vfs_fruit.
497                  */
498                 ad->ad_rsrc_data = talloc_size(ad, reso_len);
499                 if (ad->ad_rsrc_data == NULL) {
500                         return false;
501                 }
502
503                 n = SMB_VFS_NEXT_PREAD(handle,
504                                        fsp,
505                                        ad->ad_rsrc_data,
506                                        reso_len,
507                                        ADEDOFF_RFORK_DOT_UND);
508                 if (n != reso_len) {
509                         DBG_ERR("Read on [%s] failed\n",
510                                 fsp_str_dbg(fsp));
511                         ok = false;
512                         goto out;
513                 }
514         }
515
516         n = SMB_VFS_NEXT_PWRITE(handle,
517                                 fsp,
518                                 ad->ad_rsrc_data,
519                                 reso_len,
520                                 reso_off);
521         if (n != reso_len) {
522                 DBG_ERR("Write on [%s] failed\n",
523                         fsp_str_dbg(fsp));
524                 ok = false;
525                 goto out;
526         }
527
528         ok = true;
529 out:
530         return ok;
531 }
532
533 static bool ad_pack_xattrs(struct vfs_handle_struct *handle,
534                            struct adouble *ad,
535                            files_struct *fsp)
536 {
537         struct ad_xattr_header *h = &ad->adx_header;
538         size_t oldsize;
539         uint32_t off;
540         uint32_t data_off;
541         uint16_t i;
542         bool ok;
543
544         if (ad->adx_entries == NULL) {
545                 /* No xattrs, nothing to pack */
546                 return true;
547         }
548
549         if (fsp == NULL) {
550                 DBG_ERR("fsp unexpectedly NULL\n");
551                 return false;
552         }
553
554         oldsize = talloc_get_size(ad->ad_data);
555         if (oldsize < AD_XATTR_MAX_HDR_SIZE) {
556                 ad->ad_data = talloc_realloc(ad,
557                                              ad->ad_data,
558                                              char,
559                                              AD_XATTR_MAX_HDR_SIZE);
560                 if (ad->ad_data == NULL) {
561                         return false;
562                 }
563                 memset(ad->ad_data + oldsize,
564                        0,
565                        AD_XATTR_MAX_HDR_SIZE - oldsize);
566         }
567
568         /*
569          * First, let's calculate the start of the xattr data area which will be
570          * after the xattr header + header entries.
571          */
572
573         data_off = ad_getentryoff(ad, ADEID_FINDERI);
574         data_off += ADEDLEN_FINDERI + AD_XATTR_HDR_SIZE;
575         /* 2 bytes padding */
576         data_off += 2;
577
578         for (i = 0; i < h->adx_num_attrs; i++) {
579                 struct ad_xattr_entry *e = &ad->adx_entries[i];
580
581                 /* Align on 4 byte boundary */
582                 data_off = (data_off + 3) & ~3;
583
584                 data_off += e->adx_namelen + ADX_ENTRY_FIXED_SIZE;
585                 if (data_off >= AD_XATTR_MAX_HDR_SIZE) {
586                         return false;
587                 }
588         }
589
590         off = ad_getentryoff(ad, ADEID_FINDERI);
591         off +=  ADEDLEN_FINDERI + AD_XATTR_HDR_SIZE;
592         /* 2 bytes padding */
593         off += 2;
594
595         for (i = 0; i < h->adx_num_attrs; i++) {
596                 struct ad_xattr_entry *e = &ad->adx_entries[i];
597
598                 /* Align on 4 byte boundary */
599                 off = (off + 3) & ~3;
600
601                 e->adx_offset = data_off;
602                 data_off += e->adx_length;
603
604                 DBG_DEBUG("%zu(%s){%zu}: off [%zu] adx_length [%zu] "
605                           "adx_data_off [%zu]\n",
606                           (size_t)i,
607                           e->adx_name,
608                           (size_t)e->adx_namelen,
609                           (size_t)off,
610                           (size_t)e->adx_length,
611                           (size_t)e->adx_offset);
612
613                 if (off + 4 >= AD_XATTR_MAX_HDR_SIZE) {
614                         return false;
615                 }
616                 RSIVAL(ad->ad_data, off, e->adx_offset);
617                 off += 4;
618
619                 if (off + 4 >= AD_XATTR_MAX_HDR_SIZE) {
620                         return false;
621                 }
622                 RSIVAL(ad->ad_data, off, e->adx_length);
623                 off += 4;
624
625                 if (off + 2 >= AD_XATTR_MAX_HDR_SIZE) {
626                         return false;
627                 }
628                 RSSVAL(ad->ad_data, off, e->adx_flags);
629                 off += 2;
630
631                 if (off + 1 >= AD_XATTR_MAX_HDR_SIZE) {
632                         return false;
633                 }
634                 SCVAL(ad->ad_data, off, e->adx_namelen);
635                 off += 1;
636
637                 if (off + e->adx_namelen >= AD_XATTR_MAX_HDR_SIZE) {
638                         return false;
639                 }
640                 memcpy(ad->ad_data + off, e->adx_name, e->adx_namelen);
641                 off += e->adx_namelen;
642         }
643
644         h->adx_data_start = off;
645         h->adx_data_length = talloc_get_size(ad->adx_data);
646         h->adx_total_size = h->adx_data_start + h->adx_data_length;
647
648         if (talloc_get_size(ad->ad_data) < h->adx_total_size) {
649                 ad->ad_data = talloc_realloc(ad,
650                                              ad->ad_data,
651                                              char,
652                                              h->adx_total_size);
653                 if (ad->ad_data == NULL) {
654                         return false;
655                 }
656         }
657
658         memcpy(ad->ad_data + h->adx_data_start,
659                ad->adx_data,
660                h->adx_data_length);
661
662         ad_setentrylen(ad,
663                        ADEID_FINDERI,
664                        h->adx_total_size - ad_getentryoff(ad, ADEID_FINDERI));
665
666         ad_setentryoff(ad,
667                        ADEID_RFORK,
668                        ad_getentryoff(ad, ADEID_FINDERI) +
669                        ad_getentrylen(ad, ADEID_FINDERI));
670
671         memcpy(ad->ad_data + ADEDOFF_FILLER, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
672
673         /*
674          * Rewind, then update the header fields.
675          */
676
677         off = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI;
678         /* 2 bytes padding */
679         off += 2;
680
681         RSIVAL(ad->ad_data, off, AD_XATTR_HDR_MAGIC);
682         off += 4;
683         RSIVAL(ad->ad_data, off, 0);
684         off += 4;
685         RSIVAL(ad->ad_data, off, h->adx_total_size);
686         off += 4;
687         RSIVAL(ad->ad_data, off, h->adx_data_start);
688         off += 4;
689         RSIVAL(ad->ad_data, off, h->adx_data_length);
690         off += 4;
691
692         /* adx_reserved and adx_flags */
693         memset(ad->ad_data + off, 0, 3 * 4 + 2);
694         off += 3 * 4 + 2;
695
696         RSSVAL(ad->ad_data, off, h->adx_num_attrs);
697         off += 2;
698
699         ok = ad_pack_move_reso(handle, ad, fsp);
700         if (!ok) {
701                 DBG_ERR("Moving resourcefork of [%s] failed\n",
702                         fsp_str_dbg(fsp));
703                 return false;
704         }
705
706         return true;
707 }
708
709 /**
710  * Pack AppleDouble structure into data buffer
711  **/
712 static bool ad_pack(struct vfs_handle_struct *handle,
713                     struct adouble *ad,
714                     files_struct *fsp)
715 {
716         uint32_t       eid;
717         uint16_t       nent;
718         uint32_t       bufsize;
719         uint32_t       offset = 0;
720         bool ok;
721
722         bufsize = talloc_get_size(ad->ad_data);
723         if (bufsize < AD_DATASZ_DOT_UND) {
724                 DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
725                 return false;
726         }
727
728         if (offset + ADEDLEN_MAGIC < offset ||
729                         offset + ADEDLEN_MAGIC >= bufsize) {
730                 return false;
731         }
732         RSIVAL(ad->ad_data, offset, ad->ad_magic);
733         offset += ADEDLEN_MAGIC;
734
735         if (offset + ADEDLEN_VERSION < offset ||
736                         offset + ADEDLEN_VERSION >= bufsize) {
737                 return false;
738         }
739         RSIVAL(ad->ad_data, offset, ad->ad_version);
740         offset += ADEDLEN_VERSION;
741
742         if (offset + ADEDLEN_FILLER < offset ||
743                         offset + ADEDLEN_FILLER >= bufsize) {
744                 return false;
745         }
746         if (ad->ad_type == ADOUBLE_RSRC) {
747                 memcpy(ad->ad_data + offset, AD_FILLER_TAG, ADEDLEN_FILLER);
748         }
749         offset += ADEDLEN_FILLER;
750
751         if (offset + ADEDLEN_NENTRIES < offset ||
752                         offset + ADEDLEN_NENTRIES >= bufsize) {
753                 return false;
754         }
755         offset += ADEDLEN_NENTRIES;
756
757         ok = ad_pack_xattrs(handle, ad, fsp);
758         if (!ok) {
759                 return false;
760         }
761
762         for (eid = 0, nent = 0; eid < ADEID_MAX; eid++) {
763                 if (ad->ad_eid[eid].ade_off == 0) {
764                         /*
765                          * ade_off is also used as indicator whether a
766                          * specific entry is used or not
767                          */
768                         continue;
769                 }
770
771                 if (offset + AD_ENTRY_LEN_EID < offset ||
772                                 offset + AD_ENTRY_LEN_EID >= bufsize) {
773                         return false;
774                 }
775                 RSIVAL(ad->ad_data, offset, AD_EID_DISK(eid));
776                 offset += AD_ENTRY_LEN_EID;
777
778                 if (offset + AD_ENTRY_LEN_OFF < offset ||
779                                 offset + AD_ENTRY_LEN_OFF >= bufsize) {
780                         return false;
781                 }
782                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_off);
783                 offset += AD_ENTRY_LEN_OFF;
784
785                 if (offset + AD_ENTRY_LEN_LEN < offset ||
786                                 offset + AD_ENTRY_LEN_LEN >= bufsize) {
787                         return false;
788                 }
789                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_len);
790                 offset += AD_ENTRY_LEN_LEN;
791
792                 nent++;
793         }
794
795         if (ADEDOFF_NENTRIES + 2 >= bufsize) {
796                 return false;
797         }
798         RSSVAL(ad->ad_data, ADEDOFF_NENTRIES, nent);
799
800         return true;
801 }
802
803 static bool ad_unpack_xattrs(struct adouble *ad)
804 {
805         struct ad_xattr_header *h = &ad->adx_header;
806         size_t bufsize = talloc_get_size(ad->ad_data);
807         const char *p = ad->ad_data;
808         uint32_t hoff;
809         uint32_t i;
810
811         if (ad->ad_type != ADOUBLE_RSRC) {
812                 return false;
813         }
814
815         if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) {
816                 return true;
817         }
818
819         /*
820          * Ensure the buffer ad->ad_data was allocated by ad_alloc() for an
821          * ADOUBLE_RSRC type (._ AppleDouble file on-disk).
822          */
823         if (bufsize != AD_XATTR_MAX_HDR_SIZE) {
824                 return false;
825         }
826
827         /* 2 bytes padding */
828         hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2;
829
830         h->adx_magic       = RIVAL(p, hoff + 0);
831         h->adx_debug_tag   = RIVAL(p, hoff + 4); /* Not used -> not checked */
832         h->adx_total_size  = RIVAL(p, hoff + 8);
833         h->adx_data_start  = RIVAL(p, hoff + 12);
834         h->adx_data_length = RIVAL(p, hoff + 16);
835         h->adx_flags       = RSVAL(p, hoff + 32); /* Not used -> not checked */
836         h->adx_num_attrs   = RSVAL(p, hoff + 34);
837
838         if (h->adx_magic != AD_XATTR_HDR_MAGIC) {
839                 DBG_ERR("Bad magic: 0x%" PRIx32 "\n", h->adx_magic);
840                 return false;
841         }
842
843         if (h->adx_total_size > ad_getentryoff(ad, ADEID_RFORK)) {
844                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
845                 return false;
846         }
847         if (h->adx_total_size > AD_XATTR_MAX_HDR_SIZE) {
848                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
849                 return false;
850         }
851
852         if (h->adx_data_start < (hoff + AD_XATTR_HDR_SIZE)) {
853                 DBG_ERR("Bad start: 0x%" PRIx32 "\n", h->adx_data_start);
854                 return false;
855         }
856
857         if ((h->adx_data_start + h->adx_data_length) < h->adx_data_start) {
858                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
859                 return false;
860         }
861         if ((h->adx_data_start + h->adx_data_length) >
862             ad->adx_header.adx_total_size)
863         {
864                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
865                 return false;
866         }
867
868         if (h->adx_num_attrs > AD_XATTR_MAX_ENTRIES) {
869                 DBG_ERR("Bad num xattrs: %" PRIu16 "\n", h->adx_num_attrs);
870                 return false;
871         }
872
873         if (h->adx_num_attrs == 0) {
874                 return true;
875         }
876
877         ad->adx_entries = talloc_zero_array(
878                 ad, struct ad_xattr_entry, h->adx_num_attrs);
879         if (ad->adx_entries == NULL) {
880                 return false;
881         }
882
883         hoff += AD_XATTR_HDR_SIZE;
884
885         for (i = 0; i < h->adx_num_attrs; i++) {
886                 struct ad_xattr_entry *e = &ad->adx_entries[i];
887
888                 hoff = (hoff + 3) & ~3;
889
890                 e->adx_offset  = RIVAL(p, hoff + 0);
891                 e->adx_length  = RIVAL(p, hoff + 4);
892                 e->adx_flags   = RSVAL(p, hoff + 8);
893                 e->adx_namelen = *(p + hoff + 10);
894
895                 if (e->adx_offset >= ad->adx_header.adx_total_size) {
896                         DBG_ERR("Bad adx_offset: %" PRIx32 "\n",
897                                 e->adx_offset);
898                         return false;
899                 }
900
901                 if ((e->adx_offset + e->adx_length) < e->adx_offset) {
902                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
903                                 e->adx_length);
904                         return false;
905                 }
906
907                 if ((e->adx_offset + e->adx_length) >
908                     ad->adx_header.adx_total_size)
909                 {
910                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
911                                 e->adx_length);
912                         return false;
913                 }
914
915                 if (e->adx_namelen == 0) {
916                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
917                                 e->adx_namelen);
918                         return false;
919                 }
920                 if ((hoff + 11 + e->adx_namelen) < hoff + 11) {
921                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
922                                 e->adx_namelen);
923                         return false;
924                 }
925                 if ((hoff + 11 + e->adx_namelen) >
926                     ad->adx_header.adx_data_start)
927                 {
928                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
929                                 e->adx_namelen);
930                         return false;
931                 }
932
933                 e->adx_name = talloc_strndup(ad->adx_entries,
934                                              p + hoff + 11,
935                                              e->adx_namelen);
936                 if (e->adx_name == NULL) {
937                         return false;
938                 }
939
940                 DBG_DEBUG("xattr [%s] offset [0x%x] size [0x%x]\n",
941                           e->adx_name, e->adx_offset, e->adx_length);
942                 dump_data(10, (uint8_t *)(ad->ad_data + e->adx_offset),
943                           e->adx_length);
944
945                 hoff += 11 + e->adx_namelen;
946         }
947
948         return true;
949 }
950
951 /**
952  * Unpack an AppleDouble blob into a struct adoble
953  **/
954 static bool ad_unpack(struct adouble *ad, const size_t nentries,
955                       size_t filesize)
956 {
957         size_t bufsize = talloc_get_size(ad->ad_data);
958         size_t adentries, i;
959         uint32_t eid, len, off;
960         bool ok;
961
962         /*
963          * The size of the buffer ad->ad_data is checked when read, so
964          * we wouldn't have to check our own offsets, a few extra
965          * checks won't hurt though. We have to check the offsets we
966          * read from the buffer anyway.
967          */
968
969         if (bufsize < (AD_HEADER_LEN + (AD_ENTRY_LEN * nentries))) {
970                 DBG_NOTICE("Bad size\n");
971                 return false;
972         }
973
974         ad->ad_magic = RIVAL(ad->ad_data, 0);
975         ad->ad_version = RIVAL(ad->ad_data, ADEDOFF_VERSION);
976         if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION)) {
977                 DBG_NOTICE("Wrong magic or version\n");
978                 return false;
979         }
980
981         memcpy(ad->ad_filler, ad->ad_data + ADEDOFF_FILLER, ADEDLEN_FILLER);
982
983         adentries = RSVAL(ad->ad_data, ADEDOFF_NENTRIES);
984         if (adentries != nentries) {
985                 DBG_NOTICE("Invalid number of entries: %zu\n", adentries);
986                 return false;
987         }
988
989         /* now, read in the entry bits */
990         for (i = 0; i < adentries; i++) {
991                 eid = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN));
992                 eid = get_eid(eid);
993                 off = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 4);
994                 len = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 8);
995
996                 if (!eid || eid >= ADEID_MAX) {
997                         DBG_NOTICE("Bogus eid %d\n", eid);
998                         return false;
999                 }
1000
1001                 /*
1002                  * All entries other than the resource fork are
1003                  * expected to be read into the ad_data buffer, so
1004                  * ensure the specified offset is within that bound
1005                  */
1006                 if ((off > bufsize) && (eid != ADEID_RFORK)) {
1007                         DBG_NOTICE("Bogus eid %d: off: %" PRIu32
1008                                    ", len: %" PRIu32 "\n",
1009                                    eid,
1010                                    off,
1011                                    len);
1012                         return false;
1013                 }
1014
1015                 ok = ad_entry_check_size(eid, bufsize, off, len);
1016                 if (!ok) {
1017                         DBG_NOTICE("Bogus eid [%" PRIu32 "] bufsize [%zu] "
1018                                    "off [%" PRIu32 "] len [%" PRIu32 "]\n",
1019                                    eid,
1020                                    bufsize,
1021                                    off,
1022                                    len);
1023                         return false;
1024                 }
1025
1026                 /*
1027                  * That would be obviously broken
1028                  */
1029                 if (off > filesize) {
1030                         DBG_NOTICE("Bogus eid %d: off: %" PRIu32
1031                                    ", len: %" PRIu32 "\n",
1032                                    eid,
1033                                    off,
1034                                    len);
1035                         return false;
1036                 }
1037
1038                 /*
1039                  * Check for any entry that has its end beyond the
1040                  * filesize.
1041                  */
1042                 if (off + len < off) {
1043                         DBG_NOTICE("offset wrap in eid %d: off: %" PRIu32
1044                                    ", len: %" PRIu32 "\n",
1045                                    eid,
1046                                    off,
1047                                    len);
1048                         return false;
1049
1050                 }
1051                 if (off + len > filesize) {
1052                         /*
1053                          * If this is the resource fork entry, we fix
1054                          * up the length, for any other entry we bail
1055                          * out.
1056                          */
1057                         if (eid != ADEID_RFORK) {
1058                                 DBG_NOTICE("Bogus eid %d: off: %" PRIu32
1059                                            ", len: %" PRIu32 "\n",
1060                                            eid,
1061                                            off,
1062                                            len);
1063                                 return false;
1064                         }
1065
1066                         /*
1067                          * Fixup the resource fork entry by limiting
1068                          * the size to entryoffset - filesize.
1069                          */
1070                         len = filesize - off;
1071                         DBG_NOTICE("Limiting ADEID_RFORK: off: %" PRIu32
1072                                    ", len: %" PRIu32 "\n",
1073                                    off,
1074                                    len);
1075                 }
1076
1077                 ad->ad_eid[eid].ade_off = off;
1078                 ad->ad_eid[eid].ade_len = len;
1079         }
1080
1081         if (ad->ad_type == ADOUBLE_RSRC) {
1082                 ok = ad_unpack_xattrs(ad);
1083                 if (!ok) {
1084                         return false;
1085                 }
1086         }
1087
1088         return true;
1089 }
1090
1091 static bool ad_convert_move_reso(vfs_handle_struct *handle,
1092                                  struct adouble *ad,
1093                                  const struct smb_filename *smb_fname)
1094 {
1095         char *buf = NULL;
1096         size_t rforklen;
1097         size_t rforkoff;
1098         ssize_t n;
1099         int ret;
1100
1101         rforklen = ad_getentrylen(ad, ADEID_RFORK);
1102         if (rforklen == 0) {
1103                 return true;
1104         }
1105
1106         buf = talloc_size(ad, rforklen);
1107         if (buf == NULL) {
1108                 /*
1109                  * This allocates a buffer for reading the resource fork data in
1110                  * one big swoop. Resource forks won't be larger then, say, 64
1111                  * MB, I swear, so just doing the allocation with the talloc
1112                  * limit as safeguard seems safe.
1113                  */
1114                 DBG_ERR("Failed to allocate %zu bytes for rfork\n",
1115                         rforklen);
1116                 return false;
1117         }
1118
1119         rforkoff = ad_getentryoff(ad, ADEID_RFORK);
1120
1121         n = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, rforkoff);
1122         if (n != rforklen) {
1123                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
1124                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
1125                 return false;
1126         }
1127
1128         rforkoff = ADEDOFF_RFORK_DOT_UND;
1129
1130         n = SMB_VFS_PWRITE(ad->ad_fsp, buf, rforklen, rforkoff);
1131         if (n != rforklen) {
1132                 DBG_ERR("Writing %zu bytes to rfork [%s] failed: %s\n",
1133                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
1134                 return false;
1135         }
1136
1137         ad_setentryoff(ad, ADEID_RFORK, ADEDOFF_RFORK_DOT_UND);
1138
1139         ret = ad_fset(handle, ad, ad->ad_fsp);
1140         if (ret != 0) {
1141                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
1142                 return false;
1143         }
1144
1145         return true;
1146 }
1147
1148 static bool ad_convert_xattr(vfs_handle_struct *handle,
1149                              struct adouble *ad,
1150                              const struct smb_filename *smb_fname,
1151                              const char *catia_mappings,
1152                              bool *converted_xattr)
1153 {
1154         static struct char_mappings **string_replace_cmaps = NULL;
1155         uint16_t i;
1156         int saved_errno = 0;
1157         NTSTATUS status;
1158         int rc;
1159         bool ok;
1160
1161         *converted_xattr = false;
1162
1163         if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
1164                 return true;
1165         }
1166
1167         if (string_replace_cmaps == NULL) {
1168                 const char **mappings = NULL;
1169
1170                 mappings = str_list_make_v3_const(
1171                         talloc_tos(), catia_mappings, NULL);
1172                 if (mappings == NULL) {
1173                         return false;
1174                 }
1175                 string_replace_cmaps = string_replace_init_map(
1176                         handle->conn->sconn, mappings);
1177                 TALLOC_FREE(mappings);
1178         }
1179
1180         for (i = 0; i < ad->adx_header.adx_num_attrs; i++) {
1181                 struct ad_xattr_entry *e = &ad->adx_entries[i];
1182                 char *mapped_name = NULL;
1183                 char *tmp = NULL;
1184                 struct smb_filename *stream_name = NULL;
1185                 files_struct *fsp = NULL;
1186                 ssize_t nwritten;
1187
1188                 status = string_replace_allocate(handle->conn,
1189                                                  e->adx_name,
1190                                                  string_replace_cmaps,
1191                                                  talloc_tos(),
1192                                                  &mapped_name,
1193                                                  vfs_translate_to_windows);
1194                 if (!NT_STATUS_IS_OK(status) &&
1195                     !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
1196                 {
1197                         DBG_ERR("string_replace_allocate failed\n");
1198                         ok = false;
1199                         goto fail;
1200                 }
1201
1202                 tmp = mapped_name;
1203                 mapped_name = talloc_asprintf(talloc_tos(), ":%s", tmp);
1204                 TALLOC_FREE(tmp);
1205                 if (mapped_name == NULL) {
1206                         ok = false;
1207                         goto fail;
1208                 }
1209
1210                 stream_name = synthetic_smb_fname(talloc_tos(),
1211                                                   smb_fname->base_name,
1212                                                   mapped_name,
1213                                                   NULL,
1214                                                   smb_fname->twrp,
1215                                                   smb_fname->flags);
1216                 TALLOC_FREE(mapped_name);
1217                 if (stream_name == NULL) {
1218                         DBG_ERR("synthetic_smb_fname failed\n");
1219                         ok = false;
1220                         goto fail;
1221                 }
1222
1223                 DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
1224
1225                 status = openat_pathref_fsp(handle->conn->cwd_fsp, stream_name);
1226                 if (!NT_STATUS_IS_OK(status) &&
1227                     !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
1228                 {
1229                         ok = false;
1230                         goto fail;
1231                 }
1232
1233                 status = SMB_VFS_CREATE_FILE(
1234                         handle->conn,                   /* conn */
1235                         NULL,                           /* req */
1236                         NULL,                           /* dirfsp */
1237                         stream_name,                    /* fname */
1238                         FILE_GENERIC_WRITE,             /* access_mask */
1239                         FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* share_access */
1240                         FILE_OPEN_IF,                   /* create_disposition */
1241                         0,                              /* create_options */
1242                         0,                              /* file_attributes */
1243                         INTERNAL_OPEN_ONLY,             /* oplock_request */
1244                         NULL,                           /* lease */
1245                         0,                              /* allocation_size */
1246                         0,                              /* private_flags */
1247                         NULL,                           /* sd */
1248                         NULL,                           /* ea_list */
1249                         &fsp,                           /* result */
1250                         NULL,                           /* psbuf */
1251                         NULL, NULL);                    /* create context */
1252                 TALLOC_FREE(stream_name);
1253                 if (!NT_STATUS_IS_OK(status)) {
1254                         DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
1255                         ok = false;
1256                         goto fail;
1257                 }
1258
1259                 nwritten = SMB_VFS_PWRITE(fsp,
1260                                           ad->ad_data + e->adx_offset,
1261                                           e->adx_length,
1262                                           0);
1263                 if (nwritten == -1) {
1264                         DBG_ERR("SMB_VFS_PWRITE failed\n");
1265                         saved_errno = errno;
1266                         close_file_free(NULL, &fsp, ERROR_CLOSE);
1267                         errno = saved_errno;
1268                         ok = false;
1269                         goto fail;
1270                 }
1271
1272                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
1273                 if (!NT_STATUS_IS_OK(status)) {
1274                         ok = false;
1275                         goto fail;
1276                 }
1277                 fsp = NULL;
1278         }
1279
1280         ad->adx_header.adx_num_attrs = 0;
1281         TALLOC_FREE(ad->adx_entries);
1282
1283         ad_setentrylen(ad, ADEID_FINDERI, ADEDLEN_FINDERI);
1284
1285         rc = ad_fset(handle, ad, ad->ad_fsp);
1286         if (rc != 0) {
1287                 DBG_ERR("ad_fset on [%s] failed: %s\n",
1288                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
1289                 ok = false;
1290                 goto fail;
1291         }
1292
1293         ok = ad_convert_move_reso(handle, ad, smb_fname);
1294         if (!ok) {
1295                 goto fail;
1296         }
1297
1298         *converted_xattr = true;
1299         ok = true;
1300
1301 fail:
1302         return ok;
1303 }
1304
1305 static bool ad_convert_finderinfo(vfs_handle_struct *handle,
1306                                   struct adouble *ad,
1307                                   const struct smb_filename *smb_fname)
1308 {
1309         char *p_ad = NULL;
1310         AfpInfo *ai = NULL;
1311         DATA_BLOB aiblob;
1312         struct smb_filename *stream_name = NULL;
1313         files_struct *fsp = NULL;
1314         size_t size;
1315         ssize_t nwritten;
1316         NTSTATUS status;
1317         int saved_errno = 0;
1318         int cmp;
1319
1320         cmp = memcmp(ad->ad_filler, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
1321         if (cmp != 0) {
1322                 return true;
1323         }
1324
1325         p_ad = ad_get_entry(ad, ADEID_FINDERI);
1326         if (p_ad == NULL) {
1327                 return false;
1328         }
1329
1330         ai = afpinfo_new(talloc_tos());
1331         if (ai == NULL) {
1332                 return false;
1333         }
1334
1335         memcpy(ai->afpi_FinderInfo, p_ad, ADEDLEN_FINDERI);
1336
1337         aiblob = data_blob_talloc(talloc_tos(), NULL, AFP_INFO_SIZE);
1338         if (aiblob.data == NULL) {
1339                 TALLOC_FREE(ai);
1340                 return false;
1341         }
1342
1343         size = afpinfo_pack(ai, (char *)aiblob.data);
1344         TALLOC_FREE(ai);
1345         if (size != AFP_INFO_SIZE) {
1346                 return false;
1347         }
1348
1349         stream_name = synthetic_smb_fname(talloc_tos(),
1350                                           smb_fname->base_name,
1351                                           AFPINFO_STREAM,
1352                                           NULL,
1353                                           smb_fname->twrp,
1354                                           smb_fname->flags);
1355         if (stream_name == NULL) {
1356                 data_blob_free(&aiblob);
1357                 DBG_ERR("synthetic_smb_fname failed\n");
1358                 return false;
1359         }
1360
1361         DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
1362
1363         status = openat_pathref_fsp(handle->conn->cwd_fsp, stream_name);
1364         if (!NT_STATUS_IS_OK(status) &&
1365             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND))
1366         {
1367                 return false;
1368         }
1369
1370         status = SMB_VFS_CREATE_FILE(
1371                 handle->conn,                   /* conn */
1372                 NULL,                           /* req */
1373                 NULL,                           /* dirfsp */
1374                 stream_name,                    /* fname */
1375                 FILE_GENERIC_WRITE,             /* access_mask */
1376                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
1377                 FILE_OPEN_IF,                   /* create_disposition */
1378                 0,                              /* create_options */
1379                 0,                              /* file_attributes */
1380                 INTERNAL_OPEN_ONLY,             /* oplock_request */
1381                 NULL,                           /* lease */
1382                 0,                              /* allocation_size */
1383                 0,                              /* private_flags */
1384                 NULL,                           /* sd */
1385                 NULL,                           /* ea_list */
1386                 &fsp,                           /* result */
1387                 NULL,                           /* psbuf */
1388                 NULL, NULL);                    /* create context */
1389         TALLOC_FREE(stream_name);
1390         if (!NT_STATUS_IS_OK(status)) {
1391                 DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
1392                 return false;
1393         }
1394
1395         nwritten = SMB_VFS_PWRITE(fsp,
1396                                   aiblob.data,
1397                                   aiblob.length,
1398                                   0);
1399         if (nwritten == -1) {
1400                 DBG_ERR("SMB_VFS_PWRITE failed\n");
1401                 saved_errno = errno;
1402                 close_file_free(NULL, &fsp, ERROR_CLOSE);
1403                 errno = saved_errno;
1404                 return false;
1405         }
1406
1407         status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
1408         if (!NT_STATUS_IS_OK(status)) {
1409                 return false;
1410         }
1411         fsp = NULL;
1412
1413         return true;
1414 }
1415
1416 static bool ad_convert_truncate(vfs_handle_struct *handle,
1417                                 struct adouble *ad,
1418                                 const struct smb_filename *smb_fname)
1419 {
1420         int rc;
1421         off_t newlen;
1422
1423         newlen = ADEDOFF_RFORK_DOT_UND + ad_getentrylen(ad, ADEID_RFORK);
1424
1425         rc = SMB_VFS_FTRUNCATE(ad->ad_fsp, newlen);
1426         if (rc != 0) {
1427                 return false;
1428         }
1429
1430         return true;
1431 }
1432
1433 static bool ad_convert_blank_rfork(vfs_handle_struct *handle,
1434                                    struct adouble *ad,
1435                                    uint32_t flags,
1436                                    bool *blank)
1437 {
1438         size_t rforklen = sizeof(empty_resourcefork);
1439         char buf[rforklen];
1440         ssize_t nread;
1441         int cmp;
1442         int rc;
1443
1444         *blank = false;
1445
1446         if (!(flags & AD_CONV_WIPE_BLANK)) {
1447                 return true;
1448         }
1449
1450         if (ad_getentrylen(ad, ADEID_RFORK) != rforklen) {
1451                 return true;
1452         }
1453
1454         nread = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, ADEDOFF_RFORK_DOT_UND);
1455         if (nread != rforklen) {
1456                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
1457                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
1458                 return false;
1459         }
1460
1461         cmp = memcmp(buf, empty_resourcefork, rforklen);
1462         if (cmp != 0) {
1463                 return true;
1464         }
1465
1466         ad_setentrylen(ad, ADEID_RFORK, 0);
1467
1468         rc = ad_fset(handle, ad, ad->ad_fsp);
1469         if (rc != 0) {
1470                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
1471                 return false;
1472         }
1473
1474         *blank = true;
1475         return true;
1476 }
1477
1478 static bool ad_convert_delete_adfile(vfs_handle_struct *handle,
1479                                 struct adouble *ad,
1480                                 const struct smb_filename *smb_fname,
1481                                 uint32_t flags)
1482 {
1483         struct smb_filename *parent_fname = NULL;
1484         struct smb_filename *at_fname = NULL;
1485         struct smb_filename *ad_name = NULL;
1486         NTSTATUS status;
1487         int rc;
1488
1489         if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
1490                 return true;
1491         }
1492
1493         if (!(flags & AD_CONV_DELETE)) {
1494                 return true;
1495         }
1496
1497         rc = adouble_path(talloc_tos(), smb_fname, &ad_name);
1498         if (rc != 0) {
1499                 return false;
1500         }
1501
1502         status = parent_pathref(talloc_tos(),
1503                                 handle->conn->cwd_fsp,
1504                                 ad_name,
1505                                 &parent_fname,
1506                                 &at_fname);
1507         TALLOC_FREE(ad_name);
1508         if (!NT_STATUS_IS_OK(status)) {
1509                 return false;
1510         }
1511
1512         rc = SMB_VFS_NEXT_UNLINKAT(handle,
1513                         parent_fname->fsp,
1514                         at_fname,
1515                         0);
1516         if (rc != 0) {
1517                 DBG_ERR("Unlinking [%s/%s] failed: %s\n",
1518                         smb_fname_str_dbg(parent_fname),
1519                         smb_fname_str_dbg(at_fname), strerror(errno));
1520                 TALLOC_FREE(parent_fname);
1521                 return false;
1522         }
1523
1524         DBG_WARNING("Unlinked [%s/%s] after conversion\n",
1525                     smb_fname_str_dbg(parent_fname),
1526                     smb_fname_str_dbg(at_fname));
1527         TALLOC_FREE(parent_fname);
1528
1529         return true;
1530 }
1531
1532 /**
1533  * Convert from Apple's ._ file to Netatalk
1534  *
1535  * Apple's AppleDouble may contain a FinderInfo entry longer then 32
1536  * bytes containing packed xattrs.
1537  *
1538  * @return -1 in case an error occurred, 0 if no conversion was done, 1
1539  * otherwise
1540  **/
1541 int ad_convert(struct vfs_handle_struct *handle,
1542                 const struct smb_filename *smb_fname,
1543                 const char *catia_mappings,
1544                 uint32_t flags)
1545 {
1546         struct adouble *ad = NULL;
1547         bool ok;
1548         bool converted_xattr = false;
1549         bool blank;
1550         int ret;
1551
1552         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
1553         if (ad == NULL) {
1554                 return 0;
1555         }
1556
1557         ok = ad_convert_xattr(handle,
1558                               ad,
1559                               smb_fname,
1560                               catia_mappings,
1561                               &converted_xattr);
1562         if (!ok) {
1563                 ret = -1;
1564                 goto done;
1565         }
1566
1567         ok = ad_convert_blank_rfork(handle, ad, flags, &blank);
1568         if (!ok) {
1569                 ret = -1;
1570                 goto done;
1571         }
1572
1573         if (converted_xattr || blank) {
1574                 ok = ad_convert_truncate(handle, ad, smb_fname);
1575                 if (!ok) {
1576                         ret = -1;
1577                         goto done;
1578                 }
1579         }
1580
1581         ok = ad_convert_finderinfo(handle, ad, smb_fname);
1582         if (!ok) {
1583                 DBG_ERR("Failed to convert [%s]\n",
1584                         smb_fname_str_dbg(smb_fname));
1585                 ret = -1;
1586                 goto done;
1587         }
1588
1589         ok = ad_convert_delete_adfile(handle,
1590                         ad,
1591                         smb_fname,
1592                         flags);
1593         if (!ok) {
1594                 ret = -1;
1595                 goto done;
1596         }
1597
1598         ret = 0;
1599 done:
1600         TALLOC_FREE(ad);
1601         return ret;
1602 }
1603
1604 static bool ad_unconvert_open_ad(TALLOC_CTX *mem_ctx,
1605                                  struct vfs_handle_struct *handle,
1606                                  struct smb_filename *smb_fname,
1607                                  struct smb_filename *adpath,
1608                                  files_struct **_fsp)
1609 {
1610         files_struct *fsp = NULL;
1611         NTSTATUS status;
1612         int ret;
1613
1614         status = openat_pathref_fsp(handle->conn->cwd_fsp, adpath);
1615         if (!NT_STATUS_IS_OK(status) &&
1616             !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
1617                 return false;
1618         }
1619
1620         status = SMB_VFS_CREATE_FILE(
1621                 handle->conn,
1622                 NULL,                           /* req */
1623                 NULL,                           /* dirfsp */
1624                 adpath,
1625                 FILE_READ_DATA|FILE_WRITE_DATA,
1626                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
1627                 FILE_OPEN_IF,
1628                 0,                              /* create_options */
1629                 0,                              /* file_attributes */
1630                 INTERNAL_OPEN_ONLY,
1631                 NULL,                           /* lease */
1632                 0,                              /* allocation_size */
1633                 0,                              /* private_flags */
1634                 NULL,                           /* sd */
1635                 NULL,                           /* ea_list */
1636                 &fsp,
1637                 NULL,                           /* info */
1638                 NULL, NULL);                    /* create context */
1639         if (!NT_STATUS_IS_OK(status)) {
1640                 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed: %s\n",
1641                         smb_fname_str_dbg(adpath), nt_errstr(status));
1642                 return false;
1643         }
1644
1645         if (fsp->fsp_name->st.st_ex_uid != smb_fname->st.st_ex_uid ||
1646             fsp->fsp_name->st.st_ex_gid != smb_fname->st.st_ex_gid)
1647         {
1648                 ret = SMB_VFS_FCHOWN(fsp,
1649                                      smb_fname->st.st_ex_uid,
1650                                      smb_fname->st.st_ex_gid);
1651                 if (ret != 0) {
1652                         DBG_ERR("SMB_VFS_FCHOWN [%s] failed: %s\n",
1653                                 fsp_str_dbg(fsp), nt_errstr(status));
1654                         close_file_free(NULL, &fsp, NORMAL_CLOSE);
1655                         return false;
1656                 }
1657         }
1658
1659         *_fsp = fsp;
1660         return true;
1661 }
1662
1663 static bool ad_unconvert_get_streams(struct vfs_handle_struct *handle,
1664                                      struct smb_filename *smb_fname,
1665                                      TALLOC_CTX *mem_ctx,
1666                                      unsigned int *num_streams,
1667                                      struct stream_struct **streams)
1668 {
1669         files_struct *fsp = NULL;
1670         NTSTATUS status;
1671
1672         status = openat_pathref_fsp(handle->conn->cwd_fsp, smb_fname);
1673         if (!NT_STATUS_IS_OK(status)) {
1674                 return false;
1675         }
1676
1677         status = SMB_VFS_CREATE_FILE(
1678                 handle->conn,                           /* conn */
1679                 NULL,                                   /* req */
1680                 NULL,                                   /* dirfsp */
1681                 smb_fname,                              /* fname */
1682                 FILE_READ_ATTRIBUTES,                   /* access_mask */
1683                 (FILE_SHARE_READ | FILE_SHARE_WRITE |   /* share_access */
1684                         FILE_SHARE_DELETE),
1685                 FILE_OPEN,                              /* create_disposition*/
1686                 0,                                      /* create_options */
1687                 0,                                      /* file_attributes */
1688                 INTERNAL_OPEN_ONLY,                     /* oplock_request */
1689                 NULL,                                   /* lease */
1690                 0,                                      /* allocation_size */
1691                 0,                                      /* private_flags */
1692                 NULL,                                   /* sd */
1693                 NULL,                                   /* ea_list */
1694                 &fsp,                                   /* result */
1695                 NULL,                                   /* pinfo */
1696                 NULL, NULL);                            /* create context */
1697         if (!NT_STATUS_IS_OK(status)) {
1698                 DBG_ERR("Opening [%s] failed: %s\n",
1699                         smb_fname_str_dbg(smb_fname),
1700                         nt_errstr(status));
1701                 return false;
1702         }
1703
1704         status = vfs_fstreaminfo(fsp,
1705                                 mem_ctx,
1706                                 num_streams,
1707                                 streams);
1708         if (!NT_STATUS_IS_OK(status)) {
1709                 close_file_free(NULL, &fsp, NORMAL_CLOSE);
1710                 DBG_ERR("streaminfo on [%s] failed: %s\n",
1711                         smb_fname_str_dbg(smb_fname),
1712                         nt_errstr(status));
1713                 return false;
1714         }
1715
1716         status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
1717         if (!NT_STATUS_IS_OK(status)) {
1718                 DBG_ERR("close_file [%s] failed: %s\n",
1719                         smb_fname_str_dbg(smb_fname),
1720                         nt_errstr(status));
1721                 return false;
1722         }
1723
1724         return true;
1725 }
1726
1727 struct ad_collect_state {
1728         bool have_adfile;
1729         size_t adx_data_off;
1730         char *rsrc_data_buf;
1731 };
1732
1733 static bool ad_collect_one_stream(struct vfs_handle_struct *handle,
1734                                   struct char_mappings **cmaps,
1735                                   struct smb_filename *smb_fname,
1736                                   const struct stream_struct *stream,
1737                                   struct adouble *ad,
1738                                   struct ad_collect_state *state)
1739 {
1740         struct smb_filename *sname = NULL;
1741         files_struct *fsp = NULL;
1742         struct ad_xattr_entry *e = NULL;
1743         char *mapped_name = NULL;
1744         char *p = NULL;
1745         size_t needed_size;
1746         ssize_t nread;
1747         NTSTATUS status;
1748         bool ok;
1749
1750         sname = synthetic_smb_fname(ad,
1751                                     smb_fname->base_name,
1752                                     stream->name,
1753                                     NULL,
1754                                     smb_fname->twrp,
1755                                     0);
1756         if (sname == NULL) {
1757                 return false;
1758         }
1759
1760         if (is_ntfs_default_stream_smb_fname(sname)) {
1761                 TALLOC_FREE(sname);
1762                 return true;
1763         }
1764
1765         DBG_DEBUG("Collecting stream [%s]\n", smb_fname_str_dbg(sname));
1766
1767         status = openat_pathref_fsp(handle->conn->cwd_fsp, sname);
1768         if (!NT_STATUS_IS_OK(status)) {
1769                 ok = false;
1770                 goto out;
1771         }
1772
1773         status = SMB_VFS_CREATE_FILE(
1774                 handle->conn,
1775                 NULL,                           /* req */
1776                 NULL,                           /* dirfsp */
1777                 sname,
1778                 FILE_READ_DATA|DELETE_ACCESS,
1779                 FILE_SHARE_READ,
1780                 FILE_OPEN,
1781                 0,                              /* create_options */
1782                 0,                              /* file_attributes */
1783                 INTERNAL_OPEN_ONLY,             /* oplock_request */
1784                 NULL,                           /* lease */
1785                 0,                              /* allocation_size */
1786                 0,                              /* private_flags */
1787                 NULL,                           /* sd */
1788                 NULL,                           /* ea_list */
1789                 &fsp,
1790                 NULL,                           /* info */
1791                 NULL, NULL);                    /* create context */
1792         if (!NT_STATUS_IS_OK(status)) {
1793                 DBG_ERR("SMB_VFS_CREATE_FILE [%s] failed\n",
1794                         smb_fname_str_dbg(sname));
1795                 ok = false;
1796                 goto out;
1797         }
1798
1799         if (is_afpinfo_stream(stream->name)) {
1800                 char buf[AFP_INFO_SIZE];
1801
1802                 if (stream->size != AFP_INFO_SIZE) {
1803                         DBG_ERR("Bad size [%zd] on [%s]\n",
1804                                 (ssize_t)stream->size,
1805                                 smb_fname_str_dbg(sname));
1806                         ok = false;
1807                         goto out;
1808                 }
1809
1810                 nread = SMB_VFS_PREAD(fsp, buf, stream->size, 0);
1811                 if (nread != AFP_INFO_SIZE) {
1812                         DBG_ERR("Bad size [%zd] on [%s]\n",
1813                                 (ssize_t)stream->size,
1814                                 smb_fname_str_dbg(sname));
1815                         ok = false;
1816                         goto out;
1817                 }
1818
1819                 memcpy(ad->ad_data + ADEDOFF_FINDERI_DOT_UND,
1820                        buf + AFP_OFF_FinderInfo,
1821                        AFP_FinderSize);
1822
1823                 ok = set_delete_on_close(fsp,
1824                                          true,
1825                                          fsp->conn->session_info->security_token,
1826                                          fsp->conn->session_info->unix_token);
1827                 if (!ok) {
1828                         DBG_ERR("Deleting [%s] failed\n",
1829                                 smb_fname_str_dbg(sname));
1830                         ok = false;
1831                         goto out;
1832                 }
1833                 ok = true;
1834                 goto out;
1835         }
1836
1837         if (is_afpresource_stream(stream->name)) {
1838                 ad->ad_rsrc_data = talloc_size(ad, stream->size);
1839                 if (ad->ad_rsrc_data == NULL) {
1840                         ok = false;
1841                         goto out;
1842                 }
1843
1844                 nread = SMB_VFS_PREAD(fsp,
1845                                       ad->ad_rsrc_data,
1846                                       stream->size,
1847                                       0);
1848                 if (nread != stream->size) {
1849                         DBG_ERR("Bad size [%zd] on [%s]\n",
1850                                 (ssize_t)stream->size,
1851                                 smb_fname_str_dbg(sname));
1852                         ok = false;
1853                         goto out;
1854                 }
1855
1856                 ad_setentrylen(ad, ADEID_RFORK, stream->size);
1857
1858                 if (!state->have_adfile) {
1859                         /*
1860                          * We have a resource *stream* but no AppleDouble
1861                          * sidecar file, this means the share is configured with
1862                          * fruit:resource=stream. So we should delete the
1863                          * resource stream.
1864                          */
1865                         ok = set_delete_on_close(
1866                                 fsp,
1867                                 true,
1868                                 fsp->conn->session_info->security_token,
1869                                 fsp->conn->session_info->unix_token);
1870                         if (!ok) {
1871                                 DBG_ERR("Deleting [%s] failed\n",
1872                                         smb_fname_str_dbg(sname));
1873                                 ok = false;
1874                                 goto out;
1875                         }
1876                 }
1877                 ok = true;
1878                 goto out;
1879         }
1880
1881         ad->adx_entries = talloc_realloc(ad,
1882                                          ad->adx_entries,
1883                                          struct ad_xattr_entry,
1884                                          ad->adx_header.adx_num_attrs + 1);
1885         if (ad->adx_entries == NULL) {
1886                 ok = false;
1887                 goto out;
1888         }
1889
1890         e = &ad->adx_entries[ad->adx_header.adx_num_attrs];
1891         *e = (struct ad_xattr_entry) {
1892                 .adx_length = stream->size,
1893         };
1894         e->adx_name = talloc_strdup(ad, stream->name + 1);
1895         if (e->adx_name == NULL) {
1896                 ok = false;
1897                 goto out;
1898         }
1899         p = strchr(e->adx_name, ':');
1900         if (p != NULL) {
1901                 *p = '\0';
1902         }
1903
1904         status = string_replace_allocate(handle->conn,
1905                                          e->adx_name,
1906                                          cmaps,
1907                                          ad,
1908                                          &mapped_name,
1909                                          vfs_translate_to_unix);
1910         if (!NT_STATUS_IS_OK(status) &&
1911             !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
1912         {
1913                 DBG_ERR("string_replace_allocate failed\n");
1914                 ok = false;
1915                 goto out;
1916         }
1917
1918         e->adx_name = mapped_name;
1919         e->adx_namelen = strlen(e->adx_name) + 1,
1920
1921         DBG_DEBUG("%u: name (%s) size (%zu)\n",
1922                   ad->adx_header.adx_num_attrs,
1923                   e->adx_name,
1924                   (size_t)e->adx_length);
1925
1926         ad->adx_header.adx_num_attrs++;
1927
1928         needed_size = state->adx_data_off + stream->size;
1929         if (needed_size > talloc_get_size(ad->adx_data)) {
1930                 ad->adx_data = talloc_realloc(ad,
1931                                               ad->adx_data,
1932                                               char,
1933                                               needed_size);
1934                 if (ad->adx_data == NULL) {
1935                         ok = false;
1936                         goto out;
1937                 }
1938         }
1939
1940         nread = SMB_VFS_PREAD(fsp,
1941                               ad->adx_data + state->adx_data_off,
1942                               stream->size,
1943                               0);
1944         if (nread != stream->size) {
1945                 DBG_ERR("Bad size [%zd] on [%s]\n",
1946                         (ssize_t)stream->size,
1947                         smb_fname_str_dbg(sname));
1948                 ok = false;
1949                 goto out;
1950         }
1951         state->adx_data_off += nread;
1952
1953         ok = set_delete_on_close(fsp,
1954                                  true,
1955                                  fsp->conn->session_info->security_token,
1956                                  fsp->conn->session_info->unix_token);
1957         if (!ok) {
1958                 DBG_ERR("Deleting [%s] failed\n",
1959                         smb_fname_str_dbg(sname));
1960                 ok = false;
1961                 goto out;
1962         }
1963
1964 out:
1965         TALLOC_FREE(sname);
1966         if (fsp != NULL) {
1967                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
1968                 if (!NT_STATUS_IS_OK(status)) {
1969                         DBG_ERR("close_file [%s] failed: %s\n",
1970                                 smb_fname_str_dbg(smb_fname),
1971                                 nt_errstr(status));
1972                         ok = false;
1973                 }
1974         }
1975
1976         return ok;
1977 }
1978
1979 /**
1980  * Convert filesystem metadata to AppleDouble file
1981  **/
1982 bool ad_unconvert(TALLOC_CTX *mem_ctx,
1983                   struct vfs_handle_struct *handle,
1984                   const char *catia_mappings,
1985                   struct smb_filename *smb_fname,
1986                   bool *converted)
1987 {
1988         static struct char_mappings **cmaps = NULL;
1989         TALLOC_CTX *frame = talloc_stackframe();
1990         struct ad_collect_state state;
1991         struct stream_struct *streams = NULL;
1992         struct smb_filename *adpath = NULL;
1993         struct adouble *ad = NULL;
1994         unsigned int num_streams = 0;
1995         size_t to_convert = 0;
1996         bool have_rsrc = false;
1997         files_struct *fsp = NULL;
1998         size_t i;
1999         NTSTATUS status;
2000         int ret;
2001         bool ok;
2002
2003         *converted = false;
2004
2005         if (cmaps == NULL) {
2006                 const char **mappings = NULL;
2007
2008                 mappings = str_list_make_v3_const(
2009                         frame, catia_mappings, NULL);
2010                 if (mappings == NULL) {
2011                         ok = false;
2012                         goto out;
2013                 }
2014                 cmaps = string_replace_init_map(mem_ctx, mappings);
2015                 TALLOC_FREE(mappings);
2016         }
2017
2018         ok = ad_unconvert_get_streams(handle,
2019                                       smb_fname,
2020                                       frame,
2021                                       &num_streams,
2022                                       &streams);
2023         if (!ok) {
2024                 goto out;
2025         }
2026
2027         for (i = 0; i < num_streams; i++) {
2028                 if (strcasecmp_m(streams[i].name, "::$DATA") == 0) {
2029                         continue;
2030                 }
2031                 to_convert++;
2032                 if (is_afpresource_stream(streams[i].name)) {
2033                         have_rsrc = true;
2034                 }
2035         }
2036
2037         if (to_convert == 0) {
2038                 ok = true;
2039                 goto out;
2040         }
2041
2042         state = (struct ad_collect_state) {
2043                 .adx_data_off = 0,
2044         };
2045
2046         ret = adouble_path(frame, smb_fname, &adpath);
2047         if (ret != 0) {
2048                 ok = false;
2049                 goto out;
2050         }
2051
2052         ret = SMB_VFS_STAT(handle->conn, adpath);
2053         if (ret == 0) {
2054                 state.have_adfile = true;
2055         } else {
2056                 if (errno != ENOENT) {
2057                         ok = false;
2058                         goto out;
2059                 }
2060                 state.have_adfile = false;
2061         }
2062
2063         if (to_convert == 1 && have_rsrc && state.have_adfile) {
2064                 /*
2065                  * So we have just a single stream, the resource fork stream
2066                  * from an AppleDouble file. Fine, that means there's nothing to
2067                  * convert.
2068                  */
2069                 ok = true;
2070                 goto out;
2071         }
2072
2073         ad = ad_init(frame, ADOUBLE_RSRC);
2074         if (ad == NULL) {
2075                 ok = false;
2076                 goto out;
2077         }
2078
2079         for (i = 0; i < num_streams; i++) {
2080                 ok = ad_collect_one_stream(handle,
2081                                            cmaps,
2082                                            smb_fname,
2083                                            &streams[i],
2084                                            ad,
2085                                            &state);
2086                 if (!ok) {
2087                         goto out;
2088                 }
2089         }
2090
2091         ok = ad_unconvert_open_ad(frame, handle, smb_fname, adpath, &fsp);
2092         if (!ok) {
2093                 DBG_ERR("Failed to open adfile [%s]\n",
2094                         smb_fname_str_dbg(smb_fname));
2095                 goto out;
2096         }
2097
2098         ret = ad_fset(handle, ad, fsp);
2099         if (ret != 0) {
2100                 ok = false;
2101                 goto out;
2102         }
2103
2104         *converted = true;
2105         ok = true;
2106
2107 out:
2108         if (fsp != NULL) {
2109                 status = close_file_free(NULL, &fsp, NORMAL_CLOSE);
2110                 if (!NT_STATUS_IS_OK(status)) {
2111                         DBG_ERR("close_file_free() [%s] failed: %s\n",
2112                                 smb_fname_str_dbg(smb_fname),
2113                                 nt_errstr(status));
2114                         ok = false;
2115                 }
2116         }
2117         TALLOC_FREE(frame);
2118         return ok;
2119 }
2120
2121 /**
2122  * Read and parse Netatalk AppleDouble metadata xattr
2123  **/
2124 static ssize_t ad_read_meta(vfs_handle_struct *handle,
2125                             struct adouble *ad,
2126                             const struct smb_filename *smb_fname)
2127 {
2128         int      rc = 0;
2129         ssize_t  ealen;
2130         bool     ok;
2131         struct files_struct *fsp = smb_fname->fsp;
2132
2133         DEBUG(10, ("reading meta xattr for %s\n", smb_fname->base_name));
2134
2135         fsp = metadata_fsp(fsp);
2136
2137         ealen = SMB_VFS_FGETXATTR(fsp,
2138                                   AFPINFO_EA_NETATALK,
2139                                   ad->ad_data,
2140                                   AD_DATASZ_XATTR);
2141
2142         if (ealen == -1) {
2143                 switch (errno) {
2144                 case ENOATTR:
2145                 case ENOENT:
2146                         if (errno == ENOATTR) {
2147                                 errno = ENOENT;
2148                         }
2149                         rc = -1;
2150                         goto exit;
2151                 default:
2152                         DEBUG(2, ("error reading meta xattr: %s\n",
2153                                   strerror(errno)));
2154                         rc = -1;
2155                         goto exit;
2156                 }
2157         }
2158         if (ealen != AD_DATASZ_XATTR) {
2159                 DEBUG(2, ("bad size %zd\n", ealen));
2160                 errno = EINVAL;
2161                 rc = -1;
2162                 goto exit;
2163         }
2164
2165         /* Now parse entries */
2166         ok = ad_unpack(ad, ADEID_NUM_XATTR, AD_DATASZ_XATTR);
2167         if (!ok) {
2168                 DBG_WARNING(
2169                         "Invalid AppleDouble xattr metadata (%s) in file: %s - "
2170                         "Consider deleting the corrupted file.\n",
2171                         smb_fname->base_name,
2172                         ad->ad_fsp->fsp_name->base_name);
2173                 errno = EINVAL;
2174                 rc = -1;
2175                 goto exit;
2176         }
2177
2178         if (!ad_getentryoff(ad, ADEID_FINDERI)
2179             || !ad_getentryoff(ad, ADEID_COMMENT)
2180             || !ad_getentryoff(ad, ADEID_FILEDATESI)
2181             || !ad_getentryoff(ad, ADEID_AFPFILEI)
2182             || !ad_getentryoff(ad, ADEID_PRIVDEV)
2183             || !ad_getentryoff(ad, ADEID_PRIVINO)
2184             || !ad_getentryoff(ad, ADEID_PRIVSYN)
2185             || !ad_getentryoff(ad, ADEID_PRIVID)) {
2186                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
2187                 errno = EINVAL;
2188                 rc = -1;
2189                 goto exit;
2190         }
2191
2192 exit:
2193         DEBUG(10, ("reading meta xattr for %s, rc: %d\n",
2194                 smb_fname->base_name, rc));
2195
2196         if (rc != 0) {
2197                 ealen = -1;
2198                 if (errno == EINVAL) {
2199                         become_root();
2200                         (void)SMB_VFS_FREMOVEXATTR(fsp,
2201                                                    AFPINFO_EA_NETATALK);
2202                         unbecome_root();
2203                         errno = ENOENT;
2204                 }
2205         }
2206         return ealen;
2207 }
2208
2209 static NTSTATUS adouble_open_rsrc_fsp(const struct files_struct *dirfsp,
2210                                       const struct smb_filename *smb_base_fname,
2211                                       int in_flags,
2212                                       mode_t mode,
2213                                       struct files_struct **_ad_fsp)
2214 {
2215         int rc = 0;
2216         struct adouble *ad = NULL;
2217         struct smb_filename *adp_smb_fname = NULL;
2218         struct files_struct *ad_fsp = NULL;
2219         NTSTATUS status;
2220         struct vfs_open_how how = { .flags = in_flags, .mode = mode, };
2221
2222         rc = adouble_path(talloc_tos(),
2223                           smb_base_fname,
2224                           &adp_smb_fname);
2225         if (rc != 0) {
2226                 return NT_STATUS_NO_MEMORY;
2227         }
2228
2229         status = create_internal_fsp(dirfsp->conn,
2230                                      adp_smb_fname,
2231                                      &ad_fsp);
2232         if (!NT_STATUS_IS_OK(status)) {
2233                 return status;
2234         }
2235
2236 #ifdef O_PATH
2237         how.flags &= ~(O_PATH);
2238 #endif
2239         if (how.flags & (O_CREAT | O_TRUNC | O_WRONLY)) {
2240                 /* We always need read/write access for the metadata header too */
2241                 how.flags &= ~(O_WRONLY);
2242                 how.flags |= O_RDWR;
2243         }
2244
2245         status = fd_openat(dirfsp,
2246                            adp_smb_fname,
2247                            ad_fsp,
2248                            &how);
2249         if (!NT_STATUS_IS_OK(status)) {
2250                 file_free(NULL, ad_fsp);
2251                 return status;
2252         }
2253
2254         if (how.flags & (O_CREAT | O_TRUNC)) {
2255                 ad = ad_init(talloc_tos(), ADOUBLE_RSRC);
2256                 if (ad == NULL) {
2257                         file_free(NULL, ad_fsp);
2258                         return NT_STATUS_NO_MEMORY;
2259                 }
2260
2261                 rc = ad_fset(ad_fsp->conn->vfs_handles, ad, ad_fsp);
2262                 if (rc != 0) {
2263                         file_free(NULL, ad_fsp);
2264                         return NT_STATUS_IO_DEVICE_ERROR;
2265                 }
2266                 TALLOC_FREE(ad);
2267         }
2268
2269         *_ad_fsp = ad_fsp;
2270         return NT_STATUS_OK;
2271 }
2272
2273 NTSTATUS adouble_open_from_base_fsp(const struct files_struct *dirfsp,
2274                                     struct files_struct *base_fsp,
2275                                     adouble_type_t type,
2276                                     int flags,
2277                                     mode_t mode,
2278                                     struct files_struct **_ad_fsp)
2279 {
2280         *_ad_fsp = NULL;
2281
2282         SMB_ASSERT(base_fsp != NULL);
2283         SMB_ASSERT(!fsp_is_alternate_stream(base_fsp));
2284
2285         switch (type) {
2286         case ADOUBLE_META:
2287                 return NT_STATUS_INTERNAL_ERROR;
2288         case ADOUBLE_RSRC:
2289                 return adouble_open_rsrc_fsp(dirfsp,
2290                                              base_fsp->fsp_name,
2291                                              flags,
2292                                              mode,
2293                                              _ad_fsp);
2294         }
2295
2296         return NT_STATUS_INTERNAL_ERROR;
2297 }
2298
2299 /*
2300  * Here's the deal: for ADOUBLE_META we can do without an fd as we can issue
2301  * path based xattr calls. For ADOUBLE_RSRC however we need a full-fledged fd
2302  * for file IO on the ._ file.
2303  */
2304 static int ad_open(vfs_handle_struct *handle,
2305                    struct adouble *ad,
2306                    files_struct *fsp,
2307                    const struct smb_filename *smb_fname,
2308                    int flags,
2309                    mode_t mode)
2310 {
2311         NTSTATUS status;
2312
2313         DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name,
2314                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
2315
2316         if (ad->ad_type == ADOUBLE_META) {
2317                 return 0;
2318         }
2319
2320         if (fsp != NULL) {
2321                 ad->ad_fsp = fsp;
2322                 ad->ad_opened = false;
2323                 return 0;
2324         }
2325
2326         status = adouble_open_rsrc_fsp(handle->conn->cwd_fsp,
2327                                        smb_fname,
2328                                        flags,
2329                                        mode,
2330                                        &ad->ad_fsp);
2331         if (!NT_STATUS_IS_OK(status)) {
2332                 errno = map_errno_from_nt_status(status);
2333                 return -1;
2334         }
2335         ad->ad_opened = true;
2336
2337         DBG_DEBUG("Path [%s] type [%s]\n",
2338                   smb_fname->base_name,
2339                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
2340
2341         return 0;
2342 }
2343
2344 static ssize_t ad_read_rsrc_adouble(vfs_handle_struct *handle,
2345                                     struct adouble *ad,
2346                                     const struct smb_filename *smb_fname)
2347 {
2348         size_t to_read;
2349         ssize_t len;
2350         int ret;
2351         bool ok;
2352
2353         ret = SMB_VFS_NEXT_FSTAT(handle, ad->ad_fsp, &ad->ad_fsp->fsp_name->st);
2354         if (ret != 0) {
2355                 DBG_ERR("fstat [%s] failed: %s\n",
2356                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
2357                 return -1;
2358         }
2359
2360         to_read = ad->ad_fsp->fsp_name->st.st_ex_size;
2361         if (to_read > AD_XATTR_MAX_HDR_SIZE) {
2362                 to_read = AD_XATTR_MAX_HDR_SIZE;
2363         }
2364
2365         len = SMB_VFS_NEXT_PREAD(handle,
2366                                  ad->ad_fsp,
2367                                  ad->ad_data,
2368                                  to_read,
2369                                  0);
2370         if (len != to_read)  {
2371                 DBG_NOTICE("%s %s: bad size: %zd\n",
2372                            smb_fname->base_name, strerror(errno), len);
2373                 return -1;
2374         }
2375
2376         /* Now parse entries */
2377         ok = ad_unpack(ad,
2378                        ADEID_NUM_DOT_UND,
2379                        ad->ad_fsp->fsp_name->st.st_ex_size);
2380         if (!ok) {
2381                 DBG_WARNING("Invalid AppleDouble resource (%s) in file: %s - "
2382                             "Consider deleting the corrupted file.\n",
2383                             smb_fname->base_name,
2384                             ad->ad_fsp->fsp_name->base_name);
2385                 errno = EINVAL;
2386                 return -1;
2387         }
2388
2389         if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
2390             || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
2391             || (ad_getentryoff(ad, ADEID_RFORK) < ADEDOFF_RFORK_DOT_UND))
2392         {
2393                 DBG_WARNING("Invalid AppleDouble resource (%s) in file: %s - "
2394                             "Consider deleting the corrupted file.\n",
2395                             smb_fname->base_name,
2396                             ad->ad_fsp->fsp_name->base_name);
2397                 errno = EINVAL;
2398                 return -1;
2399         }
2400
2401         return len;
2402 }
2403
2404 /**
2405  * Read and parse resource fork, either ._ AppleDouble file or xattr
2406  **/
2407 static ssize_t ad_read_rsrc(vfs_handle_struct *handle,
2408                             struct adouble *ad,
2409                             const struct smb_filename *smb_fname)
2410 {
2411         return ad_read_rsrc_adouble(handle, ad, smb_fname);
2412 }
2413
2414 /**
2415  * Read and unpack an AppleDouble metadata xattr or resource
2416  **/
2417 static ssize_t ad_read(vfs_handle_struct *handle,
2418                        struct adouble *ad,
2419                        const struct smb_filename *smb_fname)
2420 {
2421         switch (ad->ad_type) {
2422         case ADOUBLE_META:
2423                 return ad_read_meta(handle, ad, smb_fname);
2424         case ADOUBLE_RSRC:
2425                 return ad_read_rsrc(handle, ad, smb_fname);
2426         default:
2427                 return -1;
2428         }
2429 }
2430
2431 static int adouble_destructor(struct adouble *ad)
2432 {
2433         NTSTATUS status;
2434
2435         if (!ad->ad_opened) {
2436                 return 0;
2437         }
2438
2439         SMB_ASSERT(ad->ad_fsp != NULL);
2440
2441         status = fd_close(ad->ad_fsp);
2442         if (!NT_STATUS_IS_OK(status)) {
2443                 DBG_ERR("Closing [%s] failed: %s\n",
2444                         fsp_str_dbg(ad->ad_fsp), nt_errstr(status));
2445         }
2446         file_free(NULL, ad->ad_fsp);
2447         ad->ad_fsp = NULL;
2448         ad->ad_opened = false;
2449
2450         return 0;
2451 }
2452
2453 /**
2454  * Allocate a struct adouble without initialiing it
2455  *
2456  * The struct is either hang of the fsp extension context or if fsp is
2457  * NULL from ctx.
2458  *
2459  * @param[in] ctx        talloc context
2460  * @param[in] handle     vfs handle
2461  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
2462  *
2463  * @return               adouble handle
2464  **/
2465 static struct adouble *ad_alloc(TALLOC_CTX *ctx,
2466                                 adouble_type_t type)
2467 {
2468         int rc = 0;
2469         size_t adsize = 0;
2470         struct adouble *ad;
2471
2472         switch (type) {
2473         case ADOUBLE_META:
2474                 adsize = AD_DATASZ_XATTR;
2475                 break;
2476         case ADOUBLE_RSRC:
2477                 /*
2478                  * AppleDouble ._ file case, optimize for fewer (but larger)
2479                  * IOs. Two cases:
2480                  *
2481                  * - without xattrs size of the header is exactly
2482                  *   AD_DATASZ_DOT_UND (82) bytes
2483                  *
2484                  * - with embedded xattrs it can be larger, up to
2485                  *   AD_XATTR_MAX_HDR_SIZE
2486                  *
2487                  * Larger headers are not supported, but this is a reasonable
2488                  * limit that is also employed by the macOS client.
2489                  *
2490                  * We used the largest possible size to be able to read the full
2491                  * header with one IO.
2492                  */
2493                 adsize = AD_XATTR_MAX_HDR_SIZE;
2494                 break;
2495         default:
2496                 return NULL;
2497         }
2498
2499         ad = talloc_zero(ctx, struct adouble);
2500         if (ad == NULL) {
2501                 rc = -1;
2502                 goto exit;
2503         }
2504
2505         if (adsize) {
2506                 ad->ad_data = talloc_zero_array(ad, char, adsize);
2507                 if (ad->ad_data == NULL) {
2508                         rc = -1;
2509                         goto exit;
2510                 }
2511         }
2512
2513         ad->ad_type = type;
2514         ad->ad_magic = AD_MAGIC;
2515         ad->ad_version = AD_VERSION;
2516
2517         talloc_set_destructor(ad, adouble_destructor);
2518
2519 exit:
2520         if (rc != 0) {
2521                 TALLOC_FREE(ad);
2522         }
2523         return ad;
2524 }
2525
2526 /**
2527  * Allocate and initialize a new struct adouble
2528  *
2529  * @param[in] ctx        talloc context
2530  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
2531  *
2532  * @return               adouble handle, initialized
2533  **/
2534 struct adouble *ad_init(TALLOC_CTX *ctx, adouble_type_t type)
2535 {
2536         int rc = 0;
2537         const struct ad_entry_order  *eid;
2538         struct adouble *ad = NULL;
2539         time_t t = time(NULL);
2540
2541         switch (type) {
2542         case ADOUBLE_META:
2543                 eid = entry_order_meta_xattr;
2544                 break;
2545         case ADOUBLE_RSRC:
2546                 eid = entry_order_dot_und;
2547                 break;
2548         default:
2549                 return NULL;
2550         }
2551
2552         ad = ad_alloc(ctx, type);
2553         if (ad == NULL) {
2554                 return NULL;
2555         }
2556
2557         while (eid->id) {
2558                 ad->ad_eid[eid->id].ade_off = eid->offset;
2559                 ad->ad_eid[eid->id].ade_len = eid->len;
2560                 eid++;
2561         }
2562
2563         /* put something sane in the date fields */
2564         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, t);
2565         ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, t);
2566         ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, t);
2567         ad_setdate(ad, AD_DATE_BACKUP, htonl(AD_DATE_START));
2568
2569         if (rc != 0) {
2570                 TALLOC_FREE(ad);
2571         }
2572         return ad;
2573 }
2574
2575 static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
2576                                        vfs_handle_struct *handle,
2577                                        files_struct *fsp,
2578                                        const struct smb_filename *smb_fname,
2579                                        adouble_type_t type)
2580 {
2581         int rc = 0;
2582         ssize_t len;
2583         struct adouble *ad = NULL;
2584         int mode;
2585
2586         if (fsp != NULL) {
2587                 if (fsp_is_alternate_stream(fsp)) {
2588                         smb_fname = fsp->base_fsp->fsp_name;
2589                 } else {
2590                         smb_fname = fsp->fsp_name;
2591                 }
2592         }
2593
2594         DEBUG(10, ("ad_get(%s) called for %s\n",
2595                    type == ADOUBLE_META ? "meta" : "rsrc",
2596                    smb_fname != NULL ? smb_fname->base_name : "???"));
2597
2598         ad = ad_alloc(ctx, type);
2599         if (ad == NULL) {
2600                 rc = -1;
2601                 goto exit;
2602         }
2603
2604         /* Try rw first so we can use the fd in ad_convert() */
2605         mode = O_RDWR;
2606
2607         rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
2608         if (rc == -1 && ((errno == EROFS) || (errno == EACCES))) {
2609                 mode = O_RDONLY;
2610                 rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
2611         }
2612         if (rc == -1) {
2613                 DBG_DEBUG("ad_open [%s] error [%s]\n",
2614                           smb_fname->base_name, strerror(errno));
2615                 goto exit;
2616
2617         }
2618
2619         len = ad_read(handle, ad, smb_fname);
2620         if (len == -1) {
2621                 DEBUG(10, ("error reading AppleDouble for %s\n",
2622                         smb_fname->base_name));
2623                 rc = -1;
2624                 goto exit;
2625         }
2626
2627 exit:
2628         DEBUG(10, ("ad_get(%s) for %s returning %d\n",
2629                   type == ADOUBLE_META ? "meta" : "rsrc",
2630                   smb_fname->base_name, rc));
2631
2632         if (rc != 0) {
2633                 TALLOC_FREE(ad);
2634         }
2635         return ad;
2636 }
2637
2638 /**
2639  * Return AppleDouble data for a file
2640  *
2641  * @param[in] ctx      talloc context
2642  * @param[in] handle   vfs handle
2643  * @param[in] smb_fname pathname to file or directory
2644  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
2645  *
2646  * @return             talloced struct adouble or NULL on error
2647  **/
2648 struct adouble *ad_get(TALLOC_CTX *ctx,
2649                               vfs_handle_struct *handle,
2650                               const struct smb_filename *smb_fname,
2651                               adouble_type_t type)
2652 {
2653         return ad_get_internal(ctx, handle, NULL, smb_fname, type);
2654 }
2655
2656 /**
2657  * Return AppleDouble data for a file
2658  *
2659  * @param[in] ctx      talloc context
2660  * @param[in] handle   vfs handle
2661  * @param[in] fsp      fsp to use for IO
2662  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
2663  *
2664  * @return             talloced struct adouble or NULL on error
2665  **/
2666 struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
2667                         files_struct *fsp, adouble_type_t type)
2668 {
2669         return ad_get_internal(ctx, handle, fsp, NULL, type);
2670 }
2671
2672 /**
2673  * Set AppleDouble metadata on a file or directory
2674  *
2675  * @param[in] ad      adouble handle
2676  * @param[in] fsp     file handle
2677  *
2678  * @return            status code, 0 means success
2679  **/
2680 int ad_fset(struct vfs_handle_struct *handle,
2681             struct adouble *ad,
2682             files_struct *fsp)
2683 {
2684         int rc = -1;
2685         ssize_t len;
2686         bool ok;
2687
2688         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
2689
2690         ok = ad_pack(handle, ad, fsp);
2691         if (!ok) {
2692                 return -1;
2693         }
2694
2695         switch (ad->ad_type) {
2696         case ADOUBLE_META:
2697                 rc = SMB_VFS_NEXT_FSETXATTR(handle,
2698                                    fsp->base_fsp ? fsp->base_fsp : fsp,
2699                                    AFPINFO_EA_NETATALK,
2700                                    ad->ad_data,
2701                                    AD_DATASZ_XATTR, 0);
2702                 break;
2703         case ADOUBLE_RSRC:
2704                 len = SMB_VFS_NEXT_PWRITE(handle,
2705                                           fsp,
2706                                           ad->ad_data,
2707                                           ad_getentryoff(ad, ADEID_RFORK),
2708                                           0);
2709                 if (len != ad_getentryoff(ad, ADEID_RFORK)) {
2710                         DBG_ERR("short write on %s: %zd\n", fsp_str_dbg(fsp), len);
2711                         return -1;
2712                 }
2713                 rc = 0;
2714                 break;
2715
2716         default:
2717                 return -1;
2718         }
2719
2720         DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
2721
2722         return rc;
2723 }
2724
2725 bool is_adouble_file(const char *path)
2726 {
2727         const char *p = NULL;
2728         int match;
2729
2730         p = strrchr(path, '/');
2731         if (p == NULL) {
2732                 p = path;
2733         } else {
2734                 p++;
2735         }
2736
2737         match = strncmp(p,
2738                         ADOUBLE_NAME_PREFIX,
2739                         strlen(ADOUBLE_NAME_PREFIX));
2740         if (match != 0) {
2741                 return false;
2742         }
2743         return true;
2744 }
2745
2746 /**
2747  * Prepend "._" to a basename
2748  * Return a new struct smb_filename with stream_name == NULL.
2749  **/
2750 int adouble_path(TALLOC_CTX *ctx,
2751                  const struct smb_filename *smb_fname_in,
2752                  struct smb_filename **pp_smb_fname_out)
2753 {
2754         char *parent;
2755         const char *base;
2756         struct smb_filename *smb_fname = NULL;
2757
2758         smb_fname = cp_smb_filename_nostream(ctx, smb_fname_in);
2759         if (smb_fname == NULL) {
2760                 return -1;
2761         }
2762
2763         /* We're replacing base_name. */
2764         TALLOC_FREE(smb_fname->base_name);
2765
2766         SET_STAT_INVALID(smb_fname->st);
2767
2768         if (!parent_dirname(smb_fname, smb_fname_in->base_name,
2769                                 &parent, &base)) {
2770                 TALLOC_FREE(smb_fname);
2771                 return -1;
2772         }
2773
2774         if (ISDOT(parent)) {
2775                 smb_fname->base_name = talloc_asprintf(smb_fname,
2776                                         "._%s", base);
2777         } else {
2778                 smb_fname->base_name = talloc_asprintf(smb_fname,
2779                                         "%s/._%s", parent, base);
2780         }
2781         if (smb_fname->base_name == NULL) {
2782                 TALLOC_FREE(smb_fname);
2783                 return -1;
2784         }
2785
2786         *pp_smb_fname_out = smb_fname;
2787
2788         return 0;
2789 }
2790
2791 /**
2792  * Allocate and initialize an AfpInfo struct
2793  **/
2794 AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
2795 {
2796         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
2797         if (ai == NULL) {
2798                 return NULL;
2799         }
2800         ai->afpi_Signature = AFP_Signature;
2801         ai->afpi_Version = AFP_Version;
2802         ai->afpi_BackupTime = AD_DATE_START;
2803         return ai;
2804 }
2805
2806 /**
2807  * Pack an AfpInfo struct into a buffer
2808  *
2809  * Buffer size must be at least AFP_INFO_SIZE
2810  * Returns size of packed buffer
2811  **/
2812 ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
2813 {
2814         memset(buf, 0, AFP_INFO_SIZE);
2815
2816         RSIVAL(buf, 0, ai->afpi_Signature);
2817         RSIVAL(buf, 4, ai->afpi_Version);
2818         RSIVAL(buf, 12, ai->afpi_BackupTime);
2819         memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
2820
2821         return AFP_INFO_SIZE;
2822 }
2823
2824 /**
2825  * Unpack a buffer into a AfpInfo structure
2826  *
2827  * Buffer size must be at least AFP_INFO_SIZE
2828  * Returns allocated AfpInfo struct
2829  **/
2830 AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data, bool validate)
2831 {
2832         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
2833         if (ai == NULL) {
2834                 return NULL;
2835         }
2836
2837         ai->afpi_Signature = RIVAL(data, 0);
2838         ai->afpi_Version = RIVAL(data, 4);
2839         ai->afpi_BackupTime = RIVAL(data, 12);
2840         memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
2841                sizeof(ai->afpi_FinderInfo));
2842
2843         if (validate) {
2844                 if (ai->afpi_Signature != AFP_Signature
2845                     || ai->afpi_Version != AFP_Version)
2846                 {
2847                         DEBUG(1, ("Bad AfpInfo signature or version\n"));
2848                         TALLOC_FREE(ai);
2849                 }
2850         } else {
2851                 ai->afpi_Signature = AFP_Signature;
2852                 ai->afpi_Version = AFP_Version;
2853         }
2854
2855         return ai;
2856 }