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 
16 #if defined __APPLE__ && !defined __LP64__
17 /*
18    In this file, we want 'struct stat' to have a 32-bit 'ino_t'.
19    We use 'struct stat64' when we need a 64-bit 'ino_t'.
20 */
21 #define _DARWIN_NO_64_BIT_INODE
22 
23 /*
24    This file is for 32-bit symbols which have the "$UNIX2003" version, i.e.
25    32-bit symbols whose semantics adhere to the SUSv3 standard.
26 */
27 #define _DARWIN_C_SOURCE
28 
29 #include "config.h"
30 #include "communicate.h"
31 
32 #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
33 
34 #ifdef STUPID_ALPHA_HACK
35 #define SEND_STAT(a,b,c) send_stat(a,b,c)
36 #define SEND_STAT64(a,b,c) send_stat64(a,b,c)
37 #define SEND_GET_STAT(a,b) send_get_stat(a,b)
38 #define SEND_GET_STAT64(a,b) send_get_stat64(a,b)
39 #else
40 #define SEND_STAT(a,b,c) send_stat(a,b)
41 #define SEND_STAT64(a,b,c) send_stat64(a,b)
42 #define SEND_GET_STAT(a,b) send_get_stat(a)
43 #define SEND_GET_STAT64(a,b) send_get_stat64(a)
44 #endif
45 
46 /*
47    These INT_* (which stands for internal) macros should always be used when
48    the fakeroot library owns the storage of the stat variable.
49 */
50 #ifdef STAT64_SUPPORT
51 #define INT_STRUCT_STAT struct stat64
52 #define INT_NEXT_STAT(a,b) NEXT_STAT64(_STAT_VER,a,b)
53 #define INT_NEXT_LSTAT(a,b) NEXT_LSTAT64(_STAT_VER,a,b)
54 #define INT_NEXT_FSTAT(a,b) NEXT_FSTAT64(_STAT_VER,a,b)
55 #define INT_NEXT_FSTATAT(a,b,c,d) NEXT_FSTATAT64(_STAT_VER,a,b,c,d)
56 #define INT_SEND_STAT(a,b) SEND_STAT64(a,b,_STAT_VER)
57 #else
58 #define INT_STRUCT_STAT struct stat
59 #define INT_NEXT_STAT(a,b) NEXT_STAT(_STAT_VER,a,b)
60 #define INT_NEXT_LSTAT(a,b) NEXT_LSTAT(_STAT_VER,a,b)
61 #define INT_NEXT_FSTAT(a,b) NEXT_FSTAT(_STAT_VER,a,b)
62 #define INT_NEXT_FSTATAT(a,b,c,d) NEXT_FSTATAT(_STAT_VER,a,b,c,d)
63 #define INT_SEND_STAT(a,b) SEND_STAT(a,b,_STAT_VER)
64 #endif
65 
66 #include <stdio.h>
67 #include <unistd.h>
68 #include <errno.h>
69 #include <spawn.h>
70 #ifdef HAVE_SYS_ACL_H
71 #include <sys/acl.h>
72 #endif /* HAVE_SYS_ACL_H */
73 #if HAVE_FTS_H
74 #include <fts.h>
75 #endif /* HAVE_FTS_H */
76 
77 #include "patchattr.h"
78 #include "wrapped.h"
79 #include "wraptmpf.h"
80 #include "wrapdef.h"
81 
82 extern int fakeroot_disabled;
83 
84 #ifdef LCHOWN_SUPPORT
85 extern int dont_try_chown() __attribute__((visibility("hidden")));
86 
lchown$UNIX2003(const char * path,uid_t owner,gid_t group)87 int lchown$UNIX2003(const char *path, uid_t owner, gid_t group){
88   INT_STRUCT_STAT st;
89   int r=0;
90 
91 #ifdef LIBFAKEROOT_DEBUGGING
92   if (fakeroot_debug) {
93     fprintf(stderr, "lchown$UNIX2003 path %s owner %d group %d\n", path, owner, group);
94   }
95 #endif /* LIBFAKEROOT_DEBUGGING */
96   r=INT_NEXT_LSTAT(path, &st);
97   if(r)
98     return r;
99   st.st_uid=owner;
100   st.st_gid=group;
101   INT_SEND_STAT(&st,chown_func);
102   if(!dont_try_chown())
103     r=next_lchown$UNIX2003(path,owner,group);
104   else
105     r=0;
106   if(r&&(errno==EPERM))
107     r=0;
108 
109   return r;
110 }
111 #endif
112 
chmod$UNIX2003(const char * path,mode_t mode)113 int chmod$UNIX2003(const char *path, mode_t mode){
114   INT_STRUCT_STAT st;
115   int r;
116 
117 #ifdef LIBFAKEROOT_DEBUGGING
118   if (fakeroot_debug) {
119     fprintf(stderr, "chmod$UNIX2003 path %s\n", path);
120   }
121 #endif /* LIBFAKEROOT_DEBUGGING */
122   r=INT_NEXT_STAT(path, &st);
123   if(r)
124     return r;
125 
126   st.st_mode=(mode&ALLPERMS)|(st.st_mode&~ALLPERMS);
127 
128   INT_SEND_STAT(&st, chmod_func);
129 
130   /* if a file is unwritable, then root can still write to it
131      (no matter who owns the file). If we are fakeroot, the only
132      way to fake this is to always make the file writable, readable
133      etc for the real user (who started fakeroot). Also holds for
134      the exec bit of directories.
135      Yes, packages requering that are broken. But we have lintian
136      to get rid of broken packages, not fakeroot.
137   */
138   mode |= 0600;
139   if(S_ISDIR(st.st_mode))
140     mode |= 0100;
141 
142   r=next_chmod$UNIX2003(path, mode);
143   if(r&&(errno==EPERM))
144     r=0;
145 #ifdef EFTYPE		/* available under FreeBSD kernel */
146   if(r&&(errno==EFTYPE))
147     r=0;
148 #endif
149   return r;
150 }
151 
fchmod$UNIX2003(int fd,mode_t mode)152 int fchmod$UNIX2003(int fd, mode_t mode){
153   int r;
154   INT_STRUCT_STAT st;
155 
156 
157 #ifdef LIBFAKEROOT_DEBUGGING
158   if (fakeroot_debug) {
159     fprintf(stderr, "fchmod$UNIX2003 fd %d\n", fd);
160   }
161 #endif /* LIBFAKEROOT_DEBUGGING */
162   r=INT_NEXT_FSTAT(fd, &st);
163 
164   if(r)
165     return(r);
166 
167   st.st_mode=(mode&ALLPERMS)|(st.st_mode&~ALLPERMS);
168   INT_SEND_STAT(&st,chmod_func);
169 
170   /* see chmod() for comment */
171   mode |= 0600;
172   if(S_ISDIR(st.st_mode))
173     mode |= 0100;
174 
175   r=next_fchmod$UNIX2003(fd, mode);
176   if(r&&(errno==EPERM))
177     r=0;
178 #ifdef EFTYPE		/* available under FreeBSD kernel */
179   if(r&&(errno==EFTYPE))
180     r=0;
181 #endif
182   return r;
183 }
184 
185 extern int set_faked_reuid(uid_t ruid, uid_t euid) __attribute__((visibility("hidden")));
186 
setreuid$UNIX2003(SETREUID_ARG ruid,SETREUID_ARG euid)187 int setreuid$UNIX2003(SETREUID_ARG ruid, SETREUID_ARG euid){
188 #ifdef LIBFAKEROOT_DEBUGGING
189   if (fakeroot_debug) {
190     fprintf(stderr, "setreuid$UNIX2003\n");
191   }
192 #endif /* LIBFAKEROOT_DEBUGGING */
193   if (fakeroot_disabled)
194     return next_setreuid$UNIX2003(ruid, euid);
195   return set_faked_reuid(ruid, euid);
196 }
197 
198 extern int set_faked_regid(gid_t rgid, gid_t egid) __attribute__((visibility("hidden")));
199 
setregid$UNIX2003(SETREGID_ARG rgid,SETREGID_ARG egid)200 int setregid$UNIX2003(SETREGID_ARG rgid, SETREGID_ARG egid){
201 #ifdef LIBFAKEROOT_DEBUGGING
202   if (fakeroot_debug) {
203     fprintf(stderr, "setregid$UNIX2003\n");
204   }
205 #endif /* LIBFAKEROOT_DEBUGGING */
206   if (fakeroot_disabled)
207     return next_setregid$UNIX2003(rgid, egid);
208   return set_faked_regid(rgid, egid);
209 }
210 
211 int
getattrlist$UNIX2003(const char * path,void * attrList,void * attrBuf,size_t attrBufSize,unsigned long options)212 getattrlist$UNIX2003(const char *path, void *attrList, void *attrBuf,
213             size_t attrBufSize, unsigned long options)
214 {
215   int r;
216   struct stat st;
217 
218 #ifdef LIBFAKEROOT_DEBUGGING
219   if (fakeroot_debug) {
220     fprintf(stderr, "getattrlist$UNIX2003 path %s\n", path);
221   }
222 #endif /* LIBFAKEROOT_DEBUGGING */
223   r=next_getattrlist$UNIX2003(path, attrList, attrBuf, attrBufSize, options);
224   if (r) {
225     return r;
226   }
227   if (options & FSOPT_NOFOLLOW) {
228     r=WRAP_LSTAT(path, &st);
229   } else {
230     r=WRAP_STAT(path, &st);
231   }
232   if (r) {
233     return r;
234   }
235   patchattr(attrList, attrBuf, st.st_uid, st.st_gid, st.st_mode);
236 
237   return 0;
238 }
239 #endif /* MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 */
240 #endif /* if defined __APPLE__ && !defined __LP64__ */
241