1 /*
2 * Copyright (c) 1990,1993 Regents of The University of Michigan.
3 * All Rights Reserved. See COPYRIGHT.
4 */
5
6 #ifdef HAVE_CONFIG_H
7 #include "config.h"
8 #endif /* HAVE_CONFIG_H */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <inttypes.h>
13 #include <string.h>
14 #include <errno.h>
15 #include <limits.h>
16 #include <sys/param.h>
17 #include <atalk/logger.h>
18 #include <atalk/adouble.h>
19 #include <atalk/vfs.h>
20 #include <atalk/afp.h>
21 #include <atalk/util.h>
22 #include <atalk/unix.h>
23 #include <atalk/acl.h>
24
25 #include "auth.h"
26 #include "directory.h"
27 #include "volume.h"
28 #include "unix.h"
29 #include "fork.h"
30 #ifdef HAVE_ACLS
31 #include "acls.h"
32 #endif
33
34 /*
35 * Get the free space on a partition.
36 */
ustatfs_getvolspace(const struct vol * vol,VolSpace * bfree,VolSpace * btotal,uint32_t * bsize)37 int ustatfs_getvolspace(const struct vol *vol, VolSpace *bfree, VolSpace *btotal, uint32_t *bsize)
38 {
39 VolSpace maxVolSpace = UINT64_MAX;
40
41 #ifdef ultrix
42 struct fs_data sfs;
43 #else /*ultrix*/
44 struct statfs sfs;
45 #endif /*ultrix*/
46
47 if ( statfs( vol->v_path, &sfs ) < 0 ) {
48 LOG(log_error, logtype_afpd, "ustatfs_getvolspace unable to stat %s", vol->v_path);
49 return( AFPERR_PARAM );
50 }
51
52 #ifdef ultrix
53 *bfree = (VolSpace) sfs.fd_req.bfreen;
54 *bsize = 1024;
55 #else /* !ultrix */
56 *bfree = (VolSpace) sfs.f_bavail;
57 *bsize = sfs.f_frsize;
58 #endif /* ultrix */
59
60 if ( *bfree > maxVolSpace / *bsize ) {
61 *bfree = maxVolSpace;
62 } else {
63 *bfree *= *bsize;
64 }
65
66 #ifdef ultrix
67 *btotal = (VolSpace)
68 ( sfs.fd_req.btot - ( sfs.fd_req.bfree - sfs.fd_req.bfreen ));
69 #else /* !ultrix */
70 *btotal = (VolSpace) sfs.f_blocks;
71 #endif /* ultrix */
72
73 /* see similar block above comments */
74 if ( *btotal > maxVolSpace / *bsize ) {
75 *btotal = maxVolSpace;
76 } else {
77 *btotal *= *bsize;
78 }
79
80 return( AFP_OK );
81 }
82
utombits(mode_t bits)83 static int utombits(mode_t bits)
84 {
85 int mbits;
86
87 mbits = 0;
88
89 mbits |= ( bits & ( S_IREAD >> 6 )) ? AR_UREAD : 0;
90 mbits |= ( bits & ( S_IWRITE >> 6 )) ? AR_UWRITE : 0;
91 /* Do we really need this? */
92 mbits |= ( bits & ( S_IEXEC >> 6) ) ? AR_USEARCH : 0;
93
94 return( mbits );
95 }
96
97 /* --------------------------------
98 cf AFP 3.0 page 63
99 */
utommode(const AFPObj * obj,const struct stat * stat,struct maccess * ma)100 static void utommode(const AFPObj *obj, const struct stat *stat, struct maccess *ma)
101 {
102 mode_t mode;
103
104 mode = stat->st_mode;
105 ma->ma_world = utombits( mode );
106 mode = mode >> 3;
107
108 ma->ma_group = utombits( mode );
109 mode = mode >> 3;
110
111 ma->ma_owner = utombits( mode );
112
113 /* ma_user is a union of all permissions but we must follow
114 * unix perm
115 */
116 if (obj->euid == 0) {
117 ma->ma_user = AR_UREAD | AR_UWRITE | AR_USEARCH | AR_UOWN;
118 } else if (obj->uid == stat->st_uid) {
119 ma->ma_user = ma->ma_owner | AR_UOWN;
120 }
121 else if (gmem(stat->st_gid, obj->ngroups, obj->groups)) {
122 ma->ma_user = ma->ma_group;
123 }
124 else {
125 ma->ma_user = ma->ma_world;
126 }
127
128 /*
129 * There are certain things the mac won't try if you don't have
130 * the "owner" bit set, even tho you can do these things on unix wiht
131 * only write permission. What were the things?
132 *
133 * FIXME
134 * ditto seems to care if st_uid is 0 ?
135 * was ma->ma_user & AR_UWRITE
136 * but 0 as owner is a can of worms.
137 */
138 if ( !stat->st_uid ) {
139 ma->ma_user |= AR_UOWN;
140 }
141 }
142
143 #ifdef accessmode
144
145 #undef accessmode
146 #endif
147 /*
148 * Calculate the mode for a directory using a stat() call to
149 * estimate permission.
150 *
151 * Note: the previous method, using access(), does not work correctly
152 * over NFS.
153 *
154 * dir parameter is used by AFS
155 */
accessmode(const AFPObj * obj,const struct vol * vol,char * path,struct maccess * ma,struct dir * dir _U_,struct stat * st)156 void accessmode(const AFPObj *obj, const struct vol *vol, char *path, struct maccess *ma, struct dir *dir _U_, struct stat *st)
157 {
158 struct stat sb;
159
160 ma->ma_user = ma->ma_owner = ma->ma_world = ma->ma_group = 0;
161 if (!st) {
162 if (ostat(path, &sb, vol_syml_opt(vol)) != 0)
163 return;
164 st = &sb;
165 }
166 utommode(obj, st, ma );
167 #ifdef HAVE_ACLS
168 acltoownermode(obj, vol, path, st, ma);
169 #endif
170 }
171
mtoubits(u_char bits)172 static mode_t mtoubits(u_char bits)
173 {
174 mode_t mode;
175
176 mode = 0;
177
178 mode |= ( bits & AR_UREAD ) ? ( (S_IREAD | S_IEXEC) >> 6 ) : 0;
179 mode |= ( bits & AR_UWRITE ) ? ( (S_IWRITE | S_IEXEC) >> 6 ) : 0;
180 /* I don't think there's a way to set the SEARCH bit by itself on a Mac
181 mode |= ( bits & AR_USEARCH ) ? ( S_IEXEC >> 6 ) : 0; */
182
183 return( mode );
184 }
185
186 /* ----------------------------------
187 from the finder's share windows (menu--> File--> sharing...)
188 and from AFP 3.0 spec page 63
189 the mac mode should be save somewhere
190 */
mtoumode(struct maccess * ma)191 mode_t mtoumode(struct maccess *ma)
192 {
193 mode_t mode;
194
195 mode = 0;
196 mode |= mtoubits( ma->ma_owner |ma->ma_world);
197 mode = mode << 3;
198
199 mode |= mtoubits( ma->ma_group |ma->ma_world);
200 mode = mode << 3;
201
202 mode |= mtoubits( ma->ma_world );
203
204 return( mode );
205 }
206
207 /* --------------------- */
setfilunixmode(const struct vol * vol,struct path * path,mode_t mode)208 int setfilunixmode (const struct vol *vol, struct path* path, mode_t mode)
209 {
210 if (!path->st_valid) {
211 of_stat(vol, path);
212 }
213
214 if (path->st_errno) {
215 return -1;
216 }
217
218 mode |= vol->v_fperm;
219
220 if (setfilmode(vol, path->u_name, mode, &path->st) < 0)
221 return -1;
222 /* we need to set write perm if read set for resource fork */
223 return vol->vfs->vfs_setfilmode(vol, path->u_name, mode, &path->st);
224 }
225
226
227 /* --------------------- */
setdirunixmode(const struct vol * vol,char * name,mode_t mode)228 int setdirunixmode(const struct vol *vol, char *name, mode_t mode)
229 {
230 LOG(log_debug, logtype_afpd, "setdirunixmode('%s', mode:%04o) {v_dperm:%04o}",
231 fullpathname(name), mode, vol->v_dperm);
232
233 mode |= vol->v_dperm | DIRBITS;
234 mode &= ~vol->v_umask;
235
236 if (dir_rx_set(mode)) {
237 /* extending right? dir first then .AppleDouble in rf_setdirmode */
238 if (ochmod(name, mode, NULL,
239 vol_syml_opt(vol) | vol_chmod_opt(vol)
240 ) < 0)
241 return -1;
242 }
243 if (vol->vfs->vfs_setdirunixmode(vol, name, mode, NULL) < 0) {
244 return -1 ;
245 }
246 if (!dir_rx_set(mode)) {
247 if (ochmod(name, mode, NULL,
248 vol_syml_opt(vol) | vol_chmod_opt(vol)
249 ) < 0)
250 return -1;
251 }
252 return 0;
253 }
254
255 /* ----------------------------- */
setfilowner(const struct vol * vol,const uid_t uid,const gid_t gid,struct path * path)256 int setfilowner(const struct vol *vol, const uid_t uid, const gid_t gid, struct path* path)
257 {
258 if (ochown( path->u_name, uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) {
259 LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s",
260 uid, gid, path->u_name, strerror(errno));
261 return -1;
262 }
263
264 if (vol->vfs->vfs_chown(vol, path->u_name, uid, gid) < 0 && errno != EPERM) {
265 LOG(log_debug, logtype_afpd, "setfilowner: rf_chown %d/%d %s: %s",
266 uid, gid, path->u_name, strerror(errno) );
267 return -1;
268 }
269
270 return 0;
271 }
272
273 /* ---------------------------------
274 * uid/gid == 0 need to be handled as special cases. they really mean
275 * that user/group should inherit from other, but that doesn't fit
276 * into the unix permission scheme. we can get around this by
277 * co-opting some bits. */
setdirowner(const struct vol * vol,const char * name,const uid_t uid,const gid_t gid)278 int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const gid_t gid)
279 {
280 if (ochown(name, uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) {
281 LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s",
282 uid, gid, fullpathname(name), strerror(errno) );
283 }
284
285 if (vol->vfs->vfs_setdirowner(vol, name, uid, gid) < 0)
286 return -1;
287
288 return( 0 );
289 }
290