]> arthur.barton.de Git - netatalk.git/commitdiff
bugfix file.c directory.c: open directory descriptor leak, buffer overflow if
authordidg <didg>
Sun, 26 Jan 2003 10:42:40 +0000 (10:42 +0000)
committerdidg <didg>
Sun, 26 Jan 2003 10:42:40 +0000 (10:42 +0000)
path > MAX_PATH.
fork.c rename a function, keep afp_xxx only for AFP calls.

etc/afpd/directory.c
etc/afpd/directory.h
etc/afpd/file.c
etc/afpd/fork.c

index 260dca07f32bb2a91095e8b6e0c58fa72a4334b3..dbb0e65a06a1d0ef302e41a1a35a7cbdce78548a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.c,v 1.58 2003-01-24 07:08:42 didg Exp $
+ * $Id: directory.c,v 1.59 2003-01-26 10:42:40 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -550,6 +550,79 @@ struct path *path;
     return( dir );
 }
 
+/* -------------------
+   system rmdir with afp error code.
+   ENOENT is not an error.
+ */
+static 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.
+*/
+static int netatalk_mkdir(const char *name)
+{
+    if (ad_mkdir(name, DIRBITS | 0777) < 0) {
+        switch ( errno ) {
+        case ENOENT :
+            return( AFPERR_NOOBJ );
+        case EROFS :
+            return( AFPERR_VLOCK );
+        case EPERM:
+        case EACCES :
+            return( AFPERR_ACCESS );
+        case EEXIST :
+            return( AFPERR_EXIST );
+        case ENOSPC :
+        case EDQUOT :
+            return( AFPERR_DFULL );
+        default :
+            return( AFPERR_PARAM );
+        }
+    }
+    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)
 {
     char path[MAXPATHLEN + 1];
@@ -557,9 +630,10 @@ static int deletedir(char *dir)
     struct dirent      *de;
     struct stat st;
     size_t len;
-    int err;
+    int err = AFP_OK;
+    size_t remain;
 
-    if ((len = strlen(dir)) > sizeof(path))
+    if ((len = strlen(dir)) +2 > sizeof(path))
         return AFPERR_PARAM;
 
     /* already gone */
@@ -569,57 +643,34 @@ static int deletedir(char *dir)
     strcpy(path, dir);
     strcat(path, "/");
     len++;
-    while ((de = readdir(dp))) {
+    remain = sizeof(path) -len -1;
+    while ((de = readdir(dp)) && err == AFP_OK) {
         /* skip this and previous directory */
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
             continue;
 
-        strncpy(path + len, de->d_name, sizeof(path) - len);
-        if (stat(path, &st) == 0) {
-            if (S_ISDIR(st.st_mode)) {
-                if ((err = deletedir(path)) < 0) {
-                    closedir(dp);
-                    return err;
-                }
-            } else if (unlink(path) < 0) {
-                switch (errno) {
-                case ENOENT :
-                    continue; /* somebody went and deleted it behind our backs. */
-                case EROFS:
-                    err = AFPERR_VLOCK;
-                    break;
-                case EPERM:
-                case EACCES :
-                    err = AFPERR_ACCESS;
-                    break;
-                default :
-                    err = AFPERR_PARAM;
-                }
-                closedir(dp);
-                return err;
-            }
+        if (strlen(de->d_name) > remain) {
+            err = AFPERR_PARAM;
+            break;
+        }
+        strcpy(path + len, de->d_name);
+        if (stat(path, &st)) {
+            continue;
+        }
+        if (S_ISDIR(st.st_mode)) {
+            err = deletedir(path);
+        } else {
+            err = netatalk_unlink(path);
         }
     }
     closedir(dp);
 
     /* okay. the directory is empty. delete it. note: we already got rid
        of .AppleDouble.  */
-    if (rmdir(dir) < 0) {
-        switch ( errno ) {
-        case ENOENT :
-            break;
-        case ENOTEMPTY : /* should never happen */
-            return( AFPERR_DIRNEMPT );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EROFS:
-            return AFPERR_VLOCK;
-        default :
-            return( AFPERR_PARAM );
-        }
+    if (err == AFP_OK) {
+        err = netatalk_rmdir(dir);
     }
-    return AFP_OK;
+    return err;
 }
 
 /* do a recursive copy. */
@@ -631,6 +682,8 @@ static int copydir(char *src, char *dst, int noadouble)
     struct stat st;
     struct utimbuf      ut;
     size_t slen, dlen;
+    size_t srem, drem;
+    
     int err;
 
     /* doesn't exist or the path is too long. */
@@ -640,47 +693,45 @@ static int copydir(char *src, char *dst, int noadouble)
         return AFPERR_PARAM;
 
     /* try to create the destination directory */
-    if (ad_mkdir(dst, DIRBITS | 0777) < 0) {
+    if (AFP_OK != (err = netatalk_mkdir(dst)) ) {
         closedir(dp);
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EROFS :
-            return( AFPERR_VLOCK );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EEXIST :
-            return( AFPERR_EXIST );
-        case ENOSPC :
-        case EDQUOT :
-            return( AFPERR_DFULL );
-        default :
-            return( AFPERR_PARAM );
-        }
+        return err;
     }
 
     /* set things up to copy */
     strcpy(spath, src);
     strcat(spath, "/");
     slen++;
+    srem = sizeof(spath) - slen -1;
+    
     strcpy(dpath, dst);
     strcat(dpath, "/");
     dlen++;
+    drem = sizeof(dpath) - dlen -1;
+
     err = AFP_OK;
     while ((de = readdir(dp))) {
         /* skip this and previous directory */
         if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
             continue;
 
-        strncpy(spath + slen, de->d_name, sizeof(spath) - slen);
+        if (strlen(de->d_name) > srem) {
+            err = AFPERR_PARAM;
+            break;
+        }
+        strcpy(spath + slen, de->d_name);
+
         if (stat(spath, &st) == 0) {
-            strncpy(dpath + dlen, de->d_name, sizeof(dpath) - dlen);
+            if (strlen(de->d_name) > drem) {
+                err = AFPERR_PARAM;
+                break;
+            }
+            strcpy(dpath + dlen, de->d_name);
 
             if (S_ISDIR(st.st_mode)) {
-                if ((err = copydir(spath, dpath, noadouble)) < 0)
+                if (AFP_OK != (err = copydir(spath, dpath, noadouble)))
                     goto copydir_done;
-            } else if ((err = copyfile(spath, dpath, NULL, noadouble)) < 0) {
+            } else if (AFP_OK != (err = copyfile(spath, dpath, NULL, noadouble))) {
                 goto copydir_done;
 
             } else {
@@ -1691,7 +1742,8 @@ int               ibuflen, *rbuflen;
     struct path         *s_path;
     u_int32_t          did;
     u_int16_t          vid;
-
+    int                 err;
+    
     *rbuflen = 0;
     ibuf += 2;
 
@@ -1718,29 +1770,12 @@ int             ibuflen, *rbuflen;
         return AFPERR_EXIST;
 
     upath = s_path->u_name;
-    {
-    int ret;
-        if (0 != (ret = check_name(vol, upath))) {
-            return  ret;
-        }
+    if (0 != (err = check_name(vol, upath))) {
+       return err;
     }
 
-    if ( ad_mkdir( upath, DIRBITS | 0777 ) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case EROFS :
-            return( AFPERR_VLOCK );
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EEXIST :
-            return( AFPERR_EXIST );
-        case ENOSPC :
-        case EDQUOT :
-            return( AFPERR_DFULL );
-        default :
-            return( AFPERR_PARAM );
-        }
+    if (AFP_OK != (err = netatalk_mkdir( upath))) {
+        return err;
     }
 
     if (of_stat(s_path) < 0) {
@@ -1882,6 +1917,7 @@ int pathlen;
     DIR *dp;
     struct adouble     ad;
     u_int16_t          ashort;
+    int err;
 
     if ( curdir->d_parent == NULL ) {
         return( AFPERR_ACCESS );
@@ -1921,38 +1957,16 @@ int pathlen;
             }
 
             strcpy(path + DOT_APPLEDOUBLE_LEN, de->d_name);
-            if (unlink(path) < 0) {
+            if ((err = netatalk_unlink(path))) {
                 closedir(dp);
-                switch (errno) {
-                case EPERM:
-                case EACCES :
-                    return( AFPERR_ACCESS );
-                case EROFS:
-                    return AFPERR_VLOCK;
-                case ENOENT :
-                    continue;
-                default :
-                    return( AFPERR_PARAM );
-                }
+                return err;
             }
         }
         closedir(dp);
     }
 
-    if ( rmdir( ".AppleDouble" ) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            break;
-        case ENOTEMPTY :
-            return( AFPERR_DIRNEMPT );
-        case EROFS:
-            return AFPERR_VLOCK;
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        default :
-            return( AFPERR_PARAM );
-        }
+    if ( (err = netatalk_rmdir( ".AppleDouble" ))  ) {
+       return err;
     }
 
     /* now get rid of dangling symlinks */
@@ -1964,21 +1978,13 @@ int pathlen;
 
             /* bail if it's not a symlink */
             if ((lstat(de->d_name, &st) == 0) && !S_ISLNK(st.st_mode)) {
+               closedir(dp);
                 return AFPERR_DIRNEMPT;
             }
 
-            if (unlink(de->d_name) < 0) {
-                switch (errno) {
-                case EPERM:
-                case EACCES :
-                    return( AFPERR_ACCESS );
-                case EROFS:
-                    return AFPERR_VLOCK;
-                case ENOENT :
-                    continue;
-                default :
-                    return( AFPERR_PARAM );
-                }
+            if ((err = netatalk_unlink(de->d_name))) {
+               closedir(dp);
+               return err;
             }
         }
         closedir(dp);
@@ -1988,20 +1994,8 @@ int pathlen;
         return afp_errno;
     }
 
-    if ( rmdir(fdir->d_u_name) < 0 ) {
-        switch ( errno ) {
-        case ENOENT :
-            return( AFPERR_NOOBJ );
-        case ENOTEMPTY :
-            return( AFPERR_DIRNEMPT );
-        case EPERM:
-        case EACCES :
-            return( AFPERR_ACCESS );
-        case EROFS:
-            return AFPERR_VLOCK;
-        default :
-            return( AFPERR_PARAM );
-        }
+    if ( (err = netatalk_rmdir(fdir->d_u_name))) {
+        return err;
     }
 
     dirchildremove(curdir, fdir);
index 81345dd7222558495f3bb37aca0fd1e4ea3fe3ef..f978c340d6d3f8f125cbe039d7fc50d6664be9c7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: directory.h,v 1.9 2003-01-24 07:08:42 didg Exp $
+ * $Id: directory.h,v 1.10 2003-01-26 10:42:40 didg Exp $
  *
  * Copyright (c) 1990,1991 Regents of The University of Michigan.
  * All Rights Reserved.
@@ -202,6 +202,8 @@ extern int  for_each_dirent __P((const struct vol *, char *, dir_loop , void *))
 
 extern int  check_access __P((char *name , int mode));
 
+extern int netatalk_unlink __P((const char *name));
+
 /* from enumerate.c */
 extern char *check_dirent __P((const struct vol *, char *));
 
index 08fae3ff63a298512e0e14b2c2a075c28f518f32..ec2252dc70979222969f1f827eb268f7a7d3033f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: file.c,v 1.78 2003-01-24 12:42:31 didg Exp $
+ * $Id: file.c,v 1.79 2003-01-26 10:42:40 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -1441,44 +1441,11 @@ int         checkAttrib;
 
     if (ad_tmplock( &ad, ADEID_DFORK, locktype, 0, 0, 0 ) < 0) {
         err = AFPERR_BUSY;
-        goto delete_unlock;
     }
-
-    if ( unlink( ad_path( file, ADFLAGS_HF )) < 0 ) {
-        switch ( errno ) {
-        case EPERM:
-        case EACCES :
-            err = AFPERR_ACCESS;
-            goto delete_unlock;
-        case EROFS:
-            err = AFPERR_VLOCK;
-            goto delete_unlock;
-        case ENOENT :
-            break;
-        default :
-            err = AFPERR_PARAM;
-            goto delete_unlock;
-        }
-    }
-
-    if ( unlink( file ) < 0 ) {
-        switch ( errno ) {
-        case EPERM:
-        case EACCES :
-            err = AFPERR_ACCESS;
-            break;
-        case EROFS:
-            err = AFPERR_VLOCK;
-            break;
-        case ENOENT :
-            break;
-        default :
-            err = AFPERR_PARAM;
-            break;
-        }
+    else if ( 0 == (err = netatalk_unlink( ad_path( file, ADFLAGS_HF )) )) {
+        err = netatalk_unlink( file );
     }
 
-delete_unlock:
     if (adflags & ADFLAGS_HF)
         ad_tmplock(&ad, ADEID_RFORK, ADLOCK_CLR |ADLOCK_FILELOCK, 0, 0, 0);
     ad_tmplock(&ad, ADEID_DFORK, ADLOCK_CLR, 0, 0, 0);
index c8684e1d9d10d5a1cbd48e3a9dab0e56911bf727..5cdde3cd5f3ffebb2a9f14575fdae1dead99ee01 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: fork.c,v 1.45 2003-01-16 21:18:15 didg Exp $
+ * $Id: fork.c,v 1.46 2003-01-26 10:42:40 didg Exp $
  *
  * Copyright (c) 1990,1993 Regents of The University of Michigan.
  * All Rights Reserved.  See COPYRIGHT.
@@ -184,7 +184,7 @@ static int getforkmode(struct adouble *adp, int eid, int what)
     return ad_testlock(adp, eid,  what);
 }
 
-static int afp_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
+static int fork_setmode(struct adouble *adp, int eid, int access, int ofrefnum)
 {
     int ret;
     int readset;
@@ -484,7 +484,7 @@ int         ibuflen, *rbuflen;
     /* don't try to lock non-existent rforks. */
     if ((eid == ADEID_DFORK) || (ad_hfileno(ofork->of_ad) != -1)) {
 
-        ret = afp_setmode(ofork->of_ad, eid, access, ofrefnum);
+        ret = fork_setmode(ofork->of_ad, eid, access, ofrefnum);
         /* can we access the fork? */
         if (ret < 0) {
             ret = errno;