1 /*
2   Copyright Ⓒ 2009  Regis Duchesne
3 
4     This program is free software: you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation, either version 3 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 */
14 
15 #include <sys/attr.h>
16 #include <sys/mount.h>
17 
18 #ifndef ATTR_CMN_FILEID
19 #define ATTR_CMN_FILEID                         0x02000000
20 #endif
21 #ifndef ATTR_CMN_PARENTID
22 #define ATTR_CMN_PARENTID                       0x04000000
23 #endif
24 #ifndef ATTR_CMN_FULLPATH
25 #define ATTR_CMN_FULLPATH                       0x08000000
26 #endif
27 #ifndef ATTR_CMN_RETURNED_ATTRS
28 #define ATTR_CMN_RETURNED_ATTRS                 0x80000000
29 #endif
30 
31 #ifdef LIBFAKEROOT_DEBUGGING
32 extern int fakeroot_debug;
33 
34 #endif /* LIBFAKEROOT_DEBUGGING */
35 static void
patchattr(void * attrList,void * attrBuf,uid_t uid,gid_t gid,mode_t mode)36 patchattr(void *attrList, void *attrBuf, uid_t uid, gid_t gid, mode_t mode)
37 {
38   /* Attributes, in the order in which they are returned (which is the same as
39      the order they are described in the man page).
40   */
41   static const struct {
42     const char *name;
43     u_int32_t value;
44     size_t size;
45     int isRef;
46   } attrs[] = {
47 #define PATCHATTR(a,b,c) { #a, a, b, c, }
48     PATCHATTR(ATTR_CMN_RETURNED_ATTRS, sizeof (attribute_set_t), 0),
49     PATCHATTR(ATTR_CMN_NAME, sizeof (attrreference_t), 1),
50     PATCHATTR(ATTR_CMN_DEVID, sizeof (dev_t), 0),
51     PATCHATTR(ATTR_CMN_FSID, sizeof (fsid_t), 0),
52     PATCHATTR(ATTR_CMN_OBJTYPE, sizeof (fsobj_type_t), 0),
53     PATCHATTR(ATTR_CMN_OBJTAG, sizeof (fsobj_tag_t), 0),
54     PATCHATTR(ATTR_CMN_OBJID, sizeof (fsobj_id_t), 0),
55     PATCHATTR(ATTR_CMN_OBJPERMANENTID, sizeof (fsobj_id_t), 0),
56     PATCHATTR(ATTR_CMN_PAROBJID, sizeof (fsobj_id_t), 0),
57     PATCHATTR(ATTR_CMN_SCRIPT, sizeof (text_encoding_t), 0),
58     PATCHATTR(ATTR_CMN_CRTIME, sizeof (struct timespec), 0),
59     PATCHATTR(ATTR_CMN_MODTIME, sizeof (struct timespec), 0),
60     PATCHATTR(ATTR_CMN_CHGTIME, sizeof (struct timespec), 0),
61     PATCHATTR(ATTR_CMN_ACCTIME, sizeof (struct timespec), 0),
62     PATCHATTR(ATTR_CMN_BKUPTIME, sizeof (struct timespec), 0),
63     PATCHATTR(ATTR_CMN_FNDRINFO, 32, 0),
64     PATCHATTR(ATTR_CMN_OWNERID, sizeof (uid_t), 0),
65     PATCHATTR(ATTR_CMN_GRPID, sizeof (gid_t), 0),
66     PATCHATTR(ATTR_CMN_ACCESSMASK, sizeof (u_int32_t), 0),
67     PATCHATTR(ATTR_CMN_NAMEDATTRCOUNT, sizeof (u_int32_t), 0),
68     PATCHATTR(ATTR_CMN_NAMEDATTRLIST, sizeof (attrreference_t), 1),
69     PATCHATTR(ATTR_CMN_FLAGS, sizeof (u_int32_t), 0),
70     PATCHATTR(ATTR_CMN_USERACCESS, sizeof (u_int32_t), 0),
71     PATCHATTR(ATTR_CMN_EXTENDED_SECURITY, sizeof (attrreference_t), 1),
72     PATCHATTR(ATTR_CMN_UUID, sizeof (guid_t), 0),
73     PATCHATTR(ATTR_CMN_GRPUUID, sizeof (guid_t), 0),
74     PATCHATTR(ATTR_CMN_FILEID, sizeof (u_int64_t), 0),
75     PATCHATTR(ATTR_CMN_PARENTID, sizeof (u_int64_t), 0),
76     PATCHATTR(ATTR_CMN_FULLPATH, sizeof (attrreference_t), 1),
77 #undef PATCHATTR
78   };
79   struct attrlist *l = attrList;
80   unsigned char *b = attrBuf;
81   unsigned i;
82 
83 #ifdef LIBFAKEROOT_DEBUGGING
84   if (fakeroot_debug) {
85     fprintf(stderr, "patchattr actual attrBuf size %u\n", *(u_int32_t *)b);
86   }
87 #endif /* LIBFAKEROOT_DEBUGGING */
88   b += sizeof (u_int32_t);
89   for (i = 0; i < sizeof attrs / sizeof attrs[0]; i++) {
90     if (l->commonattr & attrs[i].value) {
91 #ifdef LIBFAKEROOT_DEBUGGING
92       if (fakeroot_debug) {
93         fprintf(stderr, "patchattr attr %s: yes\n", attrs[i].name);
94         if (attrs[i].isRef) {
95           size_t here = b - (unsigned char *)attrBuf;
96           size_t begin = here + ((attrreference_t *)b)->attr_dataoffset;
97           size_t size = ((attrreference_t *)b)->attr_length;
98           size_t alignedEnd = (begin + size + 3) & ~3;
99           fprintf(stderr, "patchattr reference begin %zu size %zu aligned end %zu\n", begin, size, alignedEnd);
100         }
101       }
102 #endif /* LIBFAKEROOT_DEBUGGING */
103       if (attrs[i].value == ATTR_CMN_OWNERID) {
104 #ifdef LIBFAKEROOT_DEBUGGING
105         if (fakeroot_debug) {
106           fprintf(stderr, "patchattr owner %d\n", *(uid_t *)b);
107         }
108 #endif /* LIBFAKEROOT_DEBUGGING */
109         *(uid_t *)b = uid;
110       }
111       if (attrs[i].value == ATTR_CMN_GRPID) {
112 #ifdef LIBFAKEROOT_DEBUGGING
113         if (fakeroot_debug) {
114           fprintf(stderr, "patchattr group %d\n", *(gid_t *)b);
115         }
116 #endif /* LIBFAKEROOT_DEBUGGING */
117         *(gid_t *)b = gid;
118       }
119       if (attrs[i].value == ATTR_CMN_ACCESSMASK) {
120 #ifdef LIBFAKEROOT_DEBUGGING
121         if (fakeroot_debug) {
122           fprintf(stderr, "patchattr mode 0%o\n", *(mode_t *)b);
123         }
124 #endif /* LIBFAKEROOT_DEBUGGING */
125         *(mode_t *)b = mode;
126       }
127       b += (attrs[i].size + 3) & ~3;
128     }
129   }
130 #ifdef LIBFAKEROOT_DEBUGGING
131   if (fakeroot_debug) {
132     size_t here = b - (unsigned char *)attrBuf;
133     fprintf(stderr, "patchattr attrBuf fixed size %zu\n", here);
134   }
135 #endif /* LIBFAKEROOT_DEBUGGING */
136 }
137