]> arthur.barton.de Git - netatalk.git/commitdiff
Merge branch-2-1
authorFrank Lahm <franklahm@googlemail.com>
Fri, 29 Oct 2010 08:04:52 +0000 (10:04 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Fri, 29 Oct 2010 08:04:52 +0000 (10:04 +0200)
1  2 
NEWS
etc/afpd/filedir.c

diff --combined NEWS
index 7a675836597be7b71a3e0cbc414b361b8de7da46,0378052c0d22e56ba2987d74e7fd5acc72891355..256aae2d24a1994f94298167d687bb51f5535857
--- 1/NEWS
--- 2/NEWS
+++ b/NEWS
@@@ -1,29 -1,9 +1,30 @@@
 +Changes in 2.2
 +==============
 +
 +* NEW: ad utility: ad cp
 +* NEW: ad utility: ad rm
 +* NEW: ad utility: ad mv
 +* NEW: afpd: dynamic directoy and CNID cache
 +* NEW: afpd: POSIX 1e ACL support
 +* NEW: afpd: automagic Zeroconf registration with avahi, registering both
 +       the service _afpovertcp._tcp and TimeMachine volumes with _adisk._tcp.
 +* UPD: afpd: ACLs usable (though not visible on the client side) without common
 +       directory service, by mapping ACLs to UARight
 +* UPD: afpd: performance improvements for ACL access calculations
 +* UPD: AppleTalk ist disabled by default at configuration time. If needed
 +       use configure switch --enable-ddp.
 +* FIX: afpd: Solaris 10 compatibilty fix: don't use SO_SNDTIMEO/SO_RCVTIMEO,
 +       use non-blocking IO and select instead.
 +* FIX: cnid_dbd: Solaris 10 compatibilty fix: don't use SO_SNDTIMEO/SO_RCVTIMEO,
 +       use non-blocking IO and select instead.
 +* REM: afile/achfile/apple_cm/apple_mv/apple_rm: use ad
 +
  Changes in 2.1.5
  ================
  * UPD: afpd: support newlines in -loginmesg with \n escaping syntax
  * UPD: afpd: support for changed chmod semantics on ZFS with ACLs
         in onnv145+
+ * FIX: afpd: fix leaking ressource when moving objects on the server
  
  Changes in 2.1.4
  ================
diff --combined etc/afpd/filedir.c
index b537001309d6b69c3ab69f84cb16e1f52d29e155,2a862abeea7ecd2a6556fe267da5f41f9e29a70b..c5fbd10595964cef45cf91706f020fefa1ba607d
@@@ -37,12 -37,9 +37,12 @@@ char *strchr (), *strrchr ()
  #include <atalk/cnid.h>
  #include <atalk/logger.h>
  #include <atalk/unix.h>
 +#include <atalk/bstrlib.h>
 +#include <atalk/bstradd.h>
  #include <atalk/acl.h>
  
  #include "directory.h"
 +#include "dircache.h"
  #include "desktop.h"
  #include "volume.h"
  #include "fork.h"
  #ifdef DROPKLUDGE
  int matchfile2dirperms(
  /* Since it's kinda' big; I decided against an
 -inline function */
 -    char      *upath,
 +   inline function */
 +    char    *upath,
      struct vol  *vol,
 -    int               did)
 +    int     did)
  /* The below code changes the way file ownership is determined in the name of
 -fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
 -more information */
 +   fixing dropboxes.  It has known security problem.  See the netatalk FAQ for
 +   more information */
  {
 -    struct stat       st, sb;
 -    struct dir        *dir;
 -    char      *adpath;
 +    struct stat st, sb;
 +    struct dir  *dir;
 +    char    *adpath;
      uid_t       uid;
      int         ret = AFP_OK;
  #ifdef DEBUG
      LOG(log_debug9, logtype_afpd, "begin matchfile2dirperms:");
 -#endif 
 +#endif
  
      if (stat(upath, &st ) < 0) {
          LOG(log_error, logtype_afpd, "Could not stat %s: %s", upath, strerror(errno));
                      adpath, strerror(errno));
                  ret = AFPERR_ACCESS;
              }
 -            seteuid(uid); 
 +            seteuid(uid);
          }
      } /* end else if stat success */
  
  
  int afp_getfildirparams(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen)
  {
 -    struct stat               *st;
 -    struct vol                *vol;
 -    struct dir                *dir;
 +    struct stat     *st;
 +    struct vol      *vol;
 +    struct dir      *dir;
      u_int32_t           did;
 -    int                       ret;
 -    size_t            buflen;
 -    u_int16_t         fbitmap, dbitmap, vid;
 +    int         ret;
 +    size_t      buflen;
 +    u_int16_t       fbitmap, dbitmap, vid;
      struct path         *s_path;
  
      *rbuflen = 0;
      if (NULL == ( vol = getvolbyvid( vid )) ) {
          /* was AFPERR_PARAM but it helps OS 10.3 when a volume has been removed
           * from the list.
 -         */ 
 +         */
          return( AFPERR_ACCESS );
      }
  
      ibuf += sizeof( dbitmap );
  
      if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
 -        return get_afp_errno(AFPERR_NOOBJ); 
 +        return get_afp_errno(AFPERR_NOOBJ);
      }
  
 -    LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, name:'%s', f/d:%04x/%04x) {cwd: %s}",
 -        ntohs(vid), ntohl(dir->d_did), s_path->u_name, fbitmap, dbitmap, getcwdpath());
 +    LOG(log_debug, logtype_afpd, "getfildirparams(vid:%u, did:%u, f/d:%04x/%04x) {cwdid:%u, cwd: %s, name:'%s'}",
 +        ntohs(vid), ntohl(dir->d_did), fbitmap, dbitmap,
 +        ntohl(curdir->d_did), cfrombstr(curdir->d_fullpath), s_path->u_name);
  
      st   = &s_path->st;
      if (!s_path->st_valid) {
          of_statdir(vol, s_path);
      }
      if ( s_path->st_errno != 0 ) {
 -        return( AFPERR_NOOBJ );
 +        if (afp_errno != AFPERR_ACCESS) {
 +            return( AFPERR_NOOBJ );
 +        }
      }
  
  
      if (S_ISDIR(st->st_mode)) {
          if (dbitmap) {
              dir = s_path->d_dir;
 -            if (!dir) 
 +            if (!dir)
                  return AFPERR_NOOBJ;
  
              ret = getdirparams(vol, dbitmap, s_path, dir,
 -                                 rbuf + 3 * sizeof( u_int16_t ), &buflen );
 +                               rbuf + 3 * sizeof( u_int16_t ), &buflen );
              if (ret != AFP_OK )
                  return( ret );
          }
          /* this is a directory */
          *(rbuf + 2 * sizeof( u_int16_t )) = (char) FILDIRBIT_ISDIR;
      } else {
 -        if (fbitmap && AFP_OK != (ret = getfilparams(vol, fbitmap, s_path, curdir, 
 -                                            rbuf + 3 * sizeof( u_int16_t ), &buflen )) ) {
 +        if (fbitmap && AFP_OK != (ret = getfilparams(vol, fbitmap, s_path, curdir,
 +                                                     rbuf + 3 * sizeof( u_int16_t ), &buflen )) ) {
              return( ret );
          }
          /* this is a file */
  
  int afp_setfildirparams(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
  {
 -    struct stat       *st;
 -    struct vol        *vol;
 -    struct dir        *dir;
 +    struct stat *st;
 +    struct vol  *vol;
 +    struct dir  *dir;
      struct path *path;
 -    u_int16_t vid, bitmap;
 -    int               did, rc;
 +    u_int16_t   vid, bitmap;
 +    int     did, rc;
  
      *rbuflen = 0;
      ibuf += 2;
      ibuf += sizeof( did);
  
      if (NULL == ( dir = dirlookup( vol, did )) ) {
 -      return afp_errno;    
 +        return afp_errno;
      }
  
      memcpy( &bitmap, ibuf, sizeof( bitmap ));
      ibuf += sizeof( bitmap );
  
      if (NULL == ( path = cname( vol, dir, &ibuf ))) {
 -        return get_afp_errno(AFPERR_NOOBJ); 
 +        return get_afp_errno(AFPERR_NOOBJ);
      }
  
      st   = &path->st;
      }
  
      if ( path->st_errno != 0 ) {
 -        return( AFPERR_NOOBJ );
 +        if (afp_errno != AFPERR_ACCESS)
 +            return( AFPERR_NOOBJ );
      }
      /*
       * If ibuf is odd, make it even.
      return( rc );
  }
  
 -/* -------------------------------------------- 
 +/* --------------------------------------------
     Factorise some checks on a pathname
  */
  int check_name(const struct vol *vol, char *name)
@@@ -338,7 -331,7 +338,7 @@@ static int moveandrename(const struct v
      struct ofork      *opened = NULL;
      struct path     path;
      cnid_t          id;
-     int             cwd_fd;
+     int             cwd_fd = -1;
  
      ad_init(&ad, vol->v_adouble, vol->v_ad_options);
      adp = &ad;
          }
      } else {
          id = sdir->d_did; /* we already have the CNID */
 -        p = ctoupath( vol, sdir->d_parent, oldname );
 +        p = ctoupath( vol, dirlookup(vol, sdir->d_pdid), oldname );
          if (!p) {
              return AFPERR_PARAM;
          }
          adflags = ADFLAGS_DIR;
      }
  
 -
      /*
       * p now points to either
       *   a) full pathname of the source fs object (if renameat is not available)
      if (sdir_fd != -1) {
          if ((cwd_fd = open(".", O_RDONLY)) == -1)
              return AFPERR_MISC;
-         if (fchdir(sdir_fd) != 0)
-             return AFPERR_MISC;
+         if (fchdir(sdir_fd) != 0) {
+             rc = AFPERR_MISC;
+             goto exit;
+         }
      }
      if (!ad_metadata(p, adflags, adp)) {
          u_int16_t bshort;
  
          ad_getattr(adp, &bshort);
          ad_close_metadata( adp);
-         if ((bshort & htons(ATTRBIT_NORENAME)))
-             return(AFPERR_OLOCK);
+         if ((bshort & htons(ATTRBIT_NORENAME))) {
+             rc = AFPERR_OLOCK;
+             goto exit;
+         }
      }
      if (sdir_fd != -1) {
          if (fchdir(cwd_fd) != 0) {
              LOG(log_error, logtype_afpd, "moveandrename: %s", strerror(errno) );
-             return AFPERR_MISC;
+             rc = AFPERR_MISC;
+             goto exit;
          }
      }
  
-     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){
-         return AFPERR_PARAM;
+     if (NULL == (upath = mtoupath(vol, newname, curdir->d_did, utf8_encoding()))){ 
+         rc = AFPERR_PARAM;
+         goto exit;
      }
      path.u_name = upath;
 -    st = &path.st;    
 +    st = &path.st;
      if (0 != (rc = check_name(vol, upath))) {
-         return  rc;
+         goto exit;
      }
  
      /* source == destination. we just silently accept this. */
 -    if ((!isdir && curdir == sdir) || (isdir && curdir == sdir->d_parent)) {
 +    if ((!isdir && curdir == sdir) || (isdir && curdir->d_did == sdir->d_pdid)) {
-         if (strcmp(oldname, newname) == 0)
-             return AFP_OK;
+         if (strcmp(oldname, newname) == 0) {
+             rc = AFP_OK;
+             goto exit;
+         }
  
          if (stat(upath, st) == 0 || caseenumerate(vol, &path, curdir) == 0) {
              if (!stat(p, &nst) && !(nst.st_dev == st->st_dev && nst.st_ino == st->st_ino) ) {
                  /* not the same file */
-                 return AFPERR_EXIST;
+                 rc = AFPERR_EXIST;
+                 goto exit;
              }
              errno = 0;
          }
-     } else if (stat(upath, st ) == 0 || caseenumerate(vol, &path, curdir) == 0)
-         return AFPERR_EXIST;
+     } else if (stat(upath, st ) == 0 || caseenumerate(vol, &path, curdir) == 0) {
+         rc = AFPERR_EXIST;
+         goto exit;
+     }
  
      if ( !isdir ) {
          path.st_valid = 1;
      }
      if ( rc == AFP_OK && id ) {
          /* renaming may have moved the file/dir across a filesystem */
-         if (stat(upath, st) < 0)
-             return AFPERR_MISC;
+         if (stat(upath, st) < 0) {
+             rc = AFPERR_MISC;
+             goto exit;
+         }
 +
 +        if (dir_modify(vol,
 +                       sdir,
 +                       curdir->d_did,
 +                       0,
 +                       newname,
 +                       upath,
 +                       S_ISDIR(st->st_mode) ? curdir->d_fullpath : NULL) != 0) {
 +            LOG(log_error, logtype_afpd, "moveandrename: dir_modify error: %s -> %s",
 +                p, upath);
 +            return AFPERR_MISC;
 +        }
 +
          /* fix up the catalog entry */
          cnid_update(vol->v_cdb, id, st, curdir->d_did, upath, strlen(upath));
      }
  
+ exit:
+     if (cwd_fd != -1)
+         close(cwd_fd);
      return rc;
  }
  
  /* -------------------------------------------- */
  int afp_rename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
  {
 -    struct vol        *vol;
 -    struct dir        *sdir;
 +    struct vol  *vol;
 +    struct dir  *sdir;
      char        *oldname, *newname;
      struct path *path;
 -    u_int32_t did;
 +    u_int32_t   did;
      int         plen;
 -    u_int16_t vid;
 +    u_int16_t   vid;
      int         isdir = 0;
      int         rc;
  
      memcpy( &did, ibuf, sizeof( did ));
      ibuf += sizeof( did );
      if (NULL == ( sdir = dirlookup( vol, did )) ) {
 -      return afp_errno;    
 +        return afp_errno;
      }
  
      /* source pathname */
      if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
 -        return get_afp_errno(AFPERR_NOOBJ); 
 +        return get_afp_errno(AFPERR_NOOBJ);
      }
  
      sdir = curdir;
          }
      }
      else {
 -        if ( sdir->d_parent == NULL ) { /* root directory */
 +        if ( sdir->d_did == DIRDID_ROOT ) { /* root directory */
              return( AFPERR_NORENAME );
          }
          /* move to destination dir */
 -        if ( movecwd( vol, sdir->d_parent ) < 0 ) {
 +        if ( movecwd( vol, dirlookup(vol, sdir->d_pdid) ) < 0 ) {
              return afp_errno;
          }
 -        strcpy(oldname, sdir->d_m_name);
 +        memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) +1);
      }
  
      /* another place where we know about the path type */
  /* ------------------------------- */
  int afp_delete(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
  {
 -    struct vol                *vol;
 -    struct dir                *dir;
 +    struct vol      *vol;
 +    struct dir      *dir;
      struct path         *s_path;
 -    char              *upath;
 -    int                       did, rc;
 -    u_int16_t         vid;
 +    char        *upath;
 +    int         did, rc;
 +    u_int16_t       vid;
  
      *rbuflen = 0;
      ibuf += 2;
  
      memcpy( &did, ibuf, sizeof( did ));
      ibuf += sizeof( int );
 +
      if (NULL == ( dir = dirlookup( vol, did )) ) {
 -      return afp_errno;    
 +        return afp_errno;
      }
  
      if (NULL == ( s_path = cname( vol, dir, &ibuf )) ) {
 -        return get_afp_errno(AFPERR_NOOBJ); 
 +        return get_afp_errno(AFPERR_NOOBJ);
      }
  
      upath = s_path->u_name;
      if ( path_isadir( s_path) ) {
 -      if (*s_path->m_name != '\0') {
 -          rc = AFPERR_ACCESS;
 -      }
 -      else {
 +        if (*s_path->m_name != '\0' || curdir->d_did == DIRDID_ROOT)
 +            rc = AFPERR_ACCESS;
 +        else
              rc = deletecurdir( vol);
 -        }
      } else if (of_findname(s_path)) {
          rc = AFPERR_BUSY;
      } else {
          }
          else {
              rc = deletefile(vol, -1, upath, 1);
 +
 +            struct dir *cachedfile;
 +            if ((cachedfile = dircache_search_by_name(vol, dir, upath, strlen(upath)))) {
 +                dircache_remove(vol, cachedfile, DIRCACHE | DIDNAME_INDEX | QUEUE_INDEX);
 +                dir_free(cachedfile);
 +            }
          }
      }
      if ( rc == AFP_OK ) {
 -      curdir->offcnt--;
 +        curdir->offcnt--;
          setvoltime(obj, vol );
      }
  
  /* ------------------------ */
  char *absupath(const struct vol *vol, struct dir *dir, char *u)
  {
 -    struct dir        *d;
 -    static char       path[ MAXPATHLEN + 1];
 -    char      *p;
 -    int               len;
 +    static char pathbuf[MAXPATHLEN + 1];
 +    bstring path;
  
 -    if (u == NULL)
 +    if (u == NULL || dir == NULL || vol == NULL)
          return NULL;
 -        
 -    p = path + sizeof( path ) - 1;
 -    *p = '\0';
 -    len = strlen( u );
 -    p -= len;
 -    memcpy( p, u, len );
 -    if (dir) for ( d = dir; d->d_parent; d = d->d_parent ) {
 -        u = d->d_u_name;
 -        len = strlen( u );
 -        if (p -len -1 < path) {
 -            /* FIXME 
 -               rather rare so LOG error and/or client message ?
 -            */
 -            return NULL;
 -        }
 -        *--p = '/';
 -        p -= len;
 -        memcpy( p, u, len );
 -    }
 -    len = strlen( vol->v_path );
 -    if (p -len -1 < path) {
 +
 +    if ((path = bstrcpy(dir->d_fullpath)) == NULL)
 +        return NULL;
 +    if (bcatcstr(path, "/") != BSTR_OK)
 +        return NULL;
 +    if (bcatcstr(path, u) != BSTR_OK)
 +        return NULL;
 +    if (path->slen > MAXPATHLEN)
          return NULL;
 -    }
 -    *--p = '/';
 -    p -= len;
 -    memcpy( p, vol->v_path, len );
  
 -    return( p );
 +    LOG(log_debug, logtype_afpd, "absupath: %s", cfrombstr(path));
 +
 +    strncpy(pathbuf, cfrombstr(path), blength(path) + 1);
 +    bdestroy(path);
 +
 +    return(pathbuf);
  }
  
 -/* ------------------------
 - * FIXME dir could be NULL
 -*/
  char *ctoupath(const struct vol *vol, struct dir *dir, char *name)
  {
 +    if (vol == NULL || dir == NULL || name == NULL)
 +        return NULL;
      return absupath(vol, dir, mtoupath(vol, name, dir->d_did, utf8_encoding()));
  }
  
  /* ------------------------- */
  int afp_moveandrename(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U_, size_t *rbuflen)
  {
 -    struct vol        *vol;
 -    struct dir        *sdir, *ddir;
 +    struct vol  *vol;
 +    struct dir  *sdir, *ddir;
      int         isdir;
 -    char      *oldname, *newname;
 +    char    *oldname, *newname;
      struct path *path;
 -    int               did;
 -    int               pdid;
 +    int     did;
 +    int     pdid;
      int         plen;
 -    u_int16_t vid;
 +    u_int16_t   vid;
      int         rc;
  #ifdef DROPKLUDGE
 -    int               retvalue;
 +    int     retvalue;
  #endif /* DROPKLUDGE */
      int     sdir_fd = -1;
  
  
      /* source pathname */
      if (NULL == ( path = cname( vol, sdir, &ibuf )) ) {
 -        return get_afp_errno(AFPERR_NOOBJ); 
 +        return get_afp_errno(AFPERR_NOOBJ);
      }
  
      sdir = curdir;
      newname = obj->newtmp;
      oldname = obj->oldtmp;
 -    
 +
      isdir = path_isadir(path);
      if ( *path->m_name != '\0' ) {
          if (isdir) {
          }
          strcpy(oldname, path->m_name); /* an extra copy for of_rename */
      } else {
 -        strcpy(oldname, sdir->d_m_name);
 +        memcpy(oldname, cfrombstr(sdir->d_m_name), blength(sdir->d_m_name) + 1);
      }
  
  #ifdef HAVE_RENAMEAT
      }
  
      /* This does the work */
 +    LOG(log_debug, logtype_afpd, "afp_move(oldname:'%s', newname:'%s', isdir:%u)",
 +        oldname, newname, isdir);
      rc = moveandrename(vol, sdir, sdir_fd, oldname, newname, isdir);
  
      if ( rc == AFP_OK ) {
          char *upath = mtoupath(vol, newname, pdid, utf8_encoding());
 -        
 +
          if (NULL == upath) {
              rc = AFPERR_PARAM;
              goto exit;
@@@ -781,8 -786,8 +797,8 @@@ int veto_file(const char*veto_str, cons
   * otherwise, 0 is returned.
   */
  {
 -    int i;    /* index to veto_str */
 -    int j;    /* index to path */
 +    int i;  /* index to veto_str */
 +    int j;  /* index to path */
  
      if ((veto_str == NULL) || (path == NULL))
          return 0;
          } else {
              if (veto_str[i] != path[j]) {
                  while ((veto_str[i] != '/')
 -                        && (veto_str[i] != '\0'))
 +                       && (veto_str[i] != '\0'))
                      i++;
                  j = 0;
                  continue;