Skip to content

Instantly share code, notes, and snippets.

@hiroyuki-sato
Last active December 14, 2015 17:38
Show Gist options
  • Save hiroyuki-sato/30ab25ad72047c1cfe31 to your computer and use it in GitHub Desktop.
Save hiroyuki-sato/30ab25ad72047c1cfe31 to your computer and use it in GitHub Desktop.
/*
3月 05 00:48:03.541107 afpd[15411] {vfs.c:426} (E:Default): acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl) failed: そのようなファイルやディレクトリはありません
3月 05 00:48:03.541162 afpd[15411] {acls.c:1333} (E:Default): vol->vfs->vfs_acl(vol, name, ACL_TYPE_ACCESS, 0, access_acl) failed: そのようなファイルやディレクトリはありません
3月 05 00:48:03.541197 afpd[15411] {acls.c:1730} (W:AFPDaemon): afp_setacl("/home/public/600282_376817112382006_1219774923_n.jpg"): error
ea = sys クライアント側のEAをサーバ側のEAに保存
ea = ad クライアント側のEAをサーバ側の.AppleDoubleディレクトリに保存
ea = auto sysがダメだったらadにフォールバック
ea = none EAをサポートせず
appledouble = ea FinderInfo,TimeStamp,ResourceFork類をサーバ側のEAに保存
appledouble = v2 FinderInfo,TimeStamp,ResourceFork類をサーバ側の.AppleDouble
ディレクトリに保存
*/
//
// etc/afpd/acls.c
//
int afp_setacl(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
{
struct vol *vol;
struct dir *dir;
int ret;
uint32_t did;
uint16_t vid, bitmap;
struct path *s_path;
LOG(log_debug9, logtype_afpd, "afp_setacl: BEGIN");
*rbuflen = 0;
ibuf += 2;
/* .... */
/* Start processing request */
/* Change owner: dont even try */
if (bitmap & kFileSec_UUID) {
LOG(log_note, logtype_afpd, "afp_setacl: change owner request, discarded");
ret = AFPERR_ACCESS;
ibuf += UUID_BINSIZE;
}
/* Change group: certain changes might be allowed, so try it. FIXME: not implemented yet. */
if (bitmap & kFileSec_UUID) {
LOG(log_note, logtype_afpd, "afp_setacl: change group request, not supported");
ret = AFPERR_PARAM;
ibuf += UUID_BINSIZE;
}
/* Remove ACL ? */
if (bitmap & kFileSec_REMOVEACL) {
LOG(log_debug, logtype_afpd, "afp_setacl: Remove ACL request.");
if ((ret = remove_acl(vol, s_path->u_name, S_ISDIR(s_path->st.st_mode))) != AFP_OK)
LOG(log_error, logtype_afpd, "afp_setacl: error from remove_acl");
}
/* Change ACL ? */
if (bitmap & kFileSec_ACL) {
LOG(log_debug, logtype_afpd, "afp_setacl: Change ACL request.");
/* Get no of ACEs the client put on the wire */
uint32_t ace_count;
memcpy(&ace_count, ibuf, sizeof(uint32_t));
ace_count = htonl(ace_count);
ibuf += 8; /* skip ACL flags (see acls.h) */
ret = set_acl(vol,
s_path->u_name,
(bitmap & kFileSec_Inherit),
(darwin_ace_t *)ibuf,
ace_count);
if (ret == 0)
ret = AFP_OK;
else {
LOG(log_warning, logtype_afpd, "afp_setacl(\"%s/%s\"): error",
getcwdpath(), s_path->u_name);
ret = AFPERR_MISC;
}
}
LOG(log_debug9, logtype_afpd, "afp_setacl: END");
return ret;
}
// etc/afpd/acls.c
static int set_acl(const struct vol *vol,
const char *name,
int inherit _U_,
darwin_ace_t *daces,
uint32_t ace_count)
{
EC_INIT;
struct stat st;
acl_t default_acl = NULL;
acl_t access_acl = NULL;
acl_entry_t entry;
acl_tag_t tag;
int entry_id = ACL_FIRST_ENTRY;
/* flags to indicate if the object has a minimal default acl and/or an extended
* default acl.
*/
uint32_t default_acl_flags = 0;
LOG(log_maxdebug, logtype_afpd, "set_acl: BEGIN");
EC_NULL_LOG_ERR(access_acl = acl_get_file(name, ACL_TYPE_ACCESS), AFPERR_MISC);
/* Iterate through acl and remove all extended acl entries. */
while (acl_get_entry(access_acl, entry_id, &entry) == 1) {
entry_id = ACL_NEXT_ENTRY;
EC_ZERO_LOG(acl_get_tag_type(entry, &tag));
if ((tag == ACL_USER) || (tag == ACL_GROUP) || (tag == ACL_MASK)) {
EC_ZERO_LOG_ERR(acl_delete_entry(access_acl, entry), AFPERR_MISC);
}
} /* while */
/* In case we are acting on a directory prepare a default acl. For files default_acl will be NULL.
* If the directory already has a default acl it will be preserved.
*/
EC_ZERO_LOG_ERR(lstat(name, &st), AFPERR_NOOBJ);
if (S_ISDIR(st.st_mode)) {
default_acl = acl_get_file(name, ACL_TYPE_DEFAULT);
if (default_acl) {
/* If default_acl is not empty then the dir has a default acl. */
if (acl_get_entry(default_acl, ACL_FIRST_ENTRY, &entry) == 1)
default_acl_flags = HAS_DEFAULT_ACL;
acl_free(default_acl);
}
default_acl = acl_dup(access_acl);
}
/* adds the clients aces */
EC_ZERO_ERR(map_aces_darwin_to_posix(daces, &default_acl, &access_acl, ace_count, &default_acl_flags), AFPERR_MISC);
/* calcuate ACL mask */
EC_ZERO_LOG_ERR(acl_calc_mask(&access_acl), AFPERR_MISC);
/* is it ok? */
EC_ZERO_LOG_ERR(acl_valid(access_acl), AFPERR_MISC);
/* set it */
EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_ACCESS, access_acl), AFPERR_MISC);
EC_ZERO_LOG_ERR(vol->vfs->vfs_acl(vol, name, ACL_TYPE_ACCESS, 0, access_acl), AFPERR_MISC);
if (default_acl) {
/* If the dir has an extended default acl it's ACL_MASK must be updated.*/
if (default_acl_flags & HAS_EXT_DEFAULT_ACL)
EC_ZERO_LOG_ERR(acl_calc_mask(&default_acl), AFPERR_MISC);
if (default_acl_flags) {
EC_ZERO_LOG_ERR(acl_valid(default_acl), AFPERR_MISC);
EC_ZERO_LOG_ERR(acl_set_file(name, ACL_TYPE_DEFAULT, default_acl), AFPERR_MISC);
EC_ZERO_LOG_ERR(vol->vfs->vfs_acl(vol, name, ACL_TYPE_DEFAULT, 0, default_acl), AFPERR_MISC);
}
}
EC_CLEANUP:
if (access_acl) acl_free(access_acl);
if (default_acl) acl_free(default_acl);
LOG(log_maxdebug, logtype_afpd, "set_acl: END");
EC_EXIT;
}
#endif /* HAVE_POSIX_ACLS */
#ifdef HAVE_POSIX_ACLS
#define VFS_FUNC_ARGS_ACL const struct vol *vol, const char *path, acl_type_t type, int count, acl_t acl
#define VFS_FUNC_VARS_ACL vol, path, type, count, acl
#endif
#ifdef HAVE_POSIX_ACLS
static int RF_posix_acl(VFS_FUNC_ARGS_ACL)
{
EC_INIT;
static char buf[ MAXPATHLEN + 1];
struct stat st;
int len;
if (stat(path, &st) == -1)
EC_FAIL;
if (S_ISDIR(st.st_mode)) {
len = snprintf(buf, MAXPATHLEN, "%s/.AppleDouble",path);
if (len < 0 || len >= MAXPATHLEN)
EC_FAIL;
/* set acl on .AppleDouble dir first */
EC_ZERO_LOG(acl_set_file(buf, type, acl));
if (type == ACL_TYPE_ACCESS)
/* set ACL on ressource fork (".Parent") too */
EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_DIR), type, acl));
} else {
/* set ACL on ressource fork */
EC_ZERO_LOG(acl_set_file(vol->ad_path(path, ADFLAGS_HF), type, acl));
}
EC_CLEANUP:
if (ret != 0)
return AFPERR_MISC;
return AFP_OK;
}
// libatalk/util/netatalk_conf.c
/*
Check if the underlying filesystem supports EAs.
If not, switch to ea:ad.
As we can't check (requires write access) on ro-volumes, we switch ea:auto
volumes that are options:ro to ea:none.
*/
#define EABUFSZ 4
static int do_check_ea_support(const struct vol *vol)
{
int haseas;
const char *eaname = "org.netatalk.has-Extended-Attributes";
const char *eacontent = "yes";
char buf[EABUFSZ];
if (sys_lgetxattr(vol->v_path, eaname, buf, EABUFSZ) != -1)
return 1;
if (vol->v_flags & AFPVOL_RO) {
LOG(log_debug, logtype_afpd, "read-only volume '%s', can't test for EA support, assuming yes", vol->v_localname);
return 1;
}
become_root();
if ((sys_setxattr(vol->v_path, eaname, eacontent, strlen(eacontent) + 1, 0)) == 0) {
haseas = 1;
} else {
LOG(log_warning, logtype_afpd, "volume \"%s\" does not support Extended Attributes or read-only volume",
vol->v_localname);
haseas = 0;
}
unbecome_root();
return haseas;
}
static void check_ea_support(struct vol *vol)
{
int haseas;
haseas = do_check_ea_support(vol);
if (vol->v_vfs_ea == AFPVOL_EA_AUTO) {
if (haseas)
vol->v_vfs_ea = AFPVOL_EA_SYS;
else
vol->v_vfs_ea = AFPVOL_EA_NONE;
}
if (vol->v_adouble == AD_VERSION_EA) {
if (!haseas)
vol->v_adouble = AD_VERSION2;
}
}
// etc/afpd/volume.c
static int getvolparams(const AFPObj *obj, uint16_t bitmap, struct vol *vol, struct stat *st, char *buf, size_t *buflen)
{
/* ...*/
case VOLPBIT_ATTR :
ashort = 0;
/* check for read-only.
* NOTE: we don't actually set the read-only flag unless
* it's passed in that way as it's possible to mount
* a read-write filesystem under a read-only one. */
if ((vol->v_flags & AFPVOL_RO) ||
((utime(vol->v_path, NULL) < 0) && (errno == EROFS))) {
ashort |= VOLPBIT_ATTR_RO;
}
/* prior 2.1 only VOLPBIT_ATTR_RO is defined */
if (obj->afp_version > 20) {
if (vol->v_cdb != NULL && (vol->v_cdb->flags & CNID_FLAG_PERSISTENT))
ashort |= VOLPBIT_ATTR_FILEID;
ashort |= VOLPBIT_ATTR_CATSEARCH;
if (obj->afp_version >= 30) {
ashort |= VOLPBIT_ATTR_UTF8;
if (vol->v_flags & AFPVOL_UNIX_PRIV)
ashort |= VOLPBIT_ATTR_UNIXPRIV;
if (vol->v_flags & AFPVOL_TM)
ashort |= VOLPBIT_ATTR_TM;
if (vol->v_flags & AFPVOL_NONETIDS)
ashort |= VOLPBIT_ATTR_NONETIDS;
if (obj->afp_version >= 32) {
if (vol->v_vfs_ea)
ashort |= VOLPBIT_ATTR_EXT_ATTRS;
if (vol->v_flags & AFPVOL_ACLS)
ashort |= VOLPBIT_ATTR_ACLS;
}
}
}
ashort = htons(ashort);
memcpy(data, &ashort, sizeof( ashort ));
data += sizeof( ashort );
break;
// libatalk/vfs/vfs.c
/* ---------------- */
void initvol_vfs(struct vol *vol)
{
vol->vfs = &vfs_master_funcs;
/* Default adouble stuff */
if (vol->v_adouble == AD_VERSION2) {
vol->vfs_modules[0] = &netatalk_adouble_v2;
vol->ad_path = ad_path;
} else {
vol->vfs_modules[0] = &netatalk_adouble_ea;
#ifdef HAVE_EAFD
vol->ad_path = ad_path_ea;
#else
vol->ad_path = ad_path_osx;
#endif
}
/* Extended Attributes */
if (vol->v_vfs_ea == AFPVOL_EA_SYS) {
LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with native EAs");
vol->vfs_modules[1] = &netatalk_ea_sys;
} else if (vol->v_vfs_ea == AFPVOL_EA_AD) {
LOG(log_debug, logtype_afpd, "initvol_vfs: enabling EA support with adouble files");
vol->vfs_modules[1] = &netatalk_ea_adouble;
} else {
LOG(log_debug, logtype_afpd, "initvol_vfs: volume without EA support");
}
/* ACLs */
#ifdef HAVE_SOLARIS_ACLS
vol->vfs_modules[2] = &netatalk_solaris_acl_adouble;
#endif
#ifdef HAVE_POSIX_ACLS
vol->vfs_modules[2] = &netatalk_posix_acl_adouble;
#endif
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment