#include <string.h>
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <grp.h>
#include <pwd.h>
#include <sys/param.h>
#include <atalk/errchk.h>
#include <atalk/globals.h>
#include <atalk/fce_api.h>
+#include <atalk/netatalk_conf.h>
#include "directory.h"
#include "dircache.h"
* If we aren't the file's owner we can't change its perms when moving it and smb
* nfs,... don't even try.
*/
-#define AFP_CHECK_ACCESS
-
-int check_access(char *path, int mode)
+int check_access(const AFPObj *obj, struct vol *vol, char *path, int mode)
{
-#ifdef AFP_CHECK_ACCESS
struct maccess ma;
char *p;
if (!p)
return -1;
- accessmode(current_vol, p, &ma, curdir, NULL);
+ accessmode(obj, vol, p, &ma, curdir, NULL);
if ((mode & OPENACC_WR) && !(ma.ma_user & AR_UWRITE))
return -1;
if ((mode & OPENACC_RD) && !(ma.ma_user & AR_UREAD))
return -1;
-#endif
+
return 0;
}
/* --------------------- */
-int file_access(struct path *path, int mode)
+int file_access(const AFPObj *obj, struct vol *vol, struct path *path, int mode)
{
struct maccess ma;
- accessmode(current_vol, path->u_name, &ma, curdir, &path->st);
+ accessmode(obj, vol, path->u_name, &ma, curdir, &path->st);
LOG(log_debug, logtype_afpd, "file_access(\"%s\"): mapped user mode: 0x%02x",
path->u_name, ma.ma_user);
(name, dir) with curdir:name == dir, from afp_enumerate
*/
-int getdirparams(const struct vol *vol,
+int getdirparams(const AFPObj *obj,
+ const struct vol *vol,
uint16_t bitmap, struct path *s_path,
struct dir *dir,
char *buf, size_t *buflen )
break;
case DIRPBIT_ACCESS :
- accessmode(vol, upath, &ma, dir , st);
+ accessmode(obj, vol, upath, &ma, dir , st);
*data++ = ma.ma_user;
*data++ = ma.ma_world;
case DIRPBIT_UNIXPR :
/* accessmode may change st_mode with ACLs */
- accessmode(vol, upath, &ma, dir, st);
+ accessmode(obj, vol, upath, &ma, dir, st);
aint = htonl(st->st_uid);
memcpy( data, &aint, sizeof( aint ));
}
/*
- * cf AFP3.0.pdf page 244 for change_mdate and change_parent_mdate logic
- *
* assume path == '\0' eg. it's a directory in canonical form
*/
int setdirparams(struct vol *vol, struct path *path, uint16_t d_bitmap, char *buf )
char *upath;
struct dir *dir;
- int bit, isad = 1;
+ int bit, isad = 0;
int cdate, bdate;
int owner, group;
uint16_t ashort, bshort, oshort;
u_char finder_buf[32];
uint32_t upriv;
mode_t mpriv = 0;
- uint16_t upriv_bit = 0;
+ bool set_upriv = false, set_maccess = false;
+
+ LOG(log_debug, logtype_afpd, "setdirparams(\"%s\", bitmap: %02x)", path->u_name, bitmap);
bit = 0;
upath = path->u_name;
buf += 32;
break;
case DIRPBIT_UID : /* What kind of loser mounts as root? */
- change_parent_mdate = 1;
memcpy( &owner, buf, sizeof(owner));
buf += sizeof( owner );
break;
case DIRPBIT_GID :
- change_parent_mdate = 1;
memcpy( &group, buf, sizeof( group ));
buf += sizeof( group );
break;
case DIRPBIT_ACCESS :
+ set_maccess = true;
change_mdate = 1;
- change_parent_mdate = 1;
ma.ma_user = *buf++;
ma.ma_world = *buf++;
ma.ma_group = *buf++;
ma.ma_owner = *buf++;
mpriv = mtoumode( &ma ) | vol->v_dperm;
- if (dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
- err = set_dir_errors(path, "setdirmode", errno);
- bitmap = 0;
- }
break;
/* Ignore what the client thinks we should do to the
ProDOS information block. Skip over the data and
break;
case DIRPBIT_UNIXPR :
if (vol_unix_priv(vol)) {
+ set_upriv = true;
memcpy( &owner, buf, sizeof(owner)); /* FIXME need to change owner too? */
buf += sizeof( owner );
memcpy( &group, buf, sizeof( group ));
buf += sizeof( group );
change_mdate = 1;
- change_parent_mdate = 1;
memcpy( &upriv, buf, sizeof( upriv ));
buf += sizeof( upriv );
upriv = ntohl (upriv) | vol->v_dperm;
- if (dir_rx_set(upriv)) {
- /* maybe we are trying to set perms back */
- if ( setdirunixmode(vol, upath, upriv) < 0 ) {
- bitmap = 0;
- err = set_dir_errors(path, "setdirunixmode", errno);
- }
- }
- else {
- /* do it later */
- upriv_bit = 1;
- }
break;
}
/* fall through */
bitmap = bitmap>>1;
bit++;
}
- ad_init(&ad, vol);
- if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) {
- /*
- * Check to see what we're trying to set. If it's anything
- * but ACCESS, UID, or GID, give an error. If it's any of those
- * three, we don't need the ad to be open, so just continue.
- *
- * note: we also don't need to worry about mdate. also, be quiet
- * if we're using the noadouble option.
- */
- if (!vol_noadouble(vol) && (d_bitmap &
- ~((1<<DIRPBIT_ACCESS)|(1<<DIRPBIT_UNIXPR)|
- (1<<DIRPBIT_UID)|(1<<DIRPBIT_GID)|
- (1<<DIRPBIT_MDATE)|(1<<DIRPBIT_PDINFO)))) {
+ if (d_bitmap & ((1<<DIRPBIT_ATTR) | (1<<DIRPBIT_CDATE) | (1<<DIRPBIT_BDATE) | (1<<DIRPBIT_FINFO))) {
+ ad_init(&ad, vol);
+ if (ad_open(&ad, upath, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) != 0) {
+ LOG(log_debug, logtype_afpd, "setdirparams(\"%s\", bitmap: %02x): need adouble", path->u_name, d_bitmap);
return AFPERR_ACCESS;
}
-
- isad = 0;
- } else {
- /*
- * Check to see if a create was necessary. If it was, we'll want
- * to set our name, etc.
- */
- if ( (ad_get_MD_flags( &ad ) & O_CREAT)) {
+ if ((ad_get_MD_flags(&ad) & O_CREAT)) {
ad_setname(&ad, cfrombstr(curdir->d_m_name));
}
+ isad = 1;
}
bit = 0;
}
break;
case DIRPBIT_ACCESS :
- if (dir->d_did == DIRDID_ROOT) {
- setdeskmode(mpriv);
- if (!dir_rx_set(mpriv)) {
- /* we can't remove read and search for owner on volume root */
- err = AFPERR_ACCESS;
- goto setdirparam_done;
- }
- }
-
- if (!dir_rx_set(mpriv) && setdirmode( vol, upath, mpriv) < 0 ) {
- err = set_dir_errors(path, "setdirmode", errno);
- goto setdirparam_done;
- }
break;
case DIRPBIT_PDINFO :
if (afp_version >= 30) {
}
break;
case DIRPBIT_UNIXPR :
- if (vol_unix_priv(vol)) {
- if (dir->d_did == DIRDID_ROOT) {
- if (!dir_rx_set(upriv)) {
- /* we can't remove read and search for owner on volume root */
- err = AFPERR_ACCESS;
- goto setdirparam_done;
- }
- setdeskowner( -1, ntohl(group) );
- setdeskmode( upriv );
- }
- if ( setdirowner(vol, upath, -1, ntohl(group) ) < 0 ) {
- err = set_dir_errors(path, "setdirowner", errno);
- goto setdirparam_done;
- }
-
- if ( upriv_bit && setdirunixmode(vol, upath, upriv) < 0 ) {
- err = set_dir_errors(path, "setdirunixmode", errno);
- goto setdirparam_done;
- }
- }
- else {
+ if (!vol_unix_priv(vol)) {
err = AFPERR_BITMAP;
goto setdirparam_done;
}
utime(upath, &ut);
}
- if ( isad ) {
+ if (isad) {
if (path->st_valid && !path->st_errno) {
struct stat *st = &path->st;
-
if (dir && dir->d_pdid) {
ad_setid(&ad, st->st_dev, st->st_ino, dir->d_did, dir->d_pdid, vol->v_stamp);
}
}
- ad_flush(&ad);
+ if (ad_flush(&ad) != 0) {
+ switch (errno) {
+ case EACCES:
+ err = AFPERR_ACCESS;
+ break;
+ default:
+ err = AFPERR_MISC;
+ break;
+ }
+ }
ad_close(&ad, ADFLAGS_HF);
}
+ if (err == AFP_OK) {
+ if (set_maccess == true) {
+ if (dir->d_did == DIRDID_ROOT) {
+ setdeskmode(mpriv);
+ if (!dir_rx_set(mpriv)) {
+ /* we can't remove read and search for owner on volume root */
+ err = AFPERR_ACCESS;
+ goto setprivdone;
+ }
+ }
+ if (setdirunixmode(vol, upath, mpriv) < 0) {
+ LOG(log_info, logtype_afpd, "setdirparams(\"%s\"): setdirunixmode: %s",
+ fullpathname(upath), strerror(errno));
+ err = set_dir_errors(path, "setdirmode", errno);
+ }
+ }
+ if ((set_upriv == true) && vol_unix_priv(vol)) {
+ if (dir->d_did == DIRDID_ROOT) {
+ if (!dir_rx_set(upriv)) {
+ /* we can't remove read and search for owner on volume root */
+ err = AFPERR_ACCESS;
+ goto setprivdone;
+ }
+ setdeskowner(-1, ntohl(group));
+ setdeskmode(upriv);
+ }
+
+ if (setdirowner(vol, upath, -1, ntohl(group)) < 0) {
+ LOG(log_info, logtype_afpd, "setdirparams(\"%s\"): setdirowner: %s",
+ fullpathname(upath), strerror(errno));
+ err = set_dir_errors(path, "setdirowner", errno);
+ goto setprivdone;
+ }
+
+ if (setdirunixmode(vol, upath, upriv) < 0) {
+ LOG(log_info, logtype_afpd, "setdirparams(\"%s\"): setdirunixmode: %s",
+ fullpathname(upath), strerror(errno));
+ err = set_dir_errors(path, "setdirunixmode", errno);
+ }
+ }
+ }
+
+setprivdone:
if (change_parent_mdate && dir->d_did != DIRDID_ROOT
&& gettimeofday(&tv, NULL) == 0) {
if (movecwd(vol, dirlookup(vol, dir->d_pdid)) == 0) {
/* should we reset curdir ?*/
}
}
-
return err;
}
ad_init(&ad, vol);
if (ad_open(&ad, ".", ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_CREATE | ADFLAGS_RDWR, 0777) < 0) {
- if (vol_noadouble(vol))
- goto createdir_done;
return( AFPERR_ACCESS );
}
ad_setname(&ad, s_path->m_name);