From 2bf71d3ccf20c072bc67a9d075b6ac8b0798021e Mon Sep 17 00:00:00 2001 From: franklahm Date: Wed, 10 Feb 2010 14:05:36 +0000 Subject: [PATCH] Merge symlink branch --- NEWS | 10 +++-- configure.in | 31 ++++++++++++- etc/afpd/acls.c | 4 +- etc/afpd/afp_asp.c | 4 +- etc/afpd/catsearch.c | 14 +++--- etc/afpd/directory.c | 88 ++++++++++++++++++++++++++++++++++--- etc/afpd/enumerate.c | 4 +- etc/afpd/file.c | 48 ++++++++++++++++---- etc/afpd/file.h | 4 +- etc/afpd/filedir.c | 4 +- etc/afpd/ofork.c | 8 ++-- etc/afpd/quota.c | 14 +++--- etc/afpd/unix.c | 20 ++++----- include/atalk/adouble.h | 3 +- libatalk/adouble/ad_flush.c | 7 ++- libatalk/adouble/ad_open.c | 39 ++++++++++++---- libatalk/adouble/ad_read.c | 13 +++++- libatalk/vfs/ea.c | 6 +-- libatalk/vfs/unix.c | 13 +++--- 19 files changed, 256 insertions(+), 78 deletions(-) diff --git a/NEWS b/NEWS index 54410534..eb3b86de 100644 --- a/NEWS +++ b/NEWS @@ -3,7 +3,7 @@ Changes in 2.1-beta1 * NEW: afpd: AFP 3.2 support * NEW: afpd: Extended Attributes support using native attributes or - using files inside .AppleDouble directories. + using files inside .AppleDouble directories. * NEW: afpd: ACL support with ZFS * NEW: cnid_metad: options -l and -f to configure logging * NEW: IPv6 support @@ -20,7 +20,7 @@ Changes in 2.1-beta1 * NEW: configure args to download and install a "private" Webmin instance including only basic Webmin modules plus our netatalk.wbm. * NEW: fallback to a temporary in memory tdb CNID database if the volume - database can't be open. + database can't be opened. * NEW: support for Unicode characters in the range above U+010000 using internal surrogate pairs * NEW: apple_dump: utility to dump AppleSingle and AppleDouble files @@ -29,6 +29,8 @@ Changes in 2.1-beta1 SRVLOC is legacy. * UPD: cdb/dbd CNID backend requires BerkeleyDB >= 4.6 * UPD: afpd: try to install PAM config that pulls in system|common auth +* UPD: afpd: symlink handling: never followed server side, client resolves + them, so it's safe to use them now. * FIX: rewritten logger * FIX: afpd: UNIX permissions handling * FIX: cnid_dbd: always use BerkeleyDB transactions @@ -40,8 +42,8 @@ Changes in 2.1-beta1 which is in our case the last configured one. atalkd now tries to find the right one. Note: now a misconfigured or plugged router can broadcast a wrong route ! -* REM: cnid_maint: use dbd [FIXME: s/dbd/INSERT NAME HERE/] -* REM: cleanappledouble.pl: use dbd [FIXME: s/dbd/INSERT NAME HERE/] +* REM: cnid_maint: use dbd +* REM: cleanappledouble.pl: use dbd * REM: nu: use `macusers` instead Changes in 2.0.5 diff --git a/configure.in b/configure.in index eaa9488f..1c107098 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl $Id: configure.in,v 1.237 2010-01-26 18:13:48 franklahm Exp $ +dnl $Id: configure.in,v 1.238 2010-02-10 14:05:36 franklahm Exp $ dnl configure.in for netatalk AC_INIT(etc/afpd/main.c) @@ -1152,6 +1152,35 @@ if test "x$neta_cv_eas_sys_found" = "xyes" ; then fi fi +dnl --------------------- Check if realpath() takes NULL +AC_CACHE_CHECK([if the realpath function allows a NULL argument], + neta_cv_REALPATH_TAKES_NULL, [ + AC_TRY_RUN([ + #include + #include + #include + + void exit_on_core(int ignored) { + exit(1); + } + + main() { + char *newpath; + signal(SIGSEGV, exit_on_core); + newpath = realpath("/tmp", NULL); + exit((newpath != NULL) ? 0 : 1); + }], + neta_cv_REALPATH_TAKES_NULL=yes, + neta_cv_REALPATH_TAKES_NULL=no, + neta_cv_REALPATH_TAKES_NULL=cross + ) + ] +) + +if test x"$neta_cv_REALPATH_TAKES_NULL" = x"yes"; then + AC_DEFINE(REALPATH_TAKES_NULL,1,[Whether the realpath function allows NULL]) +fi + dnl --------------------- Netatalk Webmin NETATALK_WEBMIN diff --git a/etc/afpd/acls.c b/etc/afpd/acls.c index a3d17f3f..f5d3eaab 100644 --- a/etc/afpd/acls.c +++ b/etc/afpd/acls.c @@ -1,5 +1,5 @@ /* - $Id: acls.c,v 1.7 2009-11-28 13:06:30 franklahm Exp $ + $Id: acls.c,v 1.8 2010-02-10 14:05:37 franklahm Exp $ Copyright (c) 2008,2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -583,7 +583,7 @@ static int check_acl_access(const char *path, const uuidp_t uuid, uint32_t reque } /* File or dir */ - if ((stat(path, &st)) != 0) { + if ((lstat(path, &st)) != 0) { LOG(log_error, logtype_afpd, "check_access: stat: %s", strerror(errno)); ret = AFPERR_PARAM; goto exit; diff --git a/etc/afpd/afp_asp.c b/etc/afpd/afp_asp.c index dddb3da5..ea40e58f 100644 --- a/etc/afpd/afp_asp.c +++ b/etc/afpd/afp_asp.c @@ -1,5 +1,5 @@ /* - * $Id: afp_asp.c,v 1.27 2009-10-25 07:18:11 didg Exp $ + * $Id: afp_asp.c,v 1.28 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1997 Adrian Sun (asun@zoology.washington.edu) * Copyright (c) 1990,1993 Regents of The University of Michigan. @@ -81,7 +81,7 @@ static void afp_authprint_remove(AFPObj *obj) memset( addr_filename_buff, 0, 256 ); - if(stat(addr_filename, &cap_st) == 0) { + if(lstat(addr_filename, &cap_st) == 0) { if( S_ISREG(cap_st.st_mode) ) { int len; int capfd = open( addr_filename, O_RDONLY ); diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c index ccbdd80f..46192e35 100644 --- a/etc/afpd/catsearch.c +++ b/etc/afpd/catsearch.c @@ -237,13 +237,13 @@ static struct finderinfo *unpack_buffer(struct finderinfo *finfo, char *buffer) /* -------------------- */ static struct finderinfo * -unpack_finderinfo(struct vol *vol, struct path *path, struct adouble **adp, struct finderinfo *finfo) +unpack_finderinfo(struct vol *vol, struct path *path, struct adouble **adp, struct finderinfo *finfo, int islnk) { packed_finder buf; void *ptr; *adp = adl_lkup(vol, path, *adp); - ptr = get_finderinfo(vol, path->u_name, *adp, &buf); + ptr = get_finderinfo(vol, path->u_name, *adp, &buf,islnk); return unpack_buffer(finfo, ptr); } @@ -265,6 +265,8 @@ static int crit_check(struct vol *vol, struct path *path) { u_int32_t ac_date, ab_date; static char convbuf[514]; /* for convert_charset dest_len parameter +2 */ size_t len; + int islnk; + islnk=S_ISLNK(path->st.st_mode); if (S_ISDIR(path->st.st_mode)) { if (!c1.dbitmap) @@ -379,7 +381,7 @@ static int crit_check(struct vol *vol, struct path *path) { /* Check file type ID */ if ((c1.rbitmap & (1<f_type != c1.finfo.f_type) goto crit_check_ret; } @@ -387,7 +389,7 @@ static int crit_check(struct vol *vol, struct path *path) { /* Check creator ID */ if ((c1.rbitmap & (1<creator != c1.finfo.creator) goto crit_check_ret; @@ -396,7 +398,7 @@ static int crit_check(struct vol *vol, struct path *path) { /* Check finder info attributes */ if ((c1.rbitmap & (1<attrs & c2.finfo.attrs) != c1.finfo.attrs) @@ -406,7 +408,7 @@ static int crit_check(struct vol *vol, struct path *path) { /* Check label */ if ((c1.rbitmap & (1<label & c2.finfo.label) != c1.finfo.label) goto crit_check_ret; diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index 11c6de7e..f330d3ca 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.131 2010-01-26 20:39:52 didg Exp $ + * $Id: directory.c,v 1.132 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -133,6 +133,76 @@ static struct dir rootpar = { SENTINEL, SENTINEL, NULL, * frPutAway: 4 home directory ID */ +/*! + * @brief symlink safe chdir replacement + * + * Only chdirs to dir if it doesn't contain symlinks. + * + * @returns 1 if a path element is a symlink, 0 otherwise, -1 on syserror + */ +static int lchdir(const char *dir) +{ + int ret = 0; + char buf[MAXPATHLEN+1]; +#ifdef REALPATH_TAKES_NULL + char *rpath = NULL; +#else + char rpath[MAXPATHLEN+1]; +#endif + + /* dir might be an relative or an absolute path */ + if (dir[0] == '/') { + /* absolute path, just make sure buf is prepared for strlcat */ + buf[0] = 0; + } else { + /* relative path, push cwd int buf */ + if (getcwd(buf, MAXPATHLEN) == NULL) + return -1; + if (strlcat(buf, "/", MAXPATHLEN) >= MAXPATHLEN) + return -1; + } + + if (strlcat(buf, dir, MAXPATHLEN) >= MAXPATHLEN) + return -1; + +#ifdef REALPATH_TAKES_NULL + if ((rpath = realpath(dir, NULL)) == NULL) { +#else + if (realpath(dir, rpath) == NULL) { +#endif + ret = -1; + goto exit; + } + + /* + * Cases: + * chdir request | realpath result | ret + * (after getwcwd) | | + * ======================================= + * /a/b/. | /a/b | 0 + * /a/b/. | /c | 1 + * /a/b/. | /c/d/e/f | 1 + */ + ret = 0; + for (int i = 0; rpath[i]; i++) { + if (buf[i] != rpath[i]) { + ret = 1; + goto exit; + } + } + + if (chdir(dir) != 0) { + ret = -1; + goto exit; + } + +exit: +#ifdef REALPATH_TAKES_NULL + free(rpath); +#endif + return ret; +} + static struct dir * vol_tree_root(const struct vol *vol, u_int32_t did) { @@ -818,7 +888,7 @@ static int deletedir(char *dir) break; } strcpy(path + len, de->d_name); - if (stat(path, &st)) { + if (lstat(path, &st)) { continue; } if (S_ISDIR(st.st_mode)) { @@ -884,7 +954,7 @@ static int copydir(const struct vol *vol, char *src, char *dst) } strcpy(spath + slen, de->d_name); - if (stat(spath, &st) == 0) { + if (lstat(spath, &st) == 0) { if (strlen(de->d_name) > drem) { err = AFPERR_PARAM; break; @@ -906,7 +976,7 @@ static int copydir(const struct vol *vol, char *src, char *dst) } /* keep the same time stamp. */ - if (stat(src, &st) == 0) { + if (lstat(src, &st) == 0) { ut.actime = ut.modtime = st.st_mtime; utime(dst, &ut); } @@ -1542,6 +1612,7 @@ int movecwd(struct vol *vol, struct dir *dir) struct dir *d; char *p, *u; int n; + int ret; if ( dir == curdir ) { return( 0 ); @@ -1580,7 +1651,14 @@ int movecwd(struct vol *vol, struct dir *dir) p -= n; memcpy( p, vol->v_path, n ); } - if ( chdir( p ) < 0 ) { + if ( (ret = lchdir( p )) != 0 ) { + LOG(log_debug, logtype_afpd, "movecwd('%s'): ret:%d, %u/%s", p, ret, errno, strerror(errno)); + + if (ret == 1) { + /* p is a symlink */ + afp_errno = AFPERR_BADTYPE; + return -1; + } switch (errno) { case EACCES: case EPERM: diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c index 15235c6f..c06ef203 100644 --- a/etc/afpd/enumerate.c +++ b/etc/afpd/enumerate.c @@ -1,5 +1,5 @@ /* - * $Id: enumerate.c,v 1.48 2010-01-11 11:09:36 franklahm Exp $ + * $Id: enumerate.c,v 1.49 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -280,7 +280,7 @@ static int enumerate(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, if ( sindex == 1 || curdir->d_did != sd.sd_did || vid != sd.sd_vid ) { sd.sd_last = sd.sd_buf; /* if dir was in the cache we don't have the inode */ - if (( !o_path->st_valid && stat( ".", &o_path->st ) < 0 ) || + if (( !o_path->st_valid && lstat( ".", &o_path->st ) < 0 ) || (ret = for_each_dirent(vol, ".", enumerate_loop, (void *)&sd)) < 0) { switch (errno) { diff --git a/etc/afpd/file.c b/etc/afpd/file.c index 31107ce2..915219f5 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.133 2010-02-08 10:29:22 franklahm Exp $ + * $Id: file.c,v 1.134 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -89,7 +89,7 @@ static int default_type(void *finder) } /* FIXME path : unix or mac name ? (for now it's unix name ) */ -void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data) +void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *adp, void *data, int islink) { struct extmap *em; void *ad_finder = NULL; @@ -114,6 +114,17 @@ void *get_finderinfo(const struct vol *vol, const char *upath, struct adouble *a memcpy((char *)data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); } } + + if (islink){ + u_int16_t linkflag; + memcpy(&linkflag, (char *)data + FINDERINFO_FRFLAGOFF, 2); + linkflag |= htons(FINDERINFO_ISALIAS); + memcpy((char *)data + FINDERINFO_FRFLAGOFF, &linkflag, 2); + memcpy((char *)data + FINDERINFO_FRTYPEOFF,"slnk",4); + memcpy((char *)data + FINDERINFO_FRCREATOFF,"rhap",4); + chk_ext = 0; + } + /** Only enter if no appledouble information and no finder information found. */ if (chk_ext && (em = getextmap( upath ))) { memcpy(data, em->em_type, sizeof( em->em_type )); @@ -332,7 +343,7 @@ int getmetadata(struct vol *vol, break; case FILPBIT_FINFO : - get_finderinfo(vol, upath, adp, (char *)data); + get_finderinfo(vol, upath, adp, (char *)data,S_ISLNK(st->st_mode)); data += ADEDLEN_FINDERI; break; @@ -795,6 +806,27 @@ int setfilparams(struct vol *vol, case FILPBIT_FINFO : change_mdate = 1; memcpy(finder_buf, buf, 32 ); + if (memcmp(buf,"slnkrhap",8)==0 && !S_ISLNK(path->st.st_mode)){ + // SLFINFO + int fp; + ssize_t len; + int erc=1; + char buf[PATH_MAX+1]; + if ((fp=open(path->u_name,O_RDONLY))>=0){ + if (len=read(fp,buf,PATH_MAX+1)){ + if (unlink(path->u_name)==0){ + buf[len]=0; + erc=symlink(buf,path->u_name); + lstat(path->u_name,&(path->st)); + } + } + close(fp); + } + if (erc!=0){ + err=AFPERR_BITMAP; + goto setfilparam_done; + } + } buf += 32; break; case FILPBIT_UNIXPR : @@ -1654,7 +1686,7 @@ static int reenumerate_loop(struct dirent *de, char *mname _U_, void *data) cnid_t did = param->did; cnid_t aint; - if ( stat(de->d_name, &path.st)<0 ) + if ( lstat(de->d_name, &path.st)<0 ) return 0; /* update or add to cnid */ @@ -1699,7 +1731,7 @@ reenumerate_id(struct vol *vol, char *name, struct dir *dir) } /* FIXME use of_statdir ? */ - if (stat(name, &st)) { + if (lstat(name, &st)) { return -1; } @@ -1869,7 +1901,7 @@ int afp_deleteid(AFPObj *obj _U_, char *ibuf, size_t ibuflen _U_, char *rbuf _U_ } err = AFP_OK; - if ((movecwd(vol, dir) < 0) || (stat(upath, &st) < 0)) { + if ((movecwd(vol, dir) < 0) || (lstat(upath, &st) < 0)) { switch (errno) { case EACCES: case EPERM: @@ -2114,10 +2146,10 @@ int afp_exchangefiles(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf _U if (did) { cnid_delete(vol->v_cdb, did); } - if ((did && ( (crossdev && stat( upath, &srcst) < 0) || + if ((did && ( (crossdev && lstat( upath, &srcst) < 0) || cnid_update(vol->v_cdb, did, &srcst, curdir->d_did,upath, dlen) < 0)) || - (sid && ( (crossdev && stat(p, &destst) < 0) || + (sid && ( (crossdev && lstat(p, &destst) < 0) || cnid_update(vol->v_cdb, sid, &destst, sdir->d_did,supath, slen) < 0)) ) { switch (errno) { diff --git a/etc/afpd/file.h b/etc/afpd/file.h index c4253ca0..9d3ca116 100644 --- a/etc/afpd/file.h +++ b/etc/afpd/file.h @@ -1,5 +1,5 @@ /* - * $Id: file.h,v 1.24 2009-10-15 10:43:13 didg Exp $ + * $Id: file.h,v 1.25 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -122,7 +122,7 @@ extern int deletefile (const struct vol *, char *, int); extern int getmetadata (struct vol *vol, u_int16_t bitmap, struct path *path, struct dir *dir, char *buf, size_t *buflen, struct adouble *adp); -extern void *get_finderinfo (const struct vol *, const char *, struct adouble *, void *); +extern void *get_finderinfo (const struct vol *, const char *, struct adouble *, void *, int); extern size_t mtoUTF8 (const struct vol *, const char *, size_t , char *, size_t ); extern int copy_path_name (const struct vol *, char *, char *i); diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index 897bb576..4451ae80 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -1,5 +1,5 @@ /* - * $Id: filedir.c,v 1.69 2010-01-21 14:14:49 didg Exp $ + * $Id: filedir.c,v 1.70 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -98,7 +98,7 @@ more information */ upath, strerror(errno)); ret = AFPERR_ACCESS; } - else if (chmod(upath,(st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0) + else if ((!S_ISLNK(st->st_mode)) && (chmod(upath,(st.st_mode&~default_options.umask)| S_IRGRP| S_IROTH) < 0)) { LOG(log_error, logtype_afpd, "matchfile2dirperms(%s): Error adding file read permissions: %s", diff --git a/etc/afpd/ofork.c b/etc/afpd/ofork.c index 9bb69667..d9c4f31e 100644 --- a/etc/afpd/ofork.c +++ b/etc/afpd/ofork.c @@ -1,5 +1,5 @@ /* - * $Id: ofork.c,v 1.30 2009-11-13 00:27:36 didg Exp $ + * $Id: ofork.c,v 1.31 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1996 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -285,7 +285,7 @@ int of_stat (struct path *path) int ret; path->st_errno = 0; path->st_valid = 1; - if ((ret = stat(path->u_name, &path->st)) < 0) + if ((ret = lstat(path->u_name, &path->st)) < 0) path->st_errno = errno; return ret; } @@ -309,7 +309,7 @@ int ret; /* FIXME, what about: we don't have r-x perm anymore ? */ strlcpy(pathname +3, path->d_dir->d_u_name, sizeof (pathname) -3); - if (!(ret = stat(pathname, &path->st))) + if (!(ret = lstat(pathname, &path->st))) return 0; path->st_errno = errno; @@ -318,7 +318,7 @@ int ret; if (movecwd(vol, curdir->d_parent)) return -1; path->st_errno = 0; - if ((ret = stat(path->d_dir->d_u_name, &path->st)) < 0) + if ((ret = lstat(path->d_dir->d_u_name, &path->st)) < 0) path->st_errno = errno; } return ret; diff --git a/etc/afpd/quota.c b/etc/afpd/quota.c index e40de5fa..26aae15b 100644 --- a/etc/afpd/quota.c +++ b/etc/afpd/quota.c @@ -1,5 +1,5 @@ /* - * $Id: quota.c,v 1.33 2010-01-21 14:14:49 didg Exp $ + * $Id: quota.c,v 1.34 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -296,7 +296,7 @@ mountp( char *file, int *nfs) dev_t devno; static struct mnttab mnt; - if ( stat( file, &sb ) < 0 ) { + if ( lstat( file, &sb ) < 0 ) { return( NULL ); } devno = sb.st_dev; @@ -307,14 +307,14 @@ mountp( char *file, int *nfs) while ( getmntent( mtab, &mnt ) == 0 ) { /* local fs */ - if ( (stat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) { + if ( (lstat( mnt.mnt_special, &sb ) == 0) && (devno == sb.st_rdev)) { fclose( mtab ); return mnt.mnt_mountp; } /* check for nfs. we probably should use * strcmp(mnt.mnt_fstype, MNTTYPE_NFS), but that's not as fast. */ - if ((stat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) && + if ((lstat(mnt.mnt_mountp, &sb) == 0) && (devno == sb.st_dev) && strchr(mnt.mnt_special, ':')) { *nfs = 1; fclose( mtab ); @@ -384,7 +384,7 @@ special(char *file, int *nfs) struct mntent *mnt; int found=0; - if ( stat( file, &sb ) < 0 ) { + if ( lstat( file, &sb ) < 0 ) { return( NULL ); } devno = sb.st_dev; @@ -395,14 +395,14 @@ special(char *file, int *nfs) while (( mnt = getmntent( mtab )) != NULL ) { /* check for local fs */ - if ( (stat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) { + if ( (lstat( mnt->mnt_fsname, &sb ) == 0) && devno == sb.st_rdev) { found = 1; break; } /* check for an nfs mount entry. the alternative is to use * strcmp(mnt->mnt_type, MNTTYPE_NFS) instead of the strchr. */ - if ((stat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) && + if ((lstat(mnt->mnt_dir, &sb) == 0) && (devno == sb.st_dev) && strchr(mnt->mnt_fsname, ':')) { *nfs = 1; found = 1; diff --git a/etc/afpd/unix.c b/etc/afpd/unix.c index d5bde724..57491a71 100644 --- a/etc/afpd/unix.c +++ b/etc/afpd/unix.c @@ -1,5 +1,5 @@ /* - * $Id: unix.c,v 1.60 2010-01-20 13:22:13 franklahm Exp $ + * $Id: unix.c,v 1.61 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -178,7 +178,7 @@ struct stat sb; ma->ma_user = ma->ma_owner = ma->ma_world = ma->ma_group = 0; if (!st) { - if (stat(path, &sb) != 0) + if (lstat(path, &sb) != 0) return; st = &sb; } @@ -281,7 +281,7 @@ int setdeskmode(const mode_t mode) *m = '\0'; strcat( modbuf, subp->d_name ); /* XXX: need to preserve special modes */ - if (stat(modbuf, &st) < 0) { + if (lstat(modbuf, &st) < 0) { LOG(log_error, logtype_afpd, "setdeskmode: stat %s: %s",fullpathname(modbuf), strerror(errno) ); continue; } @@ -388,7 +388,7 @@ int setdirmode(const struct vol *vol, const char *name, mode_t mode) if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) { continue; } - if ( stat( dirp->d_name, &st ) < 0 ) { + if ( lstat( dirp->d_name, &st ) < 0 ) { LOG(log_error, logtype_afpd, "setdirmode: stat %s: %s",dirp->d_name, strerror(errno) ); continue; } @@ -489,7 +489,7 @@ int setfilowner(const struct vol *vol, const uid_t uid, const gid_t gid, struct return -1; } - if ( chown( path->u_name, uid, gid ) < 0 && errno != EPERM ) { + if ( lchown( path->u_name, uid, gid ) < 0 && errno != EPERM ) { LOG(log_debug, logtype_afpd, "setfilowner: chown %d/%d %s: %s", uid, gid, path->u_name, strerror(errno) ); return -1; @@ -523,13 +523,13 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const if ( *dirp->d_name == '.' && (!osx || dirp->d_name[1] != '_')) { continue; } - if ( stat( dirp->d_name, &st ) < 0 ) { + if ( lstat( dirp->d_name, &st ) < 0 ) { LOG(log_error, logtype_afpd, "setdirowner: stat %s: %s", fullpathname(dirp->d_name), strerror(errno) ); continue; } if (( st.st_mode & S_IFMT ) == S_IFREG ) { - if ( chown( dirp->d_name, uid, gid ) < 0 && errno != EPERM ) { + if ( lchown( dirp->d_name, uid, gid ) < 0 && errno != EPERM ) { LOG(log_debug, logtype_afpd, "setdirowner: chown %s: %s", fullpathname(dirp->d_name), strerror(errno) ); /* return ( -1 ); Sometimes this is okay */ @@ -542,10 +542,10 @@ int setdirowner(const struct vol *vol, const char *name, const uid_t uid, const return -1; } - if ( stat( ".", &st ) < 0 ) { + if ( lstat( ".", &st ) < 0 ) { return( -1 ); } - if ( gid && gid != st.st_gid && chown( ".", uid, gid ) < 0 && errno != EPERM ) { + if ( gid && gid != st.st_gid && lchown( ".", uid, gid ) < 0 && errno != EPERM ) { LOG(log_debug, logtype_afpd, "setdirowner: chown %d/%d %s: %s", uid, gid, fullpathname("."), strerror(errno) ); } @@ -569,7 +569,7 @@ static int recursive_chown(const char *path, uid_t uid, gid_t gid) { return -1; } - if (stat(path, &sbuf) < 0) { + if (lstat(path, &sbuf) < 0) { LOG(log_error, logtype_afpd, "cannot chown() file [%s] (uid = %d): %s", path, uid, strerror(errno)); return -1; } diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index 8ead1c4d..fbf53a1c 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -1,5 +1,5 @@ /* - * $Id: adouble.h,v 1.52 2010-01-05 12:06:34 franklahm Exp $ + * $Id: adouble.h,v 1.53 2010-02-10 14:05:37 franklahm Exp $ * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. * @@ -249,6 +249,7 @@ struct ad_fd { off_t adf_off; #endif + char *adf_syml; int adf_flags; int adf_excl; adf_lock_t *adf_lock; diff --git a/libatalk/adouble/ad_flush.c b/libatalk/adouble/ad_flush.c index a9383315..3569e869 100644 --- a/libatalk/adouble/ad_flush.c +++ b/libatalk/adouble/ad_flush.c @@ -1,5 +1,5 @@ /* - * $Id: ad_flush.c,v 1.12 2009-10-13 22:55:37 didg Exp $ + * $Id: ad_flush.c,v 1.13 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -200,9 +200,14 @@ int ad_close( struct adouble *ad, int adflags) if (( adflags & ADFLAGS_DF ) && ad_data_fileno(ad) != -1 && !(--ad->ad_data_fork.adf_refcount)) { + if (ad->ad_data_fork.adf_syml!=0){ + free(ad->ad_data_fork.adf_syml); + ad->ad_data_fork.adf_syml=0; + }else{ if ( close( ad_data_fileno(ad) ) < 0 ) { err = -1; } + } ad_data_fileno(ad) = -1; adf_lock_free(&ad->ad_data_fork); } diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index b0eb4235..2785cbf1 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1,5 +1,5 @@ /* - * $Id: ad_open.c,v 1.68 2010-01-06 14:05:15 franklahm Exp $ + * $Id: ad_open.c,v 1.69 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) * Copyright (c) 1990,1991 Regents of The University of Michigan. @@ -1014,8 +1014,8 @@ int ad_stat(const char *path, struct stat *stbuf) if (!p) { return -1; } - - return stat( p, stbuf ); +//FIXME! + return lstat( p, stbuf ); } /* ---------------- @@ -1037,7 +1037,7 @@ static int ad_chown(const char *path, struct stat *stbuf) if (default_uid != (uid_t)-1) { /* we are root (admin) */ id = (default_uid)?default_uid:stbuf->st_uid; - ret = chown( path, id, stbuf->st_gid ); + ret = lchown( path, id, stbuf->st_gid ); } #endif return ret; @@ -1265,6 +1265,7 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble ad->ad_adflags = adflags; ad->ad_resource_fork.adf_refcount = 0; ad->ad_data_fork.adf_refcount = 0; + ad->ad_data_fork.adf_syml=0; } else { ad->ad_open_forks = ((ad->ad_data_fork.adf_refcount > 0) ? ATTRBIT_DOPEN : 0); @@ -1283,13 +1284,33 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble admode = mode; } } - ad->ad_data_fork.adf_fd =open( path, hoflags, admode ); + + ad->ad_data_fork.adf_fd =open( path, hoflags | O_NOFOLLOW, admode ); + if (ad->ad_data_fork.adf_fd < 0 ) { if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) { hoflags = oflags; - ad->ad_data_fork.adf_fd = open( path, hoflags, admode ); + ad->ad_data_fork.adf_fd = open( path, hoflags | O_NOFOLLOW, admode ); + } + if (ad->ad_data_fork.adf_fd < 0 && errno == ELOOP) { + int lsz; + + if (oflags != O_RDONLY) + return -1; + + ad->ad_data_fork.adf_syml = malloc(PATH_MAX+1); + lsz = readlink(path, ad->ad_data_fork.adf_syml, PATH_MAX); + if (lsz <= 0) { + free(ad->ad_data_fork.adf_syml); + return -1; + } + ad->ad_data_fork.adf_syml[lsz]=0; + ad->ad_data_fork.adf_syml = realloc(ad->ad_data_fork.adf_syml,lsz+1); + // XX + ad->ad_data_fork.adf_fd = 0; } } + if ( ad->ad_data_fork.adf_fd < 0) return -1; @@ -1349,11 +1370,11 @@ int ad_open( const char *path, int adflags, int oflags, int mode, struct adouble if (!(adflags & ADFLAGS_RDONLY)) { hoflags = (hoflags & ~(O_RDONLY | O_WRONLY)) | O_RDWR; } - ad->ad_md->adf_fd = open( ad_p, hoflags, 0 ); + ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 ); if (ad->ad_md->adf_fd < 0 ) { if ((errno == EACCES || errno == EROFS) && !(oflags & O_RDWR)) { hoflags = oflags & ~(O_CREAT | O_EXCL); - ad->ad_md->adf_fd = open( ad_p, hoflags, 0 ); + ad->ad_md->adf_fd = open( ad_p, hoflags | O_NOFOLLOW, 0 ); } } @@ -1618,7 +1639,7 @@ static int new_rfork(const char *path, struct adouble *ad, int adflags) memcpy(ad_entry(ad, ADEID_FINDERI) + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); } - if (stat(path, &st) < 0) { + if (lstat(path, &st) < 0) { return -1; } diff --git a/libatalk/adouble/ad_read.c b/libatalk/adouble/ad_read.c index 19d6218f..17c2361f 100644 --- a/libatalk/adouble/ad_read.c +++ b/libatalk/adouble/ad_read.c @@ -1,5 +1,5 @@ /* - * $Id: ad_read.c,v 1.9 2009-10-13 22:55:37 didg Exp $ + * $Id: ad_read.c,v 1.10 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -66,7 +66,16 @@ ssize_t ad_read( struct adouble *ad, const u_int32_t eid, off_t off, char *buf, /* We're either reading the data fork (and thus the data file) * or we're reading anything else (and thus the header file). */ if ( eid == ADEID_DFORK ) { - cc = adf_pread(&ad->ad_data_fork, buf, buflen, off); + if (ad->ad_data_fork.adf_syml !=0 ) { + /* It's a symlink, we already have the target in adf_syml */ + cc = strlen(ad->ad_data_fork.adf_syml); + if (buflen < cc) + /* Request buffersize is too small, force AFPERR_PARAM */ + return -1; + memcpy(buf, ad->ad_data_fork.adf_syml, cc); + } else { + cc = adf_pread(&ad->ad_data_fork, buf, buflen, off); + } } else { off_t r_off; diff --git a/libatalk/vfs/ea.c b/libatalk/vfs/ea.c index 8d1a1f0d..70d28106 100644 --- a/libatalk/vfs/ea.c +++ b/libatalk/vfs/ea.c @@ -1,5 +1,5 @@ /* - $Id: ea.c,v 1.18 2009-12-10 17:40:25 franklahm Exp $ + $Id: ea.c,v 1.19 2010-02-10 14:05:37 franklahm Exp $ Copyright (c) 2009 Frank Lahm This program is free software; you can redistribute it and/or modify @@ -1483,7 +1483,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN) } } - if ((chown(ea_path(&ea, NULL, 0), uid, gid)) != 0) { + if ((lchown(ea_path(&ea, NULL, 0), uid, gid)) != 0) { switch (errno) { case EPERM: case EACCES: @@ -1500,7 +1500,7 @@ int ea_chown(VFS_FUNC_ARGS_CHOWN) ret = AFPERR_MISC; goto exit; } - if ((chown(eaname, uid, gid)) != 0) { + if ((lchown(eaname, uid, gid)) != 0) { switch (errno) { case EPERM: case EACCES: diff --git a/libatalk/vfs/unix.c b/libatalk/vfs/unix.c index 35363049..991d04a0 100644 --- a/libatalk/vfs/unix.c +++ b/libatalk/vfs/unix.c @@ -1,5 +1,5 @@ /* - * $Id: unix.c,v 1.8 2010-01-26 08:14:09 didg Exp $ + * $Id: unix.c,v 1.9 2010-02-10 14:05:37 franklahm Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -80,19 +80,18 @@ int dir_rx_set(mode_t mode) int setfilmode(const char * name, mode_t mode, struct stat *st, mode_t v_umask) { struct stat sb; - mode_t result = mode; mode_t mask = S_IRWXU | S_IRWXG | S_IRWXO; /* rwx for owner group and other, by default */ if (!st) { - if (stat(name, &sb) != 0) + if (lstat(name, &sb) != 0) return -1; st = &sb; } - result |= st->st_mode & ~mask; /* keep other bits from previous mode */ - - LOG(log_debug, logtype_afpd, "setfilmode('%s', mode:%04o, vmask:%04o) {st_mode:%04o, chmod:%04o}", - fullpathname(name), mode, v_umask, st->st_mode, result); + if (S_ISLNK(st->st_mode)) + return 0; /* we don't want to change link permissions */ + + mode |= st->st_mode & ~mask; /* keep other bits from previous mode */ if ( chmod( name, mode & ~v_umask ) < 0 && errno != EPERM ) { return -1; -- 2.39.2