s3:modules: pass a TALLOC_CTX to string_replace_init_map()
[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
28 /*
29    "._" AppleDouble Header File Layout:
30
31          MAGIC          0x00051607
32          VERSION        0x00020000
33          FILLER         0
34          COUNT          2
35      .-- AD ENTRY[0]    Finder Info Entry (must be first)
36   .--+-- AD ENTRY[1]    Resource Fork Entry (must be last)
37   |  |   /////////////
38   |  '-> FINDER INFO    Fixed Size Data (32 Bytes)
39   |      ~~~~~~~~~~~~~  2 Bytes Padding
40   |      EXT ATTR HDR   Fixed Size Data (36 Bytes)
41   |      /////////////
42   |      ATTR ENTRY[0] --.
43   |      ATTR ENTRY[1] --+--.
44   |      ATTR ENTRY[2] --+--+--.
45   |         ...          |  |  |
46   |      ATTR ENTRY[N] --+--+--+--.
47   |      ATTR DATA 0   <-'  |  |  |
48   |      ////////////       |  |  |
49   |      ATTR DATA 1   <----'  |  |
50   |      /////////////         |  |
51   |      ATTR DATA 2   <-------'  |
52   |      /////////////            |
53   |         ...                   |
54   |      ATTR DATA N   <----------'
55   |      /////////////
56   |         ...          Attribute Free Space
57   |
58   '----> RESOURCE FORK
59             ...          Variable Sized Data
60             ...
61 */
62
63 /* Number of actually used entries */
64 #define ADEID_NUM_XATTR      8
65 #define ADEID_NUM_DOT_UND    2
66 #define ADEID_NUM_RSRC_XATTR 1
67
68 /* Sizes of relevant entry bits */
69 #define ADEDLEN_MAGIC       4
70 #define ADEDLEN_VERSION     4
71 #define ADEDLEN_FILLER      16
72 #define AD_FILLER_TAG       "Netatalk        " /* should be 16 bytes */
73 #define AD_FILLER_TAG_OSX   "Mac OS X        " /* should be 16 bytes */
74 #define ADEDLEN_NENTRIES    2
75 #define AD_HEADER_LEN       (ADEDLEN_MAGIC + ADEDLEN_VERSION + \
76                              ADEDLEN_FILLER + ADEDLEN_NENTRIES) /* 26 */
77 #define AD_ENTRY_LEN_EID    4
78 #define AD_ENTRY_LEN_OFF    4
79 #define AD_ENTRY_LEN_LEN    4
80 #define AD_ENTRY_LEN (AD_ENTRY_LEN_EID + AD_ENTRY_LEN_OFF + AD_ENTRY_LEN_LEN)
81
82 /* Offsets */
83 #define ADEDOFF_MAGIC         0
84 #define ADEDOFF_VERSION       (ADEDOFF_MAGIC + ADEDLEN_MAGIC)
85 #define ADEDOFF_FILLER        (ADEDOFF_VERSION + ADEDLEN_VERSION)
86 #define ADEDOFF_NENTRIES      (ADEDOFF_FILLER + ADEDLEN_FILLER)
87
88 #define ADEDOFF_FINDERI_XATTR    (AD_HEADER_LEN + \
89                                   (ADEID_NUM_XATTR * AD_ENTRY_LEN))
90 #define ADEDOFF_COMMENT_XATTR    (ADEDOFF_FINDERI_XATTR    + ADEDLEN_FINDERI)
91 #define ADEDOFF_FILEDATESI_XATTR (ADEDOFF_COMMENT_XATTR    + ADEDLEN_COMMENT)
92 #define ADEDOFF_AFPFILEI_XATTR   (ADEDOFF_FILEDATESI_XATTR + \
93                                   ADEDLEN_FILEDATESI)
94 #define ADEDOFF_PRIVDEV_XATTR    (ADEDOFF_AFPFILEI_XATTR   + ADEDLEN_AFPFILEI)
95 #define ADEDOFF_PRIVINO_XATTR    (ADEDOFF_PRIVDEV_XATTR    + ADEDLEN_PRIVDEV)
96 #define ADEDOFF_PRIVSYN_XATTR    (ADEDOFF_PRIVINO_XATTR    + ADEDLEN_PRIVINO)
97 #define ADEDOFF_PRIVID_XATTR     (ADEDOFF_PRIVSYN_XATTR    + ADEDLEN_PRIVSYN)
98
99 #define ADEDOFF_FINDERI_DOT_UND  (AD_HEADER_LEN + \
100                                   (ADEID_NUM_DOT_UND * AD_ENTRY_LEN))
101 #define ADEDOFF_RFORK_DOT_UND    (ADEDOFF_FINDERI_DOT_UND + ADEDLEN_FINDERI)
102
103 #define AD_DATASZ_XATTR (AD_HEADER_LEN + \
104                          (ADEID_NUM_XATTR * AD_ENTRY_LEN) + \
105                          ADEDLEN_FINDERI + ADEDLEN_COMMENT + \
106                          ADEDLEN_FILEDATESI + ADEDLEN_AFPFILEI + \
107                          ADEDLEN_PRIVDEV + ADEDLEN_PRIVINO + \
108                          ADEDLEN_PRIVSYN + ADEDLEN_PRIVID)
109
110 #if AD_DATASZ_XATTR != 402
111 #error bad size for AD_DATASZ_XATTR
112 #endif
113
114 #define AD_DATASZ_DOT_UND (AD_HEADER_LEN + \
115                            (ADEID_NUM_DOT_UND * AD_ENTRY_LEN) + \
116                            ADEDLEN_FINDERI)
117 #if AD_DATASZ_DOT_UND != 82
118 #error bad size for AD_DATASZ_DOT_UND
119 #endif
120
121 #define AD_XATTR_HDR_MAGIC    0x41545452 /* 'ATTR' */
122 #define AD_XATTR_MAX_ENTRIES  1024 /* Some arbitrarily enforced limit */
123 #define AD_XATTR_HDR_SIZE     36
124 #define AD_XATTR_MAX_HDR_SIZE 65536
125
126 /*
127  * Both struct ad_xattr_header and struct ad_xattr_entry describe the in memory
128  * representation as well as the on-disk format.
129  *
130  * The ad_xattr_header follows the FinderInfo data in the FinderInfo entry if
131  * the length of the FinderInfo entry is larger then 32 bytes. It is then
132  * preceeded with 2 bytes padding.
133  *
134  * Cf: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/vfs/vfs_xattr.c
135  */
136
137 struct ad_xattr_header {
138         uint32_t adx_magic;        /* ATTR_HDR_MAGIC */
139         uint32_t adx_debug_tag;    /* for debugging == file id of owning file */
140         uint32_t adx_total_size;   /* file offset of end of attribute header + entries + data */
141         uint32_t adx_data_start;   /* file offset to attribute data area */
142         uint32_t adx_data_length;  /* length of attribute data area */
143         uint32_t adx_reserved[3];
144         uint16_t adx_flags;
145         uint16_t adx_num_attrs;
146 };
147
148 /* On-disk entries are aligned on 4 byte boundaries */
149 struct ad_xattr_entry {
150         uint32_t adx_offset;    /* file offset to data */
151         uint32_t adx_length;    /* size of attribute data */
152         uint16_t adx_flags;
153         uint8_t  adx_namelen;   /* included the NULL terminator */
154         char    *adx_name;      /* NULL-terminated UTF-8 name */
155 };
156
157 struct ad_entry {
158         size_t ade_off;
159         size_t ade_len;
160 };
161
162 struct adouble {
163         files_struct             *ad_fsp;
164         bool                      ad_opened;
165         adouble_type_t            ad_type;
166         uint32_t                  ad_magic;
167         uint32_t                  ad_version;
168         uint8_t                   ad_filler[ADEDLEN_FILLER];
169         struct ad_entry           ad_eid[ADEID_MAX];
170         char                     *ad_data;
171         struct ad_xattr_header    adx_header;
172         struct ad_xattr_entry    *adx_entries;
173 };
174
175 struct ad_entry_order {
176         uint32_t id, offset, len;
177 };
178
179 /* Netatalk AppleDouble metadata xattr */
180 static const
181 struct ad_entry_order entry_order_meta_xattr[ADEID_NUM_XATTR + 1] = {
182         {ADEID_FINDERI,    ADEDOFF_FINDERI_XATTR,    ADEDLEN_FINDERI},
183         {ADEID_COMMENT,    ADEDOFF_COMMENT_XATTR,    0},
184         {ADEID_FILEDATESI, ADEDOFF_FILEDATESI_XATTR, ADEDLEN_FILEDATESI},
185         {ADEID_AFPFILEI,   ADEDOFF_AFPFILEI_XATTR,   ADEDLEN_AFPFILEI},
186         {ADEID_PRIVDEV,    ADEDOFF_PRIVDEV_XATTR,    0},
187         {ADEID_PRIVINO,    ADEDOFF_PRIVINO_XATTR,    0},
188         {ADEID_PRIVSYN,    ADEDOFF_PRIVSYN_XATTR,    0},
189         {ADEID_PRIVID,     ADEDOFF_PRIVID_XATTR,     0},
190         {0, 0, 0}
191 };
192
193 /* AppleDouble resource fork file (the ones prefixed by "._") */
194 static const
195 struct ad_entry_order entry_order_dot_und[ADEID_NUM_DOT_UND + 1] = {
196         {ADEID_FINDERI,    ADEDOFF_FINDERI_DOT_UND,  ADEDLEN_FINDERI},
197         {ADEID_RFORK,      ADEDOFF_RFORK_DOT_UND,    0},
198         {0, 0, 0}
199 };
200
201 /* Conversion from enumerated id to on-disk AppleDouble id */
202 #define AD_EID_DISK(a) (set_eid[a])
203 static const uint32_t set_eid[] = {
204         0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
205         AD_DEV, AD_INO, AD_SYN, AD_ID
206 };
207
208 static char empty_resourcefork[] = {
209         0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
210         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
211         0x54, 0x68, 0x69, 0x73, 0x20, 0x72, 0x65, 0x73,
212         0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x66, 0x6F,
213         0x72, 0x6B, 0x20, 0x69, 0x6E, 0x74, 0x65, 0x6E,
214         0x74, 0x69, 0x6F, 0x6E, 0x61, 0x6C, 0x6C, 0x79,
215         0x20, 0x6C, 0x65, 0x66, 0x74, 0x20, 0x62, 0x6C,
216         0x61, 0x6E, 0x6B, 0x20, 0x20, 0x20, 0x00, 0x00,
217         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
242         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E,
243         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
244         0x00, 0x1C, 0x00, 0x1E, 0xFF, 0xFF
245 };
246
247 size_t ad_getentrylen(const struct adouble *ad, int eid)
248 {
249         return ad->ad_eid[eid].ade_len;
250 }
251
252 size_t ad_getentryoff(const struct adouble *ad, int eid)
253 {
254         return ad->ad_eid[eid].ade_off;
255 }
256
257 size_t ad_setentrylen(struct adouble *ad, int eid, size_t len)
258 {
259         return ad->ad_eid[eid].ade_len = len;
260 }
261
262 size_t ad_setentryoff(struct adouble *ad, int eid, size_t off)
263 {
264         return ad->ad_eid[eid].ade_off = off;
265 }
266
267 /**
268  * Return a pointer to an AppleDouble entry
269  *
270  * Returns NULL if the entry is not present
271  **/
272 char *ad_get_entry(const struct adouble *ad, int eid)
273 {
274         off_t off = ad_getentryoff(ad, eid);
275         size_t len = ad_getentrylen(ad, eid);
276
277         if (off == 0 || len == 0) {
278                 return NULL;
279         }
280
281         return ad->ad_data + off;
282 }
283
284 /**
285  * Get a date
286  **/
287 int ad_getdate(const struct adouble *ad, unsigned int dateoff, uint32_t *date)
288 {
289         bool xlate = (dateoff & AD_DATE_UNIX);
290         char *p = NULL;
291
292         dateoff &= AD_DATE_MASK;
293         p = ad_get_entry(ad, ADEID_FILEDATESI);
294         if (p == NULL) {
295                 return -1;
296         }
297
298         if (dateoff > AD_DATE_ACCESS) {
299             return -1;
300         }
301
302         memcpy(date, p + dateoff, sizeof(uint32_t));
303
304         if (xlate) {
305                 *date = AD_DATE_TO_UNIX(*date);
306         }
307         return 0;
308 }
309
310 /**
311  * Set a date
312  **/
313 int ad_setdate(struct adouble *ad, unsigned int dateoff, uint32_t date)
314 {
315         bool xlate = (dateoff & AD_DATE_UNIX);
316         char *p = NULL;
317
318         p = ad_get_entry(ad, ADEID_FILEDATESI);
319         if (p == NULL) {
320                 return -1;
321         }
322
323         dateoff &= AD_DATE_MASK;
324         if (xlate) {
325                 date = AD_DATE_FROM_UNIX(date);
326         }
327
328         if (dateoff > AD_DATE_ACCESS) {
329                 return -1;
330         }
331
332         memcpy(p + dateoff, &date, sizeof(date));
333
334         return 0;
335 }
336
337
338 /**
339  * Map on-disk AppleDouble id to enumerated id
340  **/
341 static uint32_t get_eid(uint32_t eid)
342 {
343         if (eid <= 15) {
344                 return eid;
345         }
346
347         switch (eid) {
348         case AD_DEV:
349                 return ADEID_PRIVDEV;
350         case AD_INO:
351                 return ADEID_PRIVINO;
352         case AD_SYN:
353                 return ADEID_PRIVSYN;
354         case AD_ID:
355                 return ADEID_PRIVID;
356         default:
357                 break;
358         }
359
360         return 0;
361 }
362
363 /**
364  * Pack AppleDouble structure into data buffer
365  **/
366 static bool ad_pack(struct vfs_handle_struct *handle,
367                     struct adouble *ad,
368                     files_struct *fsp)
369 {
370         uint32_t       eid;
371         uint16_t       nent;
372         uint32_t       bufsize;
373         uint32_t       offset = 0;
374
375         bufsize = talloc_get_size(ad->ad_data);
376         if (bufsize < AD_DATASZ_DOT_UND) {
377                 DBG_ERR("bad buffer size [0x%" PRIx32 "]\n", bufsize);
378                 return false;
379         }
380
381         if (offset + ADEDLEN_MAGIC < offset ||
382                         offset + ADEDLEN_MAGIC >= bufsize) {
383                 return false;
384         }
385         RSIVAL(ad->ad_data, offset, ad->ad_magic);
386         offset += ADEDLEN_MAGIC;
387
388         if (offset + ADEDLEN_VERSION < offset ||
389                         offset + ADEDLEN_VERSION >= bufsize) {
390                 return false;
391         }
392         RSIVAL(ad->ad_data, offset, ad->ad_version);
393         offset += ADEDLEN_VERSION;
394
395         if (offset + ADEDLEN_FILLER < offset ||
396                         offset + ADEDLEN_FILLER >= bufsize) {
397                 return false;
398         }
399         if (ad->ad_type == ADOUBLE_RSRC) {
400                 memcpy(ad->ad_data + offset, AD_FILLER_TAG, ADEDLEN_FILLER);
401         }
402         offset += ADEDLEN_FILLER;
403
404         if (offset + ADEDLEN_NENTRIES < offset ||
405                         offset + ADEDLEN_NENTRIES >= bufsize) {
406                 return false;
407         }
408         offset += ADEDLEN_NENTRIES;
409
410         for (eid = 0, nent = 0; eid < ADEID_MAX; eid++) {
411                 if (ad->ad_eid[eid].ade_off == 0) {
412                         /*
413                          * ade_off is also used as indicator whether a
414                          * specific entry is used or not
415                          */
416                         continue;
417                 }
418
419                 if (offset + AD_ENTRY_LEN_EID < offset ||
420                                 offset + AD_ENTRY_LEN_EID >= bufsize) {
421                         return false;
422                 }
423                 RSIVAL(ad->ad_data, offset, AD_EID_DISK(eid));
424                 offset += AD_ENTRY_LEN_EID;
425
426                 if (offset + AD_ENTRY_LEN_OFF < offset ||
427                                 offset + AD_ENTRY_LEN_OFF >= bufsize) {
428                         return false;
429                 }
430                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_off);
431                 offset += AD_ENTRY_LEN_OFF;
432
433                 if (offset + AD_ENTRY_LEN_LEN < offset ||
434                                 offset + AD_ENTRY_LEN_LEN >= bufsize) {
435                         return false;
436                 }
437                 RSIVAL(ad->ad_data, offset, ad->ad_eid[eid].ade_len);
438                 offset += AD_ENTRY_LEN_LEN;
439
440                 nent++;
441         }
442
443         if (ADEDOFF_NENTRIES + 2 >= bufsize) {
444                 return false;
445         }
446         RSSVAL(ad->ad_data, ADEDOFF_NENTRIES, nent);
447
448         return true;
449 }
450
451 static bool ad_unpack_xattrs(struct adouble *ad)
452 {
453         struct ad_xattr_header *h = &ad->adx_header;
454         const char *p = ad->ad_data;
455         uint32_t hoff;
456         uint32_t i;
457
458         if (ad_getentrylen(ad, ADEID_FINDERI) <= ADEDLEN_FINDERI) {
459                 return true;
460         }
461
462         /* 2 bytes padding */
463         hoff = ad_getentryoff(ad, ADEID_FINDERI) + ADEDLEN_FINDERI + 2;
464
465         h->adx_magic       = RIVAL(p, hoff + 0);
466         h->adx_debug_tag   = RIVAL(p, hoff + 4); /* Not used -> not checked */
467         h->adx_total_size  = RIVAL(p, hoff + 8);
468         h->adx_data_start  = RIVAL(p, hoff + 12);
469         h->adx_data_length = RIVAL(p, hoff + 16);
470         h->adx_flags       = RSVAL(p, hoff + 32); /* Not used -> not checked */
471         h->adx_num_attrs   = RSVAL(p, hoff + 34);
472
473         if (h->adx_magic != AD_XATTR_HDR_MAGIC) {
474                 DBG_ERR("Bad magic: 0x%" PRIx32 "\n", h->adx_magic);
475                 return false;
476         }
477
478         if (h->adx_total_size > ad_getentryoff(ad, ADEID_RFORK)) {
479                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
480                 return false;
481         }
482         if (h->adx_total_size > AD_XATTR_MAX_HDR_SIZE) {
483                 DBG_ERR("Bad total size: 0x%" PRIx32 "\n", h->adx_total_size);
484                 return false;
485         }
486
487         if (h->adx_data_start < (hoff + AD_XATTR_HDR_SIZE)) {
488                 DBG_ERR("Bad start: 0x%" PRIx32 "\n", h->adx_data_start);
489                 return false;
490         }
491
492         if ((h->adx_data_start + h->adx_data_length) < h->adx_data_start) {
493                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
494                 return false;
495         }
496         if ((h->adx_data_start + h->adx_data_length) >
497             ad->adx_header.adx_total_size)
498         {
499                 DBG_ERR("Bad length: %" PRIu32 "\n", h->adx_data_length);
500                 return false;
501         }
502
503         if (h->adx_num_attrs > AD_XATTR_MAX_ENTRIES) {
504                 DBG_ERR("Bad num xattrs: %" PRIu16 "\n", h->adx_num_attrs);
505                 return false;
506         }
507
508         if (h->adx_num_attrs == 0) {
509                 return true;
510         }
511
512         ad->adx_entries = talloc_zero_array(
513                 ad, struct ad_xattr_entry, h->adx_num_attrs);
514         if (ad->adx_entries == NULL) {
515                 return false;
516         }
517
518         hoff += AD_XATTR_HDR_SIZE;
519
520         for (i = 0; i < h->adx_num_attrs; i++) {
521                 struct ad_xattr_entry *e = &ad->adx_entries[i];
522
523                 hoff = (hoff + 3) & ~3;
524
525                 e->adx_offset  = RIVAL(p, hoff + 0);
526                 e->adx_length  = RIVAL(p, hoff + 4);
527                 e->adx_flags   = RSVAL(p, hoff + 8);
528                 e->adx_namelen = *(p + hoff + 10);
529
530                 if (e->adx_offset >= ad->adx_header.adx_total_size) {
531                         DBG_ERR("Bad adx_offset: %" PRIx32 "\n",
532                                 e->adx_offset);
533                         return false;
534                 }
535
536                 if ((e->adx_offset + e->adx_length) < e->adx_offset) {
537                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
538                                 e->adx_length);
539                         return false;
540                 }
541
542                 if ((e->adx_offset + e->adx_length) >
543                     ad->adx_header.adx_total_size)
544                 {
545                         DBG_ERR("Bad adx_length: %" PRIx32 "\n",
546                                 e->adx_length);
547                         return false;
548                 }
549
550                 if (e->adx_namelen == 0) {
551                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
552                                 e->adx_namelen);
553                         return false;
554                 }
555                 if ((hoff + 11 + e->adx_namelen) < hoff + 11) {
556                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
557                                 e->adx_namelen);
558                         return false;
559                 }
560                 if ((hoff + 11 + e->adx_namelen) >
561                     ad->adx_header.adx_data_start)
562                 {
563                         DBG_ERR("Bad adx_namelen: %" PRIx32 "\n",
564                                 e->adx_namelen);
565                         return false;
566                 }
567
568                 e->adx_name = talloc_strndup(ad->adx_entries,
569                                              p + hoff + 11,
570                                              e->adx_namelen);
571                 if (e->adx_name == NULL) {
572                         return false;
573                 }
574
575                 DBG_DEBUG("xattr [%s] offset [0x%x] size [0x%x]\n",
576                           e->adx_name, e->adx_offset, e->adx_length);
577                 dump_data(10, (uint8_t *)(ad->ad_data + e->adx_offset),
578                           e->adx_length);
579
580                 hoff += 11 + e->adx_namelen;
581         }
582
583         return true;
584 }
585
586 /**
587  * Unpack an AppleDouble blob into a struct adoble
588  **/
589 static bool ad_unpack(struct adouble *ad, const size_t nentries,
590                       size_t filesize)
591 {
592         size_t bufsize = talloc_get_size(ad->ad_data);
593         size_t adentries, i;
594         uint32_t eid, len, off;
595         bool ok;
596
597         /*
598          * The size of the buffer ad->ad_data is checked when read, so
599          * we wouldn't have to check our own offsets, a few extra
600          * checks won't hurt though. We have to check the offsets we
601          * read from the buffer anyway.
602          */
603
604         if (bufsize < (AD_HEADER_LEN + (AD_ENTRY_LEN * nentries))) {
605                 DEBUG(1, ("bad size\n"));
606                 return false;
607         }
608
609         ad->ad_magic = RIVAL(ad->ad_data, 0);
610         ad->ad_version = RIVAL(ad->ad_data, ADEDOFF_VERSION);
611         if ((ad->ad_magic != AD_MAGIC) || (ad->ad_version != AD_VERSION)) {
612                 DEBUG(1, ("wrong magic or version\n"));
613                 return false;
614         }
615
616         memcpy(ad->ad_filler, ad->ad_data + ADEDOFF_FILLER, ADEDLEN_FILLER);
617
618         adentries = RSVAL(ad->ad_data, ADEDOFF_NENTRIES);
619         if (adentries != nentries) {
620                 DEBUG(1, ("invalid number of entries: %zu\n",
621                           adentries));
622                 return false;
623         }
624
625         /* now, read in the entry bits */
626         for (i = 0; i < adentries; i++) {
627                 eid = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN));
628                 eid = get_eid(eid);
629                 off = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 4);
630                 len = RIVAL(ad->ad_data, AD_HEADER_LEN + (i * AD_ENTRY_LEN) + 8);
631
632                 if (!eid || eid >= ADEID_MAX) {
633                         DEBUG(1, ("bogus eid %d\n", eid));
634                         return false;
635                 }
636
637                 /*
638                  * All entries other than the resource fork are
639                  * expected to be read into the ad_data buffer, so
640                  * ensure the specified offset is within that bound
641                  */
642                 if ((off > bufsize) && (eid != ADEID_RFORK)) {
643                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
644                                   eid, off, len));
645                         return false;
646                 }
647
648                 /*
649                  * All entries besides FinderInfo and resource fork
650                  * must fit into the buffer. FinderInfo is special as
651                  * it may be larger then the default 32 bytes (if it
652                  * contains marshalled xattrs), but we will fixup that
653                  * in ad_convert(). And the resource fork is never
654                  * accessed directly by the ad_data buf (also see
655                  * comment above) anyway.
656                  */
657                 if ((eid != ADEID_RFORK) &&
658                     (eid != ADEID_FINDERI) &&
659                     ((off + len) > bufsize)) {
660                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
661                                   eid, off, len));
662                         return false;
663                 }
664
665                 /*
666                  * That would be obviously broken
667                  */
668                 if (off > filesize) {
669                         DEBUG(1, ("bogus eid %d: off: %" PRIu32 ", len: %" PRIu32 "\n",
670                                   eid, off, len));
671                         return false;
672                 }
673
674                 /*
675                  * Check for any entry that has its end beyond the
676                  * filesize.
677                  */
678                 if (off + len < off) {
679                         DEBUG(1, ("offset wrap in eid %d: off: %" PRIu32
680                                   ", len: %" PRIu32 "\n",
681                                   eid, off, len));
682                         return false;
683
684                 }
685                 if (off + len > filesize) {
686                         /*
687                          * If this is the resource fork entry, we fix
688                          * up the length, for any other entry we bail
689                          * out.
690                          */
691                         if (eid != ADEID_RFORK) {
692                                 DEBUG(1, ("bogus eid %d: off: %" PRIu32
693                                           ", len: %" PRIu32 "\n",
694                                           eid, off, len));
695                                 return false;
696                         }
697
698                         /*
699                          * Fixup the resource fork entry by limiting
700                          * the size to entryoffset - filesize.
701                          */
702                         len = filesize - off;
703                         DEBUG(1, ("Limiting ADEID_RFORK: off: %" PRIu32
704                                   ", len: %" PRIu32 "\n", off, len));
705                 }
706
707                 ad->ad_eid[eid].ade_off = off;
708                 ad->ad_eid[eid].ade_len = len;
709         }
710
711         ok = ad_unpack_xattrs(ad);
712         if (!ok) {
713                 return false;
714         }
715
716         return true;
717 }
718
719 static bool ad_convert_move_reso(vfs_handle_struct *handle,
720                                  struct adouble *ad,
721                                  const struct smb_filename *smb_fname)
722 {
723         char *buf = NULL;
724         size_t rforklen;
725         size_t rforkoff;
726         ssize_t n;
727         int ret;
728
729         rforklen = ad_getentrylen(ad, ADEID_RFORK);
730         if (rforklen == 0) {
731                 return true;
732         }
733
734         buf = talloc_size(ad, rforklen);
735         if (buf == NULL) {
736                 /*
737                  * This allocates a buffer for reading the resource fork data in
738                  * one big swoop. Resource forks won't be larger then, say, 64
739                  * MB, I swear, so just doing the allocation with the talloc
740                  * limit as safeguard seems safe.
741                  */
742                 DBG_ERR("Failed to allocate %zu bytes for rfork\n",
743                         rforklen);
744                 return false;
745         }
746
747         rforkoff = ad_getentryoff(ad, ADEID_RFORK);
748
749         n = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, rforkoff);
750         if (n != rforklen) {
751                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
752                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
753                 return false;
754         }
755
756         rforkoff = ADEDOFF_RFORK_DOT_UND;
757
758         n = SMB_VFS_PWRITE(ad->ad_fsp, buf, rforklen, rforkoff);
759         if (n != rforklen) {
760                 DBG_ERR("Writing %zu bytes to rfork [%s] failed: %s\n",
761                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
762                 return false;
763         }
764
765         ad_setentryoff(ad, ADEID_RFORK, ADEDOFF_RFORK_DOT_UND);
766
767         ret = ad_fset(handle, ad, ad->ad_fsp);
768         if (ret != 0) {
769                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
770                 return false;
771         }
772
773         return true;
774 }
775
776 static bool ad_convert_xattr(vfs_handle_struct *handle,
777                              struct adouble *ad,
778                              const struct smb_filename *smb_fname,
779                              const char *catia_mappings,
780                              bool *converted_xattr)
781 {
782         static struct char_mappings **string_replace_cmaps = NULL;
783         uint16_t i;
784         int saved_errno = 0;
785         NTSTATUS status;
786         int rc;
787         bool ok;
788
789         *converted_xattr = false;
790
791         if (ad_getentrylen(ad, ADEID_FINDERI) == ADEDLEN_FINDERI) {
792                 return true;
793         }
794
795         if (string_replace_cmaps == NULL) {
796                 const char **mappings = NULL;
797
798                 mappings = str_list_make_v3_const(
799                         talloc_tos(), catia_mappings, NULL);
800                 if (mappings == NULL) {
801                         return false;
802                 }
803                 string_replace_cmaps = string_replace_init_map(
804                         handle->conn->sconn, mappings);
805                 TALLOC_FREE(mappings);
806         }
807
808         for (i = 0; i < ad->adx_header.adx_num_attrs; i++) {
809                 struct ad_xattr_entry *e = &ad->adx_entries[i];
810                 char *mapped_name = NULL;
811                 char *tmp = NULL;
812                 struct smb_filename *stream_name = NULL;
813                 files_struct *fsp = NULL;
814                 ssize_t nwritten;
815
816                 status = string_replace_allocate(handle->conn,
817                                                  e->adx_name,
818                                                  string_replace_cmaps,
819                                                  talloc_tos(),
820                                                  &mapped_name,
821                                                  vfs_translate_to_windows);
822                 if (!NT_STATUS_IS_OK(status) &&
823                     !NT_STATUS_EQUAL(status, NT_STATUS_NONE_MAPPED))
824                 {
825                         DBG_ERR("string_replace_allocate failed\n");
826                         ok = false;
827                         goto fail;
828                 }
829
830                 tmp = mapped_name;
831                 mapped_name = talloc_asprintf(talloc_tos(), ":%s", tmp);
832                 TALLOC_FREE(tmp);
833                 if (mapped_name == NULL) {
834                         ok = false;
835                         goto fail;
836                 }
837
838                 stream_name = synthetic_smb_fname(talloc_tos(),
839                                                   smb_fname->base_name,
840                                                   mapped_name,
841                                                   NULL,
842                                                   smb_fname->flags);
843                 TALLOC_FREE(mapped_name);
844                 if (stream_name == NULL) {
845                         DBG_ERR("synthetic_smb_fname failed\n");
846                         ok = false;
847                         goto fail;
848                 }
849
850                 DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
851
852                 status = SMB_VFS_CREATE_FILE(
853                         handle->conn,                   /* conn */
854                         NULL,                           /* req */
855                         0,                              /* root_dir_fid */
856                         stream_name,                    /* fname */
857                         FILE_GENERIC_WRITE,             /* access_mask */
858                         FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
859                         FILE_OPEN_IF,                   /* create_disposition */
860                         0,                              /* create_options */
861                         0,                              /* file_attributes */
862                         INTERNAL_OPEN_ONLY,             /* oplock_request */
863                         NULL,                           /* lease */
864                         0,                              /* allocation_size */
865                         0,                              /* private_flags */
866                         NULL,                           /* sd */
867                         NULL,                           /* ea_list */
868                         &fsp,                           /* result */
869                         NULL,                           /* psbuf */
870                         NULL, NULL);                    /* create context */
871                 TALLOC_FREE(stream_name);
872                 if (!NT_STATUS_IS_OK(status)) {
873                         DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
874                         ok = false;
875                         goto fail;
876                 }
877
878                 nwritten = SMB_VFS_PWRITE(fsp,
879                                           ad->ad_data + e->adx_offset,
880                                           e->adx_length,
881                                           0);
882                 if (nwritten == -1) {
883                         DBG_ERR("SMB_VFS_PWRITE failed\n");
884                         saved_errno = errno;
885                         close_file(NULL, fsp, ERROR_CLOSE);
886                         errno = saved_errno;
887                         ok = false;
888                         goto fail;
889                 }
890
891                 status = close_file(NULL, fsp, NORMAL_CLOSE);
892                 if (!NT_STATUS_IS_OK(status)) {
893                         ok = false;
894                         goto fail;
895                 }
896                 fsp = NULL;
897         }
898
899         ad->adx_header.adx_num_attrs = 0;
900         TALLOC_FREE(ad->adx_entries);
901
902         ad_setentrylen(ad, ADEID_FINDERI, ADEDLEN_FINDERI);
903
904         rc = ad_fset(handle, ad, ad->ad_fsp);
905         if (rc != 0) {
906                 DBG_ERR("ad_fset on [%s] failed: %s\n",
907                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
908                 ok = false;
909                 goto fail;
910         }
911
912         ok = ad_convert_move_reso(handle, ad, smb_fname);
913         if (!ok) {
914                 goto fail;
915         }
916
917         *converted_xattr = true;
918         ok = true;
919
920 fail:
921         return ok;
922 }
923
924 static bool ad_convert_finderinfo(vfs_handle_struct *handle,
925                                   struct adouble *ad,
926                                   const struct smb_filename *smb_fname)
927 {
928         char *p_ad = NULL;
929         AfpInfo *ai = NULL;
930         DATA_BLOB aiblob;
931         struct smb_filename *stream_name = NULL;
932         files_struct *fsp = NULL;
933         size_t size;
934         ssize_t nwritten;
935         NTSTATUS status;
936         int saved_errno = 0;
937         int cmp;
938
939         cmp = memcmp(ad->ad_filler, AD_FILLER_TAG_OSX, ADEDLEN_FILLER);
940         if (cmp != 0) {
941                 return true;
942         }
943
944         p_ad = ad_get_entry(ad, ADEID_FINDERI);
945         if (p_ad == NULL) {
946                 return false;
947         }
948
949         ai = afpinfo_new(talloc_tos());
950         if (ai == NULL) {
951                 return false;
952         }
953
954         memcpy(ai->afpi_FinderInfo, p_ad, ADEDLEN_FINDERI);
955
956         aiblob = data_blob_talloc(talloc_tos(), NULL, AFP_INFO_SIZE);
957         if (aiblob.data == NULL) {
958                 TALLOC_FREE(ai);
959                 return false;
960         }
961
962         size = afpinfo_pack(ai, (char *)aiblob.data);
963         TALLOC_FREE(ai);
964         if (size != AFP_INFO_SIZE) {
965                 return false;
966         }
967
968         stream_name = synthetic_smb_fname(talloc_tos(),
969                                           smb_fname->base_name,
970                                           AFPINFO_STREAM,
971                                           NULL,
972                                           smb_fname->flags);
973         if (stream_name == NULL) {
974                 data_blob_free(&aiblob);
975                 DBG_ERR("synthetic_smb_fname failed\n");
976                 return false;
977         }
978
979         DBG_DEBUG("stream_name: %s\n", smb_fname_str_dbg(stream_name));
980
981         status = SMB_VFS_CREATE_FILE(
982                 handle->conn,                   /* conn */
983                 NULL,                           /* req */
984                 0,                              /* root_dir_fid */
985                 stream_name,                    /* fname */
986                 FILE_GENERIC_WRITE,             /* access_mask */
987                 FILE_SHARE_READ | FILE_SHARE_WRITE, /* share_access */
988                 FILE_OPEN_IF,                   /* create_disposition */
989                 0,                              /* create_options */
990                 0,                              /* file_attributes */
991                 INTERNAL_OPEN_ONLY,             /* oplock_request */
992                 NULL,                           /* lease */
993                 0,                              /* allocation_size */
994                 0,                              /* private_flags */
995                 NULL,                           /* sd */
996                 NULL,                           /* ea_list */
997                 &fsp,                           /* result */
998                 NULL,                           /* psbuf */
999                 NULL, NULL);                    /* create context */
1000         TALLOC_FREE(stream_name);
1001         if (!NT_STATUS_IS_OK(status)) {
1002                 DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
1003                 return false;
1004         }
1005
1006         nwritten = SMB_VFS_PWRITE(fsp,
1007                                   aiblob.data,
1008                                   aiblob.length,
1009                                   0);
1010         if (nwritten == -1) {
1011                 DBG_ERR("SMB_VFS_PWRITE failed\n");
1012                 saved_errno = errno;
1013                 close_file(NULL, fsp, ERROR_CLOSE);
1014                 errno = saved_errno;
1015                 return false;
1016         }
1017
1018         status = close_file(NULL, fsp, NORMAL_CLOSE);
1019         if (!NT_STATUS_IS_OK(status)) {
1020                 return false;
1021         }
1022         fsp = NULL;
1023
1024         return true;
1025 }
1026
1027 static bool ad_convert_truncate(vfs_handle_struct *handle,
1028                                 struct adouble *ad,
1029                                 const struct smb_filename *smb_fname)
1030 {
1031         int rc;
1032         off_t newlen;
1033
1034         newlen = ADEDOFF_RFORK_DOT_UND + ad_getentrylen(ad, ADEID_RFORK);
1035
1036         rc = SMB_VFS_FTRUNCATE(ad->ad_fsp, newlen);
1037         if (rc != 0) {
1038                 return false;
1039         }
1040
1041         return true;
1042 }
1043
1044 static bool ad_convert_blank_rfork(vfs_handle_struct *handle,
1045                                    struct adouble *ad,
1046                                    uint32_t flags,
1047                                    bool *blank)
1048 {
1049         size_t rforklen = sizeof(empty_resourcefork);
1050         char buf[rforklen];
1051         ssize_t nread;
1052         int cmp;
1053         int rc;
1054
1055         *blank = false;
1056
1057         if (!(flags & AD_CONV_WIPE_BLANK)) {
1058                 return true;
1059         }
1060
1061         if (ad_getentrylen(ad, ADEID_RFORK) != rforklen) {
1062                 return true;
1063         }
1064
1065         nread = SMB_VFS_PREAD(ad->ad_fsp, buf, rforklen, ADEDOFF_RFORK_DOT_UND);
1066         if (nread != rforklen) {
1067                 DBG_ERR("Reading %zu bytes from rfork [%s] failed: %s\n",
1068                         rforklen, fsp_str_dbg(ad->ad_fsp), strerror(errno));
1069                 return false;
1070         }
1071
1072         cmp = memcmp(buf, empty_resourcefork, rforklen);
1073         if (cmp != 0) {
1074                 return true;
1075         }
1076
1077         ad_setentrylen(ad, ADEID_RFORK, 0);
1078
1079         rc = ad_fset(handle, ad, ad->ad_fsp);
1080         if (rc != 0) {
1081                 DBG_ERR("ad_fset on [%s] failed\n", fsp_str_dbg(ad->ad_fsp));
1082                 return false;
1083         }
1084
1085         *blank = true;
1086         return true;
1087 }
1088
1089 static bool ad_convert_delete_adfile(vfs_handle_struct *handle,
1090                                      struct adouble *ad,
1091                                      const struct smb_filename *smb_fname,
1092                                      uint32_t flags)
1093 {
1094         struct smb_filename *ad_name = NULL;
1095         int rc;
1096
1097         if (ad_getentrylen(ad, ADEID_RFORK) > 0) {
1098                 return true;
1099         }
1100
1101         if (!(flags & AD_CONV_DELETE)) {
1102                 return true;
1103         }
1104
1105         rc = adouble_path(talloc_tos(), smb_fname, &ad_name);
1106         if (rc != 0) {
1107                 return false;
1108         }
1109
1110         rc = SMB_VFS_NEXT_UNLINK(handle, ad_name);
1111         if (rc != 0) {
1112                 DBG_ERR("Unlinking [%s] failed: %s\n",
1113                         smb_fname_str_dbg(ad_name), strerror(errno));
1114                 TALLOC_FREE(ad_name);
1115                 return false;
1116         }
1117
1118         DBG_WARNING("Unlinked [%s] after conversion\n", smb_fname_str_dbg(ad_name));
1119         TALLOC_FREE(ad_name);
1120
1121         return true;
1122 }
1123
1124 /**
1125  * Convert from Apple's ._ file to Netatalk
1126  *
1127  * Apple's AppleDouble may contain a FinderInfo entry longer then 32
1128  * bytes containing packed xattrs.
1129  *
1130  * @return -1 in case an error occurred, 0 if no conversion was done, 1
1131  * otherwise
1132  **/
1133 int ad_convert(struct vfs_handle_struct *handle,
1134                const struct smb_filename *smb_fname,
1135                const char *catia_mappings,
1136                uint32_t flags)
1137 {
1138         struct adouble *ad = NULL;
1139         bool ok;
1140         bool converted_xattr = false;
1141         bool blank;
1142         int ret;
1143
1144         ad = ad_get(talloc_tos(), handle, smb_fname, ADOUBLE_RSRC);
1145         if (ad == NULL) {
1146                 return 0;
1147         }
1148
1149         ok = ad_convert_xattr(handle,
1150                               ad,
1151                               smb_fname,
1152                               catia_mappings,
1153                               &converted_xattr);
1154         if (!ok) {
1155                 ret = -1;
1156                 goto done;
1157         }
1158
1159         ok = ad_convert_blank_rfork(handle, ad, flags, &blank);
1160         if (!ok) {
1161                 ret = -1;
1162                 goto done;
1163         }
1164
1165         if (converted_xattr || blank) {
1166                 ok = ad_convert_truncate(handle, ad, smb_fname);
1167                 if (!ok) {
1168                         ret = -1;
1169                         goto done;
1170                 }
1171         }
1172
1173         ok = ad_convert_finderinfo(handle, ad, smb_fname);
1174         if (!ok) {
1175                 DBG_ERR("Failed to convert [%s]\n",
1176                         smb_fname_str_dbg(smb_fname));
1177                 ret = -1;
1178                 goto done;
1179         }
1180
1181         ok = ad_convert_delete_adfile(handle, ad, smb_fname, flags);
1182         if (!ok) {
1183                 ret = -1;
1184                 goto done;
1185         }
1186
1187         ret = 0;
1188 done:
1189         TALLOC_FREE(ad);
1190         return ret;
1191 }
1192
1193 /**
1194  * Read and parse Netatalk AppleDouble metadata xattr
1195  **/
1196 static ssize_t ad_read_meta(vfs_handle_struct *handle,
1197                             struct adouble *ad,
1198                             const struct smb_filename *smb_fname)
1199 {
1200         int      rc = 0;
1201         ssize_t  ealen;
1202         bool     ok;
1203
1204         DEBUG(10, ("reading meta xattr for %s\n", smb_fname->base_name));
1205
1206         ealen = SMB_VFS_GETXATTR(handle->conn, smb_fname,
1207                                  AFPINFO_EA_NETATALK, ad->ad_data,
1208                                  AD_DATASZ_XATTR);
1209         if (ealen == -1) {
1210                 switch (errno) {
1211                 case ENOATTR:
1212                 case ENOENT:
1213                         if (errno == ENOATTR) {
1214                                 errno = ENOENT;
1215                         }
1216                         rc = -1;
1217                         goto exit;
1218                 default:
1219                         DEBUG(2, ("error reading meta xattr: %s\n",
1220                                   strerror(errno)));
1221                         rc = -1;
1222                         goto exit;
1223                 }
1224         }
1225         if (ealen != AD_DATASZ_XATTR) {
1226                 DEBUG(2, ("bad size %zd\n", ealen));
1227                 errno = EINVAL;
1228                 rc = -1;
1229                 goto exit;
1230         }
1231
1232         /* Now parse entries */
1233         ok = ad_unpack(ad, ADEID_NUM_XATTR, AD_DATASZ_XATTR);
1234         if (!ok) {
1235                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
1236                 errno = EINVAL;
1237                 rc = -1;
1238                 goto exit;
1239         }
1240
1241         if (!ad_getentryoff(ad, ADEID_FINDERI)
1242             || !ad_getentryoff(ad, ADEID_COMMENT)
1243             || !ad_getentryoff(ad, ADEID_FILEDATESI)
1244             || !ad_getentryoff(ad, ADEID_AFPFILEI)
1245             || !ad_getentryoff(ad, ADEID_PRIVDEV)
1246             || !ad_getentryoff(ad, ADEID_PRIVINO)
1247             || !ad_getentryoff(ad, ADEID_PRIVSYN)
1248             || !ad_getentryoff(ad, ADEID_PRIVID)) {
1249                 DEBUG(2, ("invalid AppleDouble metadata xattr\n"));
1250                 errno = EINVAL;
1251                 rc = -1;
1252                 goto exit;
1253         }
1254
1255 exit:
1256         DEBUG(10, ("reading meta xattr for %s, rc: %d\n",
1257                 smb_fname->base_name, rc));
1258
1259         if (rc != 0) {
1260                 ealen = -1;
1261                 if (errno == EINVAL) {
1262                         become_root();
1263                         (void)SMB_VFS_REMOVEXATTR(handle->conn,
1264                                                   smb_fname,
1265                                                   AFPINFO_EA_NETATALK);
1266                         unbecome_root();
1267                         errno = ENOENT;
1268                 }
1269         }
1270         return ealen;
1271 }
1272
1273 static int ad_open_rsrc(vfs_handle_struct *handle,
1274                         const struct smb_filename *smb_fname,
1275                         int flags,
1276                         mode_t mode,
1277                         files_struct **_fsp)
1278 {
1279         int ret;
1280         struct smb_filename *adp_smb_fname = NULL;
1281         files_struct *fsp = NULL;
1282         uint32_t access_mask;
1283         uint32_t share_access;
1284         uint32_t create_disposition;
1285         NTSTATUS status;
1286
1287         ret = adouble_path(talloc_tos(), smb_fname, &adp_smb_fname);
1288         if (ret != 0) {
1289                 return -1;
1290         }
1291
1292         ret = SMB_VFS_STAT(handle->conn, adp_smb_fname);
1293         if (ret != 0) {
1294                 TALLOC_FREE(adp_smb_fname);
1295                 return -1;
1296         }
1297
1298         access_mask = FILE_GENERIC_READ;
1299         share_access = FILE_SHARE_READ | FILE_SHARE_WRITE;
1300         create_disposition = FILE_OPEN;
1301
1302         if (flags & O_RDWR) {
1303                 access_mask |= FILE_GENERIC_WRITE;
1304                 share_access &= ~FILE_SHARE_WRITE;
1305         }
1306
1307         status = SMB_VFS_CREATE_FILE(
1308                 handle->conn,                   /* conn */
1309                 NULL,                           /* req */
1310                 0,                              /* root_dir_fid */
1311                 adp_smb_fname,
1312                 access_mask,
1313                 share_access,
1314                 create_disposition,
1315                 0,                              /* create_options */
1316                 0,                              /* file_attributes */
1317                 INTERNAL_OPEN_ONLY,             /* oplock_request */
1318                 NULL,                           /* lease */
1319                 0,                              /* allocation_size */
1320                 0,                              /* private_flags */
1321                 NULL,                           /* sd */
1322                 NULL,                           /* ea_list */
1323                 &fsp,
1324                 NULL,                           /* psbuf */
1325                 NULL, NULL);                    /* create context */
1326         TALLOC_FREE(adp_smb_fname);
1327         if (!NT_STATUS_IS_OK(status)) {
1328                 DBG_ERR("SMB_VFS_CREATE_FILE failed\n");
1329                 return -1;
1330         }
1331
1332         *_fsp = fsp;
1333         return 0;
1334 }
1335
1336 /*
1337  * Here's the deal: for ADOUBLE_META we can do without an fd as we can issue
1338  * path based xattr calls. For ADOUBLE_RSRC however we need a full-fledged fd
1339  * for file IO on the ._ file.
1340  */
1341 static int ad_open(vfs_handle_struct *handle,
1342                    struct adouble *ad,
1343                    files_struct *fsp,
1344                    const struct smb_filename *smb_fname,
1345                    int flags,
1346                    mode_t mode)
1347 {
1348         int ret;
1349
1350         DBG_DEBUG("Path [%s] type [%s]\n", smb_fname->base_name,
1351                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
1352
1353         if (ad->ad_type == ADOUBLE_META) {
1354                 return 0;
1355         }
1356
1357         if (fsp != NULL) {
1358                 ad->ad_fsp = fsp;
1359                 ad->ad_opened = false;
1360                 return 0;
1361         }
1362
1363         ret = ad_open_rsrc(handle, smb_fname, flags, mode, &ad->ad_fsp);
1364         if (ret != 0) {
1365                 return -1;
1366         }
1367         ad->ad_opened = true;
1368
1369         DBG_DEBUG("Path [%s] type [%s]\n",
1370                   smb_fname->base_name,
1371                   ad->ad_type == ADOUBLE_META ? "meta" : "rsrc");
1372
1373         return 0;
1374 }
1375
1376 static ssize_t ad_read_rsrc_adouble(vfs_handle_struct *handle,
1377                                     struct adouble *ad,
1378                                     const struct smb_filename *smb_fname)
1379 {
1380         char *p_ad = NULL;
1381         size_t size;
1382         ssize_t len;
1383         int ret;
1384         bool ok;
1385
1386         ret = SMB_VFS_NEXT_FSTAT(handle, ad->ad_fsp, &ad->ad_fsp->fsp_name->st);
1387         if (ret != 0) {
1388                 DBG_ERR("fstat [%s] failed: %s\n",
1389                         fsp_str_dbg(ad->ad_fsp), strerror(errno));
1390                 return -1;
1391         }
1392
1393         /*
1394          * AppleDouble file header content and size, two cases:
1395          *
1396          * - without xattrs it is exactly AD_DATASZ_DOT_UND (82) bytes large
1397          * - with embedded xattrs it can be larger, up to AD_XATTR_MAX_HDR_SIZE
1398          *
1399          * Read as much as we can up to AD_XATTR_MAX_HDR_SIZE.
1400          */
1401         size = ad->ad_fsp->fsp_name->st.st_ex_size;
1402         if (size > talloc_array_length(ad->ad_data)) {
1403                 if (size > AD_XATTR_MAX_HDR_SIZE) {
1404                         size = AD_XATTR_MAX_HDR_SIZE;
1405                 }
1406                 p_ad = talloc_realloc(ad, ad->ad_data, char, size);
1407                 if (p_ad == NULL) {
1408                         return -1;
1409                 }
1410                 ad->ad_data = p_ad;
1411         }
1412
1413         len = SMB_VFS_NEXT_PREAD(handle, ad->ad_fsp, ad->ad_data, talloc_array_length(ad->ad_data), 0);
1414         if (len != talloc_array_length(ad->ad_data)) {
1415                 DBG_NOTICE("%s %s: bad size: %zd\n",
1416                            smb_fname->base_name, strerror(errno), len);
1417                 return -1;
1418         }
1419
1420         /* Now parse entries */
1421         ok = ad_unpack(ad, ADEID_NUM_DOT_UND, size);
1422         if (!ok) {
1423                 DBG_ERR("invalid AppleDouble resource %s\n",
1424                         smb_fname->base_name);
1425                 errno = EINVAL;
1426                 return -1;
1427         }
1428
1429         if ((ad_getentryoff(ad, ADEID_FINDERI) != ADEDOFF_FINDERI_DOT_UND)
1430             || (ad_getentrylen(ad, ADEID_FINDERI) < ADEDLEN_FINDERI)
1431             || (ad_getentryoff(ad, ADEID_RFORK) < ADEDOFF_RFORK_DOT_UND)) {
1432                 DBG_ERR("invalid AppleDouble resource %s\n",
1433                         smb_fname->base_name);
1434                 errno = EINVAL;
1435                 return -1;
1436         }
1437
1438         return len;
1439 }
1440
1441 /**
1442  * Read and parse resource fork, either ._ AppleDouble file or xattr
1443  **/
1444 static ssize_t ad_read_rsrc(vfs_handle_struct *handle,
1445                             struct adouble *ad,
1446                             const struct smb_filename *smb_fname)
1447 {
1448         return ad_read_rsrc_adouble(handle, ad, smb_fname);
1449 }
1450
1451 /**
1452  * Read and unpack an AppleDouble metadata xattr or resource
1453  **/
1454 static ssize_t ad_read(vfs_handle_struct *handle,
1455                        struct adouble *ad,
1456                        const struct smb_filename *smb_fname)
1457 {
1458         switch (ad->ad_type) {
1459         case ADOUBLE_META:
1460                 return ad_read_meta(handle, ad, smb_fname);
1461         case ADOUBLE_RSRC:
1462                 return ad_read_rsrc(handle, ad, smb_fname);
1463         default:
1464                 return -1;
1465         }
1466 }
1467
1468 static int adouble_destructor(struct adouble *ad)
1469 {
1470         NTSTATUS status;
1471
1472         if (!ad->ad_opened) {
1473                 return 0;
1474         }
1475
1476         SMB_ASSERT(ad->ad_fsp != NULL);
1477
1478         status = close_file(NULL, ad->ad_fsp, NORMAL_CLOSE);
1479         if (!NT_STATUS_IS_OK(status)) {
1480                 DBG_ERR("Closing [%s] failed: %s\n",
1481                         fsp_str_dbg(ad->ad_fsp), nt_errstr(status));
1482         }
1483
1484         return 0;
1485 }
1486
1487 /**
1488  * Allocate a struct adouble without initialiing it
1489  *
1490  * The struct is either hang of the fsp extension context or if fsp is
1491  * NULL from ctx.
1492  *
1493  * @param[in] ctx        talloc context
1494  * @param[in] handle     vfs handle
1495  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1496  *
1497  * @return               adouble handle
1498  **/
1499 static struct adouble *ad_alloc(TALLOC_CTX *ctx,
1500                                 adouble_type_t type)
1501 {
1502         int rc = 0;
1503         size_t adsize = 0;
1504         struct adouble *ad;
1505
1506         switch (type) {
1507         case ADOUBLE_META:
1508                 adsize = AD_DATASZ_XATTR;
1509                 break;
1510         case ADOUBLE_RSRC:
1511                 adsize = AD_DATASZ_DOT_UND;
1512                 break;
1513         default:
1514                 return NULL;
1515         }
1516
1517         ad = talloc_zero(ctx, struct adouble);
1518         if (ad == NULL) {
1519                 rc = -1;
1520                 goto exit;
1521         }
1522
1523         if (adsize) {
1524                 ad->ad_data = talloc_zero_array(ad, char, adsize);
1525                 if (ad->ad_data == NULL) {
1526                         rc = -1;
1527                         goto exit;
1528                 }
1529         }
1530
1531         ad->ad_type = type;
1532         ad->ad_magic = AD_MAGIC;
1533         ad->ad_version = AD_VERSION;
1534
1535         talloc_set_destructor(ad, adouble_destructor);
1536
1537 exit:
1538         if (rc != 0) {
1539                 TALLOC_FREE(ad);
1540         }
1541         return ad;
1542 }
1543
1544 /**
1545  * Allocate and initialize a new struct adouble
1546  *
1547  * @param[in] ctx        talloc context
1548  * @param[in] type       type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1549  *
1550  * @return               adouble handle, initialized
1551  **/
1552 struct adouble *ad_init(TALLOC_CTX *ctx, adouble_type_t type)
1553 {
1554         int rc = 0;
1555         const struct ad_entry_order  *eid;
1556         struct adouble *ad = NULL;
1557         time_t t = time(NULL);
1558
1559         switch (type) {
1560         case ADOUBLE_META:
1561                 eid = entry_order_meta_xattr;
1562                 break;
1563         case ADOUBLE_RSRC:
1564                 eid = entry_order_dot_und;
1565                 break;
1566         default:
1567                 return NULL;
1568         }
1569
1570         ad = ad_alloc(ctx, type);
1571         if (ad == NULL) {
1572                 return NULL;
1573         }
1574
1575         while (eid->id) {
1576                 ad->ad_eid[eid->id].ade_off = eid->offset;
1577                 ad->ad_eid[eid->id].ade_len = eid->len;
1578                 eid++;
1579         }
1580
1581         /* put something sane in the date fields */
1582         ad_setdate(ad, AD_DATE_CREATE | AD_DATE_UNIX, t);
1583         ad_setdate(ad, AD_DATE_MODIFY | AD_DATE_UNIX, t);
1584         ad_setdate(ad, AD_DATE_ACCESS | AD_DATE_UNIX, t);
1585         ad_setdate(ad, AD_DATE_BACKUP, htonl(AD_DATE_START));
1586
1587         if (rc != 0) {
1588                 TALLOC_FREE(ad);
1589         }
1590         return ad;
1591 }
1592
1593 static struct adouble *ad_get_internal(TALLOC_CTX *ctx,
1594                                        vfs_handle_struct *handle,
1595                                        files_struct *fsp,
1596                                        const struct smb_filename *smb_fname,
1597                                        adouble_type_t type)
1598 {
1599         int rc = 0;
1600         ssize_t len;
1601         struct adouble *ad = NULL;
1602         int mode;
1603
1604         if (fsp != NULL) {
1605                 smb_fname = fsp->base_fsp->fsp_name;
1606         }
1607
1608         DEBUG(10, ("ad_get(%s) called for %s\n",
1609                    type == ADOUBLE_META ? "meta" : "rsrc",
1610                    smb_fname->base_name));
1611
1612         ad = ad_alloc(ctx, type);
1613         if (ad == NULL) {
1614                 rc = -1;
1615                 goto exit;
1616         }
1617
1618         /* Try rw first so we can use the fd in ad_convert() */
1619         mode = O_RDWR;
1620
1621         rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
1622         if (rc == -1 && ((errno == EROFS) || (errno == EACCES))) {
1623                 mode = O_RDONLY;
1624                 rc = ad_open(handle, ad, fsp, smb_fname, mode, 0);
1625         }
1626         if (rc == -1) {
1627                 DBG_DEBUG("ad_open [%s] error [%s]\n",
1628                           smb_fname->base_name, strerror(errno));
1629                 goto exit;
1630
1631         }
1632
1633         len = ad_read(handle, ad, smb_fname);
1634         if (len == -1) {
1635                 DEBUG(10, ("error reading AppleDouble for %s\n",
1636                         smb_fname->base_name));
1637                 rc = -1;
1638                 goto exit;
1639         }
1640
1641 exit:
1642         DEBUG(10, ("ad_get(%s) for %s returning %d\n",
1643                   type == ADOUBLE_META ? "meta" : "rsrc",
1644                   smb_fname->base_name, rc));
1645
1646         if (rc != 0) {
1647                 TALLOC_FREE(ad);
1648         }
1649         return ad;
1650 }
1651
1652 /**
1653  * Return AppleDouble data for a file
1654  *
1655  * @param[in] ctx      talloc context
1656  * @param[in] handle   vfs handle
1657  * @param[in] smb_fname pathname to file or directory
1658  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1659  *
1660  * @return             talloced struct adouble or NULL on error
1661  **/
1662 struct adouble *ad_get(TALLOC_CTX *ctx,
1663                               vfs_handle_struct *handle,
1664                               const struct smb_filename *smb_fname,
1665                               adouble_type_t type)
1666 {
1667         return ad_get_internal(ctx, handle, NULL, smb_fname, type);
1668 }
1669
1670 /**
1671  * Return AppleDouble data for a file
1672  *
1673  * @param[in] ctx      talloc context
1674  * @param[in] handle   vfs handle
1675  * @param[in] fsp      fsp to use for IO
1676  * @param[in] type     type of AppleDouble, ADOUBLE_META or ADOUBLE_RSRC
1677  *
1678  * @return             talloced struct adouble or NULL on error
1679  **/
1680 struct adouble *ad_fget(TALLOC_CTX *ctx, vfs_handle_struct *handle,
1681                         files_struct *fsp, adouble_type_t type)
1682 {
1683         return ad_get_internal(ctx, handle, fsp, NULL, type);
1684 }
1685
1686 /**
1687  * Set AppleDouble metadata on a file or directory
1688  *
1689  * @param[in] ad      adouble handle
1690  *
1691  * @param[in] smb_fname    pathname to file or directory
1692  *
1693  * @return            status code, 0 means success
1694  **/
1695 int ad_set(vfs_handle_struct *handle,
1696            struct adouble *ad,
1697            const struct smb_filename *smb_fname)
1698 {
1699         bool ok;
1700         int ret;
1701
1702         DBG_DEBUG("Path [%s]\n", smb_fname->base_name);
1703
1704         if (ad->ad_type != ADOUBLE_META) {
1705                 DBG_ERR("ad_set on [%s] used with ADOUBLE_RSRC\n",
1706                         smb_fname->base_name);
1707                 return -1;
1708         }
1709
1710         ok = ad_pack(handle, ad, NULL);
1711         if (!ok) {
1712                 return -1;
1713         }
1714
1715         ret = SMB_VFS_SETXATTR(handle->conn,
1716                                smb_fname,
1717                                AFPINFO_EA_NETATALK,
1718                                ad->ad_data,
1719                                AD_DATASZ_XATTR, 0);
1720
1721         DBG_DEBUG("Path [%s] ret [%d]\n", smb_fname->base_name, ret);
1722
1723         return ret;
1724 }
1725
1726 /**
1727  * Set AppleDouble metadata on a file or directory
1728  *
1729  * @param[in] ad      adouble handle
1730  * @param[in] fsp     file handle
1731  *
1732  * @return            status code, 0 means success
1733  **/
1734 int ad_fset(struct vfs_handle_struct *handle,
1735             struct adouble *ad,
1736             files_struct *fsp)
1737 {
1738         int rc = -1;
1739         ssize_t len;
1740         bool ok;
1741
1742         DBG_DEBUG("Path [%s]\n", fsp_str_dbg(fsp));
1743
1744         if ((fsp == NULL)
1745             || (fsp->fh == NULL)
1746             || (fsp->fh->fd == -1))
1747         {
1748                 smb_panic("bad fsp");
1749         }
1750
1751         ok = ad_pack(handle, ad, fsp);
1752         if (!ok) {
1753                 return -1;
1754         }
1755
1756         switch (ad->ad_type) {
1757         case ADOUBLE_META:
1758                 rc = SMB_VFS_NEXT_SETXATTR(handle,
1759                                            fsp->fsp_name,
1760                                            AFPINFO_EA_NETATALK,
1761                                            ad->ad_data,
1762                                            AD_DATASZ_XATTR, 0);
1763                 break;
1764
1765         case ADOUBLE_RSRC:
1766                 len = SMB_VFS_NEXT_PWRITE(handle,
1767                                           fsp,
1768                                           ad->ad_data,
1769                                           ad_getentryoff(ad, ADEID_RFORK),
1770                                           0);
1771                 if (len != ad_getentryoff(ad, ADEID_RFORK)) {
1772                         DBG_ERR("short write on %s: %zd", fsp_str_dbg(fsp), len);
1773                         return -1;
1774                 }
1775                 rc = 0;
1776                 break;
1777
1778         default:
1779                 return -1;
1780         }
1781
1782         DBG_DEBUG("Path [%s] rc [%d]\n", fsp_str_dbg(fsp), rc);
1783
1784         return rc;
1785 }
1786
1787 bool is_adouble_file(const char *path)
1788 {
1789         const char *p = NULL;
1790         int match;
1791
1792         p = strrchr(path, '/');
1793         if (p == NULL) {
1794                 p = path;
1795         } else {
1796                 p++;
1797         }
1798
1799         match = strncmp(p,
1800                         ADOUBLE_NAME_PREFIX,
1801                         strlen(ADOUBLE_NAME_PREFIX));
1802         if (match != 0) {
1803                 return false;
1804         }
1805         return true;
1806 }
1807
1808 /**
1809  * Prepend "._" to a basename
1810  * Return a new struct smb_filename with stream_name == NULL.
1811  **/
1812 int adouble_path(TALLOC_CTX *ctx,
1813                  const struct smb_filename *smb_fname_in,
1814                  struct smb_filename **pp_smb_fname_out)
1815 {
1816         char *parent;
1817         const char *base;
1818         struct smb_filename *smb_fname = cp_smb_filename(ctx,
1819                                                 smb_fname_in);
1820
1821         if (smb_fname == NULL) {
1822                 return -1;
1823         }
1824
1825         /* We need streamname to be NULL */
1826         TALLOC_FREE(smb_fname->stream_name);
1827
1828         /* And we're replacing base_name. */
1829         TALLOC_FREE(smb_fname->base_name);
1830
1831         SET_STAT_INVALID(smb_fname->st);
1832
1833         if (!parent_dirname(smb_fname, smb_fname_in->base_name,
1834                                 &parent, &base)) {
1835                 TALLOC_FREE(smb_fname);
1836                 return -1;
1837         }
1838
1839         smb_fname->base_name = talloc_asprintf(smb_fname,
1840                                         "%s/._%s", parent, base);
1841         if (smb_fname->base_name == NULL) {
1842                 TALLOC_FREE(smb_fname);
1843                 return -1;
1844         }
1845
1846         *pp_smb_fname_out = smb_fname;
1847
1848         return 0;
1849 }
1850
1851 /**
1852  * Allocate and initialize an AfpInfo struct
1853  **/
1854 AfpInfo *afpinfo_new(TALLOC_CTX *ctx)
1855 {
1856         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
1857         if (ai == NULL) {
1858                 return NULL;
1859         }
1860         ai->afpi_Signature = AFP_Signature;
1861         ai->afpi_Version = AFP_Version;
1862         ai->afpi_BackupTime = AD_DATE_START;
1863         return ai;
1864 }
1865
1866 /**
1867  * Pack an AfpInfo struct into a buffer
1868  *
1869  * Buffer size must be at least AFP_INFO_SIZE
1870  * Returns size of packed buffer
1871  **/
1872 ssize_t afpinfo_pack(const AfpInfo *ai, char *buf)
1873 {
1874         memset(buf, 0, AFP_INFO_SIZE);
1875
1876         RSIVAL(buf, 0, ai->afpi_Signature);
1877         RSIVAL(buf, 4, ai->afpi_Version);
1878         RSIVAL(buf, 12, ai->afpi_BackupTime);
1879         memcpy(buf + 16, ai->afpi_FinderInfo, sizeof(ai->afpi_FinderInfo));
1880
1881         return AFP_INFO_SIZE;
1882 }
1883
1884 /**
1885  * Unpack a buffer into a AfpInfo structure
1886  *
1887  * Buffer size must be at least AFP_INFO_SIZE
1888  * Returns allocated AfpInfo struct
1889  **/
1890 AfpInfo *afpinfo_unpack(TALLOC_CTX *ctx, const void *data)
1891 {
1892         AfpInfo *ai = talloc_zero(ctx, AfpInfo);
1893         if (ai == NULL) {
1894                 return NULL;
1895         }
1896
1897         ai->afpi_Signature = RIVAL(data, 0);
1898         ai->afpi_Version = RIVAL(data, 4);
1899         ai->afpi_BackupTime = RIVAL(data, 12);
1900         memcpy(ai->afpi_FinderInfo, (const char *)data + 16,
1901                sizeof(ai->afpi_FinderInfo));
1902
1903         if (ai->afpi_Signature != AFP_Signature
1904             || ai->afpi_Version != AFP_Version) {
1905                 DEBUG(1, ("Bad AfpInfo signature or version\n"));
1906                 TALLOC_FREE(ai);
1907         }
1908
1909         return ai;
1910 }