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 */ 37int 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) 71 ( sfs.f_blocks - ( sfs.f_bfree - sfs.f_bavail )); 72#endif /* ultrix */ 73 74 /* see similar block above comments */ 75 if ( *btotal > maxVolSpace / *bsize ) { 76 *btotal = maxVolSpace; 77 } else { 78 *btotal *= *bsize; 79 } 80 81 return( AFP_OK ); 82} 83 84static int utombits(mode_t bits) 85{ 86 int mbits; 87 88 mbits = 0; 89 90 mbits |= ( bits & ( S_IREAD >> 6 )) ? AR_UREAD : 0; 91 mbits |= ( bits & ( S_IWRITE >> 6 )) ? AR_UWRITE : 0; 92 /* Do we really need this? */ 93 mbits |= ( bits & ( S_IEXEC >> 6) ) ? AR_USEARCH : 0; 94 95 return( mbits ); 96} 97 98/* -------------------------------- 99 cf AFP 3.0 page 63 100*/ 101static void utommode(const AFPObj *obj, const struct stat *stat, struct maccess *ma) 102{ 103 mode_t mode; 104 105 mode = stat->st_mode; 106 ma->ma_world = utombits( mode ); 107 mode = mode >> 3; 108 109 ma->ma_group = utombits( mode ); 110 mode = mode >> 3; 111 112 ma->ma_owner = utombits( mode ); 113 114 /* ma_user is a union of all permissions but we must follow 115 * unix perm 116 */ 117 if ( (obj->uid == stat->st_uid) || (obj->uid == 0)) { 118 ma->ma_user = ma->ma_owner | AR_UOWN; 119 } 120 else if (gmem(stat->st_gid, obj->ngroups, obj->groups)) { 121 ma->ma_user = ma->ma_group; 122 } 123 else { 124 ma->ma_user = ma->ma_world; 125 } 126 127 /* 128 * There are certain things the mac won't try if you don't have 129 * the "owner" bit set, even tho you can do these things on unix wiht 130 * only write permission. What were the things? 131 * 132 * FIXME 133 * ditto seems to care if st_uid is 0 ? 134 * was ma->ma_user & AR_UWRITE 135 * but 0 as owner is a can of worms. 136 */ 137 if ( !stat->st_uid ) { 138 ma->ma_user |= AR_UOWN; 139 } 140} 141 142#ifdef accessmode 143 144#undef accessmode 145#endif 146/* 147 * Calculate the mode for a directory using a stat() call to 148 * estimate permission. 149 * 150 * Note: the previous method, using access(), does not work correctly 151 * over NFS. 152 * 153 * dir parameter is used by AFS 154 */ 155void accessmode(const AFPObj *obj, const struct vol *vol, char *path, struct maccess *ma, struct dir *dir _U_, struct stat *st) 156{ 157 struct stat sb; 158 159 ma->ma_user = ma->ma_owner = ma->ma_world = ma->ma_group = 0; 160 if (!st) { 161 if (ostat(path, &sb, vol_syml_opt(vol)) != 0) 162 return; 163 st = &sb; 164 } 165 utommode(obj, st, ma ); 166#ifdef HAVE_ACLS 167 acltoownermode(obj, vol, path, st, ma); 168#endif 169} 170 171static mode_t mtoubits(u_char bits) 172{ 173 mode_t mode; 174 175 mode = 0; 176 177 mode |= ( bits & AR_UREAD ) ? ( (S_IREAD | S_IEXEC) >> 6 ) : 0; 178 mode |= ( bits & AR_UWRITE ) ? ( (S_IWRITE | S_IEXEC) >> 6 ) : 0; 179 /* I don't think there's a way to set the SEARCH bit by itself on a Mac 180 mode |= ( bits & AR_USEARCH ) ? ( S_IEXEC >> 6 ) : 0; */ 181 182 return( mode ); 183} 184 185/* ---------------------------------- 186 from the finder's share windows (menu--> File--> sharing...) 187 and from AFP 3.0 spec page 63 188 the mac mode should be save somewhere 189*/ 190mode_t mtoumode(struct maccess *ma) 191{ 192 mode_t mode; 193 194 mode = 0; 195 mode |= mtoubits( ma->ma_owner |ma->ma_world); 196 mode = mode << 3; 197 198 mode |= mtoubits( ma->ma_group |ma->ma_world); 199 mode = mode << 3; 200 201 mode |= mtoubits( ma->ma_world ); 202 203 return( mode ); 204} 205 206/* --------------------- */ 207int setfilunixmode (const struct vol *vol, struct path* path, mode_t mode) 208{ 209 if (!path->st_valid) { 210 of_stat(vol, path); 211 } 212 213 if (path->st_errno) { 214 return -1; 215 } 216 217 mode |= vol->v_fperm; 218 219 if (setfilmode(vol, path->u_name, mode, &path->st) < 0) 220 return -1; 221 /* we need to set write perm if read set for resource fork */ 222 return vol->vfs->vfs_setfilmode(vol, path->u_name, mode, &path->st); 223} 224 225 226/* --------------------- */ 227int setdirunixmode(const struct vol *vol, char *name, mode_t mode) 228{ 229 LOG(log_debug, logtype_afpd, "setdirunixmode('%s', mode:%04o) {v_dperm:%04o}", 230 fullpathname(name), mode, vol->v_dperm); 231 232 mode |= vol->v_dperm; 233 234 if (dir_rx_set(mode)) { 235 /* extending right? dir first then .AppleDouble in rf_setdirmode */ 236 if (chmod_acl(name, (DIRBITS | mode) & ~vol->v_umask) < 0 ) 237 return -1; 238 } 239 if (vol->vfs->vfs_setdirunixmode(vol, name, mode, NULL) < 0) { 240 return -1 ; 241 } 242 if (!dir_rx_set(mode)) { 243 if (chmod_acl(name, (DIRBITS | mode) & ~vol->v_umask) < 0 ) 244 return -1; 245 } 246 return 0; 247} 248 249/* ----------------------------- */ 250int setfilowner(const struct vol *vol, const uid_t uid, const gid_t gid, struct path* path) 251{ 252 if (ochown( path->u_name, uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) { 253 LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s", 254 uid, gid, path->u_name, strerror(errno)); 255 return -1; 256 } 257 258 if (vol->vfs->vfs_chown(vol, path->u_name, uid, gid) < 0 && errno != EPERM) { 259 LOG(log_debug, logtype_afpd, "setfilowner: rf_chown %d/%d %s: %s", 260 uid, gid, path->u_name, strerror(errno) ); 261 return -1; 262 } 263 264 return 0; 265} 266 267/* --------------------------------- 268 * uid/gid == 0 need to be handled as special cases. they really mean 269 * that user/group should inherit from other, but that doesn't fit 270 * into the unix permission scheme. we can get around this by 271 * co-opting some bits. */ 272int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const gid_t gid) 273{ 274 if (ochown(name, uid, gid, vol_syml_opt(vol)) < 0 && errno != EPERM ) { 275 LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", 276 uid, gid, fullpathname(name), strerror(errno) ); 277 } 278 279 if (vol->vfs->vfs_setdirowner(vol, name, uid, gid) < 0) 280 return -1; 281 282 return( 0 ); 283} 284