X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=etc%2Fafpd%2Fdirectory.c;h=619129e83e4ed20ea7a160b4c2e81459ef56ce92;hb=9f013bf0ce828ff7c61db4f5a404d9029ed82999;hp=17f9c754ebfa498019586f6a31e9a510bbd18bbe;hpb=b501c0b10a93f0740a0f5d3e82b56c9a047e5334;p=netatalk.git diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 17f9c754..619129e8 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.86 2008-08-31 13:25:57 didg Exp $ + * $Id: directory.c,v 1.107 2009-10-14 15:04:00 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -38,12 +38,14 @@ char *strchr (), *strrchr (); #include #include #include -#include +#include +#include #include #include #include #include +#include #include "directory.h" #include "desktop.h" @@ -54,6 +56,11 @@ char *strchr (), *strrchr (); #include "globals.h" #include "unix.h" #include "mangle.h" +#include "hash.h" + +#ifdef HAVE_NFSv4_ACLS +extern void addir_inherit_acl(const struct vol *vol); +#endif struct dir *curdir; int afp_errno; @@ -88,9 +95,7 @@ static struct dir rootpar = { SENTINEL, SENTINEL, NULL, 0, * how exciting. */ struct dir * - dirsearch( vol, did ) - const struct vol *vol; -u_int32_t did; + dirsearch(const struct vol *vol, u_int32_t did) { struct dir *dir; @@ -127,18 +132,6 @@ u_int32_t did; } /* ------------------- */ -#ifdef ATACC -int path_isadir(struct path *o_path) -{ - return o_path->d_dir != NULL; -#if 0 - return o_path->m_name == '\0' || /* we are in a it */ - !o_path->st_valid || /* in cache but we can't chdir in it */ - (!o_path->st_errno && S_ISDIR(o_path->st.st_mode)); /* not in cache an can't chdir */ -#endif -} -#endif - int get_afp_errno(const int param) { if (afp_errno != AFPERR_DID1) @@ -174,9 +167,7 @@ struct dir *dir = NULL; * and we are really bad in this case. */ struct dir * - dirlookup( vol, did ) - const struct vol *vol; -u_int32_t did; + dirlookup( const struct vol *vol, u_int32_t did) { struct dir *ret; char *upath; @@ -290,9 +281,7 @@ static void dirchildremove(struct dir *a,struct dir *b) /* --------------------------- */ /* rotate the tree to the left */ -static void dir_leftrotate(vol, dir) -struct vol *vol; -struct dir *dir; +static void dir_leftrotate(struct vol *vol, struct dir *dir) { struct dir *right = dir->d_right; @@ -321,9 +310,7 @@ struct dir *dir; /* rotate the tree to the right */ -static void dir_rightrotate(vol, dir) -struct vol *vol; -struct dir *dir; +static void dir_rightrotate(struct vol *vol, struct dir *dir) { struct dir *left = dir->d_left; @@ -351,9 +338,7 @@ struct dir *dir; #if 0 /* recolor after a removal */ -static struct dir *dir_rmrecolor(vol, dir) - struct vol *vol; -struct dir *dir; +static struct dir *dir_rmrecolor(struct vol *vol, struct dir *dir) { struct dir *leaf; @@ -439,9 +424,8 @@ static void dir_hash_del(const struct vol *vol, struct dir *dir) /* remove the node from the tree. this is just like insertion, but * different. actually, it has to worry about a bunch of things that * insertion doesn't care about. */ -static void dir_remove( vol, dir ) -struct vol *vol; -struct dir *dir; + +static void dir_remove( const struct vol *vol _U_, struct dir *dir) { #ifdef REMOVE_NODES struct ofork *of, *last; @@ -558,9 +542,7 @@ struct dir *dir; * process. It's fixable within afpd if fnctl_lock, doable with smb and * next to impossible for nfs and local filesystem access. */ -static void dir_invalidate( vol, dir ) -const struct vol *vol; -struct dir *dir; +static void dir_invalidate( const struct vol *vol, struct dir *dir) { if (curdir == dir) { /* v_root can't be deleted */ @@ -574,9 +556,7 @@ struct dir *dir; } /* ------------------------------------ */ -static struct dir *dir_insert(vol, dir) - const struct vol *vol; -struct dir *dir; +static struct dir *dir_insert(const struct vol *vol, struct dir *dir) { struct dir *pdir; @@ -601,15 +581,95 @@ struct dir *dir; return pdir; } +#define ENUMVETO "./../Network Trash Folder/TheVolumeSettingsFolder/TheFindByContentFolder/:2eDS_Store/Contents/Desktop Folder/Trash/Benutzer/" + +int +caseenumerate(const struct vol *vol, struct path *path, struct dir *dir) +{ + DIR *dp; + struct dirent *de; + int ret; + static u_int32_t did = 0; + static char cname[MAXPATHLEN]; + static char lname[MAXPATHLEN]; + ucs2_t u2_path[MAXPATHLEN]; + ucs2_t u2_dename[MAXPATHLEN]; + char *tmp, *savepath; + + if (!(vol->v_flags & AFPVOL_CASEINSEN)) + return -1; + + if (veto_file(ENUMVETO, path->u_name)) + return -1; + + savepath = path->u_name; + + /* very simple cache */ + if ( dir->d_did == did && strcmp(lname, path->u_name) == 0) { + path->u_name = cname; + path->d_dir = NULL; + if (of_stat( path ) == 0 ) { + return 0; + } + /* something changed, we cannot stat ... */ + did = 0; + } + + if (NULL == ( dp = opendir( "." )) ) { + LOG(log_debug, logtype_afpd, "caseenumerate: opendir failed: %s", dir->d_u_name); + return -1; + } + + + /* LOG(log_debug, logtype_afpd, "caseenumerate: for %s", path->u_name); */ + if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, path->u_name, strlen(path->u_name), u2_path, sizeof(u2_path)) ) + LOG(log_debug, logtype_afpd, "caseenumerate: conversion failed for %s", path->u_name); + + /*LOG(log_debug, logtype_afpd, "caseenumerate: dir: %s, path: %s", dir->d_u_name, path->u_name); */ + ret = -1; + for ( de = readdir( dp ); de != NULL; de = readdir( dp )) { + if (NULL == check_dirent(vol, de->d_name)) + continue; + + if ((size_t) -1 == convert_string(vol->v_volcharset, CH_UCS2, de->d_name, strlen(de->d_name), u2_dename, sizeof(u2_dename)) ) + continue; + + if (strcasecmp_w( u2_path, u2_dename) == 0) { + tmp = path->u_name; + strlcpy(cname, de->d_name, sizeof(cname)); + path->u_name = cname; + path->d_dir = NULL; + if (of_stat( path ) == 0 ) { + LOG(log_debug, logtype_afpd, "caseenumerate: using dir: %s, path: %s", de->d_name, path->u_name); + strlcpy(lname, tmp, sizeof(lname)); + did = dir->d_did; + ret = 0; + break; + } + else + path->u_name = tmp; + } + + } + closedir(dp); + + if (ret) { + /* invalidate cache */ + cname[0] = 0; + did = 0; + path->u_name = savepath; + } + /* LOG(log_debug, logtype_afpd, "caseenumerate: path on ret: %s", path->u_name); */ + return ret; +} + + /* * attempt to extend the current dir. tree to include path * as a side-effect, movecwd to that point and return the new dir */ static struct dir * - extenddir( vol, dir, path ) -struct vol *vol; -struct dir *dir; -struct path *path; + extenddir(struct vol *vol, struct dir *dir, struct path *path) { path->d_dir = NULL; @@ -617,10 +677,22 @@ struct path *path; afp_errno = AFPERR_PARAM; return NULL; } - if (of_stat( path ) != 0 ) { + + if (check_name(vol, path->u_name)) { + /* the name is illegal */ + LOG(log_info, logtype_afpd, "extenddir: illegal path: '%s'", path->u_name); + path->u_name = NULL; + afp_errno = AFPERR_PARAM; return NULL; } + if (of_stat( path ) != 0 ) { + if (!(vol->v_flags & AFPVOL_CASEINSEN)) + return NULL; + else if(caseenumerate(vol, path, dir) != 0) + return(NULL); + } + if (!S_ISDIR(path->st.st_mode)) { return( NULL ); } @@ -638,30 +710,6 @@ struct path *path; return( dir ); } -/* ------------------- - system rmdir with afp error code. - ENOENT is not an error. - */ -int netatalk_rmdir(const char *name) -{ - if (rmdir(name) < 0) { - switch ( errno ) { - case ENOENT : - break; - case ENOTEMPTY : - return AFPERR_DIRNEMPT; - case EPERM: - case EACCES : - return AFPERR_ACCESS; - case EROFS: - return AFPERR_VLOCK; - default : - return AFPERR_PARAM; - } - } - return AFP_OK; -} - /* ------------------------- appledouble mkdir afp error code. */ @@ -688,28 +736,6 @@ static int netatalk_mkdir(const char *name) return AFP_OK; } -/* ------------------- - system unlink with afp error code. - ENOENT is not an error. - */ -int netatalk_unlink(const char *name) -{ - if (unlink(name) < 0) { - switch (errno) { - case ENOENT : - break; - case EROFS: - return AFPERR_VLOCK; - case EPERM: - case EACCES : - return AFPERR_ACCESS; - default : - return AFPERR_PARAM; - } - } - return AFP_OK; -} - /* ------------------- */ static int deletedir(char *dir) { @@ -844,9 +870,7 @@ copydir_done: /* --- public functions follow --- */ /* NOTE: we start off with at least one node (the root directory). */ -static struct dir *dirinsert( vol, dir ) - struct vol *vol; -struct dir *dir; +static struct dir *dirinsert(struct vol *vol, struct dir *dir) { struct dir *node; @@ -904,10 +928,7 @@ struct dir *dir; /* ---------------------------- */ struct dir * - adddir( vol, dir, path) -struct vol *vol; -struct dir *dir; -struct path *path; + adddir(struct vol *vol, struct dir *dir, struct path *path) { struct dir *cdir, *edir; int upathlen; @@ -934,8 +955,8 @@ struct path *path; return NULL; } if ((size_t)-1 == convert_string_allocate((utf8_encoding())?CH_UTF8_MAC:vol->v_maccharset, CH_UCS2, path->m_name, strlen(path->m_name), &cdir->d_m_name_ucs2)) { - LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name); - cdir->d_m_name_ucs2 = NULL; + LOG(log_error, logtype_afpd, "Couldn't set UCS2 name for %s", name); + cdir->d_m_name_ucs2 = NULL; } cdir->d_did = id; @@ -991,8 +1012,7 @@ void dirfreename(struct dir *dir) free(dir->d_m_name); } -void dirfree( dir ) -struct dir *dir; +void dirfree(struct dir *dir) { if (!dir || (dir == SENTINEL)) return; @@ -1164,12 +1184,9 @@ static struct path *invalidate (const struct vol *vol, struct dir *dir, struct p */ struct path * -cname( vol, dir, cpath ) -const struct vol *vol; -struct dir *dir; -char **cpath; +cname(const struct vol *vol, struct dir *dir, char **cpath) { - struct dir *cdir; + struct dir *cdir, *scdir=NULL; static char path[ MAXPATHLEN + 1]; static struct path ret; @@ -1181,7 +1198,7 @@ char **cpath; int size = 0; char sep; int toUTF8 = 0; - + data = *cpath; afp_errno = AFPERR_NOOBJ; memset(&ret, 0, sizeof(ret)); @@ -1273,12 +1290,24 @@ char **cpath; if (toUTF8) { static char temp[ MAXPATHLEN + 1]; - /* not an UTF8 name */ - if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) { - afp_errno = AFPERR_PARAM; - return( NULL ); + if (dir->d_did == DIRDID_ROOT_PARENT) { + /* + With uft8 volume name is utf8-mac, but requested path may be a mangled longname. See #2611981. + So we compare it with the longname from the current volume and if they match + we overwrite the requested path with the utf8 volume name so that the following + strcmp can match. + */ + ucs2_to_charset(vol->v_maccharset, vol->v_macname, temp, AFPVOL_MACNAMELEN + 1); + if (strcasecmp( path, temp) == 0) + ucs2_to_charset(CH_UTF8_MAC, vol->v_u8mname, path, AFPVOL_U8MNAMELEN); + } else { + /* toUTF8 */ + if (mtoUTF8(vol, path, strlen(path), temp, MAXPATHLEN) == (size_t)-1) { + afp_errno = AFPERR_PARAM; + return( NULL ); + } + strcpy(path, temp); } - strcpy(path, temp); } /* check for OS X mangled filename :( */ @@ -1301,19 +1330,50 @@ char **cpath; } } if ( !extend ) { - if (dir->d_did == DIRDID_ROOT_PARENT) { - /* root parent has only one child and d_m_name is *NOT* utm (d_u_name) - * d_m_name is the Mac volume name - * d_u_name is the volume unix directory name - * - */ - cdir = NULL; - if (!strcmp(vol->v_dir->d_m_name, ret.m_name)) { - cdir = vol->v_dir; + ucs2_t *tmpname; + cdir = dir->d_child; + scdir = NULL; + if ( cdir && (vol->v_flags & AFPVOL_CASEINSEN) && + (size_t)-1 != convert_string_allocate(((ret.m_type == 3)?CH_UTF8_MAC:vol->v_maccharset), + CH_UCS2, path, strlen(path), (char **)&tmpname) ) + { + while (cdir) { + if (!cdir->d_m_name_ucs2) { + LOG(log_error, logtype_afpd, "cname: no UCS2 name for %s (did %u)!!!", cdir->d_m_name, ntohl(cdir->d_did) ); + /* this shouldn't happen !!!! */ + goto noucsfallback; + } + + if ( strcmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) { + break; + } + if ( strcasecmp_w( cdir->d_m_name_ucs2, tmpname ) == 0 ) { + scdir = cdir; + } + cdir = (cdir == dir->d_child->d_prev) ? NULL :cdir->d_next; } + free(tmpname); } else { - cdir = dirsearch_byname(vol, dir, ret.u_name); +noucsfallback: + if (dir->d_did == DIRDID_ROOT_PARENT) { + /* + root parent (did 1) has one child: the volume. Requests for did=1 with some + must check against the volume name. + */ + if (!strcmp(vol->v_dir->d_m_name, ret.m_name)) + cdir = vol->v_dir; + else + cdir = NULL; + } + else { + cdir = dirsearch_byname(vol, dir, ret.u_name); + } + } + + if (cdir == NULL && scdir != NULL) { + cdir = scdir; + /* LOG(log_debug, logtype_afpd, "cname: using casediff for %s, (%s = %s)", fullpathname(cdir->d_u_name), cdir->d_m_name, path ); */ } if ( cdir == NULL ) { @@ -1344,7 +1404,7 @@ char **cpath; if ( cdir == NULL ) { - if ( len > 0) { + if ( len > 0 || !ret.u_name ) { return NULL; } @@ -1358,9 +1418,7 @@ char **cpath; /* * Move curdir to dir, with a possible chdir() */ -int movecwd( vol, dir) -const struct vol *vol; -struct dir *dir; +int movecwd(const struct vol *vol, struct dir *dir) { char path[MAXPATHLEN + 1]; struct dir *d; @@ -1739,10 +1797,7 @@ int path_error(struct path *path, int error) } /* ----------------------------- */ -int afp_setdirparams(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf _U_; -int ibuflen _U_, *rbuflen; +int afp_setdirparams(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen) { struct vol *vol; struct dir *dir; @@ -1838,7 +1893,7 @@ int setdirparams(const struct vol *vol, char *upath; struct dir *dir; - int bit, aint, isad = 1; + int bit, isad = 1; int cdate, bdate; int owner, group; u_int16_t ashort, bshort; @@ -1903,7 +1958,7 @@ int setdirparams(const struct vol *vol, ma.ma_world = *buf++; ma.ma_group = *buf++; ma.ma_owner = *buf++; - mpriv = mtoumode( &ma ) | vol->v_perm; + 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; @@ -1932,7 +1987,7 @@ int setdirparams(const struct vol *vol, change_parent_mdate = 1; memcpy( &upriv, buf, sizeof( upriv )); buf += sizeof( upriv ); - upriv = ntohl (upriv) | vol->v_perm; + 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 ) { @@ -2022,6 +2077,10 @@ int setdirparams(const struct vol *vol, break; case DIRPBIT_FINFO : if (isad) { + /* Fixes #2802236 */ + u_int16_t *fflags = (u_int16_t *)(finder_buf + FINDERINFO_FRFLAGOFF); + *fflags &= htons(~FINDERINFO_ISHARED); + /* #2802236 end */ if ( dir->d_did == DIRDID_ROOT ) { /* * Alright, we admit it, this is *really* sick! @@ -2156,13 +2215,11 @@ setdirparam_done: return err; } - -int afp_syncdir(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_syncdir(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf _U_, int *rbuflen) { +#ifdef HAVE_DIRFD DIR *dp; +#endif int dfd; struct vol *vol; struct dir *dir; @@ -2180,33 +2237,75 @@ int ibuflen _U_, *rbuflen; memcpy( &did, ibuf, sizeof( did )); ibuf += sizeof( did ); - if (NULL == ( dir = dirlookup( vol, did )) ) { - return afp_errno; /* was AFPERR_NOOBJ */ - } - if (NULL == ( dp = opendir( "." )) ) { - switch( errno ) { - case ENOENT : - return( AFPERR_NOOBJ ); - case EACCES : + /* + * Here's the deal: + * if it's CNID 2 our only choice to meet the specs is call sync. + * For any other CNID just sync that dir. To my knowledge the + * intended use of FPSyncDir is to sync the volume so all we're + * ever going to see here is probably CNID 2. Anyway, we' prepared. + */ + + if ( ntohl(did) == 2 ) { + sync(); + } else { + if (NULL == ( dir = dirlookup( vol, did )) ) { + return afp_errno; /* was AFPERR_NOOBJ */ + } + + if (movecwd( vol, dir ) < 0 ) + return ( AFPERR_NOOBJ ); + + /* + * Assuming only OSens that have dirfd also may require fsyncing directories + * in order to flush metadata e.g. Linux. + */ + +#ifdef HAVE_DIRFD + if (NULL == ( dp = opendir( "." )) ) { + switch( errno ) { + case ENOENT : + return( AFPERR_NOOBJ ); + case EACCES : return( AFPERR_ACCESS ); - default : - return( AFPERR_PARAM ); + default : + return( AFPERR_PARAM ); + } } + + LOG(log_debug, logtype_afpd, "afp_syncdir: dir: '%s'", dir->d_u_name); + + dfd = dirfd( dp ); + if ( fsync ( dfd ) < 0 ) + LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s", + dir->d_u_name, strerror(errno) ); + closedir(dp); /* closes dfd too */ +#endif + + if ( -1 == (dfd = open(vol->ad_path(".", ADFLAGS_DIR), O_RDWR))) { + switch( errno ) { + case ENOENT: + return( AFPERR_NOOBJ ); + case EACCES: + return( AFPERR_ACCESS ); + default: + return( AFPERR_PARAM ); + } + } + + LOG(log_debug, logtype_afpd, "afp_syncdir: ad-file: '%s'", + vol->ad_path(".", ADFLAGS_DIR) ); + + if ( fsync(dfd) < 0 ) + LOG(log_error, logtype_afpd, "afp_syncdir(%s): %s", + vol->ad_path(dir->d_u_name, ADFLAGS_DIR), strerror(errno) ); + close(dfd); } - dfd = dirfd( dp ); - if ( fsync ( dfd ) < 0 ) { - LOG(log_error, logtype_afpd, "syncdir(%s): ddir(%d) %s", dir->d_u_name, dfd, strerror(errno) ); - } - return ( AFP_OK ); } -int afp_createdir(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_createdir(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf, int *rbuflen) { struct adouble ad; struct vol *vol; @@ -2247,9 +2346,6 @@ int ibuflen _U_, *rbuflen; return AFPERR_EXIST; upath = s_path->u_name; - if (0 != (err = check_name(vol, upath))) { - return err; - } if (AFP_OK != (err = netatalk_mkdir( upath))) { return err; @@ -2280,6 +2376,11 @@ int ibuflen _U_, *rbuflen; ad_close_metadata( &ad); createdir_done: +#ifdef HAVE_NFSv4_ACLS + /* FIXME: are we really inside the created dir? */ + addir_inherit_acl(vol); +#endif + memcpy( rbuf, &dir->d_did, sizeof( u_int32_t )); *rbuflen = sizeof( u_int32_t ); setvoltime(obj, vol ); @@ -2292,10 +2393,10 @@ createdir_done: * newparent curdir * */ -int renamedir(vol, src, dst, dir, newparent, newname) -const struct vol *vol; -char *src, *dst, *newname; -struct dir *dir, *newparent; +int renamedir(const struct vol *vol, char *src, char *dst, + struct dir *dir, + struct dir *newparent, + char *newname) { struct adouble ad; struct dir *parent; @@ -2329,7 +2430,7 @@ struct dir *dir, *newparent; } } - vol->vfs->rf_renamedir(vol, src, dst); + vol->vfs->vfs_renamedir(vol, src, dst); len = strlen( newname ); /* rename() succeeded so we need to update our tree even if we can't open @@ -2392,8 +2493,7 @@ struct dir *dir, *newparent; } /* delete an empty directory */ -int deletecurdir( vol) -const struct vol *vol; +int deletecurdir(const struct vol *vol) { struct dirent *de; struct stat st; @@ -2418,7 +2518,7 @@ const struct vol *vol; return AFPERR_OLOCK; } } - err = vol->vfs->rf_deletecurdir(vol); + err = vol->vfs->vfs_deletecurdir(vol); if (err) { return err; } @@ -2465,10 +2565,7 @@ delete_done: return err; } -int afp_mapid(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_mapid(AFPObj *obj, char *ibuf, int ibuflen _U_, char *rbuf, int *rbuflen) { struct passwd *pw; struct group *gr; @@ -2476,49 +2573,92 @@ int ibuflen _U_, *rbuflen; u_int32_t id; int len, sfunc; int utf8 = 0; - + uuidtype_t type; + ibuf++; sfunc = (unsigned char) *ibuf++; - memcpy( &id, ibuf, sizeof( id )); - - id = ntohl(id); *rbuflen = 0; - if (sfunc == 3 || sfunc == 4) { + + if (sfunc >= 3 && sfunc <= 6) { if (afp_version < 30) { return( AFPERR_PARAM ); } utf8 = 1; } - if ( id != 0 ) { + switch ( sfunc ) { case 1 : case 3 :/* unicode */ + memcpy( &id, ibuf, sizeof( id )); + id = ntohl(id); + if ( id != 0 ) { if (( pw = getpwuid( id )) == NULL ) { return( AFPERR_NOITEM ); } len = convert_string_allocate( obj->options.unixcharset, ((!utf8)?obj->options.maccharset:CH_UTF8_MAC), pw->pw_name, strlen(pw->pw_name), &name); + } else { + len = 0; + name = NULL; + } break; - case 2 : case 4 : /* unicode */ + memcpy( &id, ibuf, sizeof( id )); + id = ntohl(id); + if ( id != 0 ) { if (NULL == ( gr = (struct group *)getgrgid( id ))) { return( AFPERR_NOITEM ); } len = convert_string_allocate( obj->options.unixcharset, (!utf8)?obj->options.maccharset:CH_UTF8_MAC, gr->gr_name, strlen(gr->gr_name), &name); + } else { + len = 0; + name = NULL; + } break; - +#ifdef HAVE_NFSv4_ACLS + case 5 : /* UUID -> username */ + case 6 : /* UUID -> groupname */ + if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID )) + return AFPERR_PARAM; + LOG(log_debug, logtype_afpd, "afp_mapid: valid UUID request"); + len = getnamefromuuid( ibuf, &name, &type); + if (len != 0) /* its a error code, not len */ + return AFPERR_NOITEM; + if (type == UUID_USER) { + if (( pw = getpwnam( name )) == NULL ) + return( AFPERR_NOITEM ); + LOG(log_debug, logtype_afpd, "afp_mapid: name:%s -> uid:%d", name, pw->pw_uid); + id = htonl(UUID_USER); + memcpy( rbuf, &id, sizeof( id )); + id = htonl( pw->pw_uid); + rbuf += sizeof( id ); + memcpy( rbuf, &id, sizeof( id )); + rbuf += sizeof( id ); + *rbuflen = 2 * sizeof( id ); + } else { /* type == UUID_GROUP */ + if (( gr = getgrnam( name )) == NULL ) + return( AFPERR_NOITEM ); + LOG(log_debug, logtype_afpd, "afp_mapid: group:%s -> gid:%d", name, gr->gr_gid); + id = htonl(UUID_GROUP); + memcpy( rbuf, &id, sizeof( id )); + rbuf += sizeof( id ); + id = htonl( gr->gr_gid); + memcpy( rbuf, &id, sizeof( id )); + rbuf += sizeof( id ); + *rbuflen = 2 * sizeof( id ); + } + break; +#endif default : return( AFPERR_PARAM ); } - len = strlen( name ); - } else { - len = 0; - name = NULL; - } + if (name) + len = strlen( name ); + if (utf8) { u_int16_t tp = htons(len); memcpy(rbuf, &tp, sizeof(tp)); @@ -2538,10 +2678,7 @@ int ibuflen _U_, *rbuflen; return( AFP_OK ); } -int afp_mapname(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_mapname(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int *rbuflen) { struct passwd *pw; struct group *gr; @@ -2552,6 +2689,7 @@ int ibuflen _U_, *rbuflen; ibuf++; sfunc = (unsigned char) *ibuf++; *rbuflen = 0; + LOG(log_debug, logtype_afpd, "afp_mapname: sfunc: %d, afp_version: %d", sfunc, afp_version); switch ( sfunc ) { case 1 : case 2 : /* unicode */ @@ -2561,18 +2699,31 @@ int ibuflen _U_, *rbuflen; memcpy(&ulen, ibuf, sizeof(ulen)); len = ntohs(ulen); ibuf += 2; + LOG(log_debug, logtype_afpd, "afp_mapname: alive"); break; case 3 : case 4 : len = (unsigned char) *ibuf++; break; +#ifdef HAVE_NFSv4_ACLS + case 5 : /* username -> UUID */ + case 6 : /* groupname -> UUID */ + if ((afp_version < 32) || !(obj->options.flags & OPTION_UUID )) + return AFPERR_PARAM; + memcpy(&ulen, ibuf, sizeof(ulen)); + len = ntohs(ulen); + ibuf += 2; + break; +#endif default : return( AFPERR_PARAM ); } ibuf[ len ] = '\0'; - if ( len != 0 ) { + if ( len == 0 ) + return AFPERR_PARAM; + else { switch ( sfunc ) { case 1 : /* unicode */ case 3 : @@ -2580,32 +2731,46 @@ int ibuflen _U_, *rbuflen; return( AFPERR_NOITEM ); } id = pw->pw_uid; + id = htonl(id); + memcpy( rbuf, &id, sizeof( id )); + *rbuflen = sizeof( id ); break; case 2 : /* unicode */ case 4 : + LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s",ibuf); if (NULL == ( gr = (struct group *)getgrnam( ibuf ))) { return( AFPERR_NOITEM ); } id = gr->gr_gid; - break; - } - } else { - id = 0; - } + LOG(log_debug, logtype_afpd, "afp_mapname: gettgrnam for name: %s -> id: %d",ibuf, id); id = htonl(id); memcpy( rbuf, &id, sizeof( id )); *rbuflen = sizeof( id ); + break; +#ifdef HAVE_NFSv4_ACLS + case 5 : /* username -> UUID */ + LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf); + if (0 != getuuidfromname(ibuf, UUID_USER, rbuf)) + return AFPERR_NOITEM; + *rbuflen = UUID_BINSIZE; + break; + case 6 : /* groupname -> UUID */ + LOG(log_debug, logtype_afpd, "afp_mapname: name: %s",ibuf); + if (0 != getuuidfromname(ibuf, UUID_GROUP, rbuf)) + return AFPERR_NOITEM; + *rbuflen = UUID_BINSIZE; + break; +#endif + } + } return( AFP_OK ); } /* ------------------------------------ variable DID support */ -int afp_closedir(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf _U_, *rbuf _U_; -int ibuflen _U_, *rbuflen; +int afp_closedir(AFPObj *obj _U_, char *ibuf _U_, int ibuflen _U_, char *rbuf _U_, int *rbuflen) { #if 0 struct vol *vol; @@ -2641,10 +2806,7 @@ int ibuflen _U_, *rbuflen; /* did creation gets done automatically * there's a pb again with case but move it to cname */ -int afp_opendir(obj, ibuf, ibuflen, rbuf, rbuflen ) -AFPObj *obj _U_; -char *ibuf, *rbuf; -int ibuflen _U_, *rbuflen; +int afp_opendir(AFPObj *obj _U_, char *ibuf, int ibuflen _U_, char *rbuf, int *rbuflen) { struct vol *vol; struct dir *parentdir;