OPENAFS-SA-2016-002 AFSStoreStatus information leak
[openafs.git] / src / venus / afsio.c
index 3403cea..c9b04f2 100644 (file)
 
 #include <roken.h>
 
-#include <stdio.h>
 #ifdef AFS_NT40_ENV
 #include <windows.h>
 #define _CRT_RAND_S
-#include <process.h>
 #include <afs/smb_iocons.h>
 #include <afs/afsd.h>
 #include <afs/cm_ioctl.h>
 #include <afs/pioctl_nt.h>
 #include <WINNT/syscfg.h>
 #else
-#include <netdb.h>
 #include <afs/afsint.h>
 #define FSINT_COMMON_XG 1
 #endif
-#include <sys/stat.h>
+
+#include <afs/opr.h>
 #include <afs/cmd.h>
 #include <afs/auth.h>
 #include <afs/vlserver.h>
 #include <afs/ihandle.h>
 #include <afs/com_err.h>
 #include <afs/afscp.h>
-#ifdef HAVE_DIRENT_H
-#include <dirent.h>
-#endif
+
 #ifdef HAVE_DIRECT_H
 #include <direct.h>
 #endif
 #include <hcrypto/md5.h>
 #ifdef AFS_PTHREAD_ENV
-#include <assert.h>
 pthread_key_t uclient_key;
 #endif
 
@@ -80,10 +75,12 @@ static int CmdProlog(struct cmd_syndesc *, char **, char **,
 static int ScanFid(char *, struct AFSFid *);
 static afs_int32 GetVenusFidByFid(char *, char *, int, struct afscp_venusfid **);
 static afs_int32 GetVenusFidByPath(char *, char *, struct afscp_venusfid **);
-static int BreakUpPath(char *, char *, char *);
+static int BreakUpPath(char *, char **, char **);
 
 static char pnp[AFSPATHMAX];   /* filename of this program when called */
 static int verbose = 0;                /* Set if -verbose option given */
+static int clear = 0;          /* Set if -clear option given,
+                                  Unset if -crypt given; default is -crypt */
 static int cellGiven = 0;      /* Set if -cell option given */
 static int force = 0;          /* Set if -force option given */
 static int readlock = 0;       /* Set if -readlock option given */
@@ -190,6 +187,23 @@ summarizeMD5(char *fname)
            htonl(md5int[1]), htonl(md5int[2]), htonl(md5int[3]), p);
 } /* summarizeMD5 */
 
+#ifdef AFS_NT40_ENV
+static void
+ConvertAFSPath(char **fnp)
+{
+    char *p;
+
+    for (p = *fnp; *p; p++) {
+        if (*p == '\\')
+           *p = '/';
+    }
+
+    p = *fnp;
+    if (p[0] == '/' && p[1] == '/')
+        *fnp = p+1;
+}
+#endif /* AFS_NT40_ENV */
+
 /*!
  * parses all command-line arguments
  *
@@ -226,16 +240,24 @@ CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
        if (pdp->items != NULL) {
            if (strcmp(pdp->name, "-verbose") == 0)
                verbose = 1;
+           if (strcmp(pdp->name, "-clear") == 0)
+               clear = 1;
+           if (strcmp(pdp->name, "-crypt") == 0)
+               clear = 0;
             else if (strcmp(pdp->name, "-md5") == 0)
                md5sum = 1;     /* global */
             else if (strcmp(pdp->name, "-cell") == 0) {
                cellGiven = 1;  /* global */
                *cellp = pdp->items->data;
-            } else if ( (strcmp(pdp->name, "-file") == 0) ||
-                        (strcmp(pdp->name, "-fid") == 0) ||
-                        (strcmp(pdp->name, "-vnode") == 0) )
+            } else if ( strcmp(pdp->name, "-file") == 0) {
+               *fnp = pdp->items->data;
+#ifdef AFS_NT40_ENV
+                ConvertAFSPath(fnp);
+#endif /* AFS_NT40_ENV */
+            } else if ( (strcmp(pdp->name, "-fid") == 0) ||
+                        (strcmp(pdp->name, "-vnode") == 0) ) {
                *fnp = pdp->items->data;
-            else if (strcmp(pdp->name, "-force") == 0)
+            } else if (strcmp(pdp->name, "-force") == 0)
                force = 1;      /* global */
             else if (strcmp(pdp->name, "-synthesize") == 0)
                *slp = pdp->items->data;
@@ -253,85 +275,104 @@ CmdProlog(struct cmd_syndesc *as, char **cellp, char **realmp,
 int
 main(int argc, char **argv)
 {
-    afs_int32 code = 0;
     struct cmd_syndesc *ts;
-    char baseName[AFSNAMEMAX];
+    char *baseName;
+    int code;
 
     /* try to get only the base name of this executable for use in logs */
-    if (BreakUpPath(argv[0], NULL, baseName) > 0)
+#ifdef AFS_NT40_ENV
+    char *p = strdup(argv[0]);
+    ConvertAFSPath(&p);
+    code = BreakUpPath(p, NULL, &baseName);
+    free(p);
+#else
+    code = BreakUpPath(argv[0], NULL, &baseName);
+#endif
+    if (code > 0)
        strlcpy(pnp, baseName, AFSNAMEMAX);
     else
        strlcpy(pnp, argv[0], AFSPATHMAX);
+    free(baseName);
 
 #ifdef AFS_PTHREAD_ENV
-    assert(pthread_key_create(&uclient_key, NULL) == 0);
+    opr_Verify(pthread_key_create(&uclient_key, NULL) == 0);
 #endif
 
-    ts = cmd_CreateSyntax("lock", lockFile, (void *)LockWrite,
+    ts = cmd_CreateSyntax("lock", lockFile, (void *)LockWrite, 0,
                          "lock a file in AFS");
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_Seek(ts, 4);
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
     cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
     cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
 
-    ts = cmd_CreateSyntax("fidlock", lockFile, (void *)LockWrite,
+    ts = cmd_CreateSyntax("fidlock", lockFile, (void *)LockWrite, 0,
                          "lock by FID a file from AFS");
-    cmd_IsAdministratorCommand(ts);
     cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
                "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_Seek(ts, 4);
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
     cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
     cmd_AddParm(ts, "-readlock", CMD_FLAG, CMD_OPTIONAL, "read lock only");
 
-    ts = cmd_CreateSyntax("unlock", lockFile, (void *)LockRelease,
+    ts = cmd_CreateSyntax("unlock", lockFile, (void *)LockRelease, 0,
                          "unlock a file in AFS");
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_Seek(ts, 4);
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
     cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
 
-    ts = cmd_CreateSyntax("fidunlock", lockFile, (void *)LockRelease,
+    ts = cmd_CreateSyntax("fidunlock", lockFile, (void *)LockRelease, 0,
                          "unlock by FID a file from AFS");
-    cmd_IsAdministratorCommand(ts);
     cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
                "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_Seek(ts, 4);
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
     cmd_AddParm(ts, "-waitseconds", CMD_SINGLE, CMD_OPTIONAL, "seconds to wait before giving up");
 
-    ts = cmd_CreateSyntax("read", readFile, NULL,
+    ts = cmd_CreateSyntax("read", readFile, NULL, 0,
                          "read a file from AFS");
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("fidread", readFile, CMD_REQUIRED, 0,
                          "read on a non AFS-client a file from AFS");
-    cmd_IsAdministratorCommand(ts);
     cmd_AddParm(ts, "-fid", CMD_SINGLE, CMD_REQUIRED,
                "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("write", writeFile, NULL,
+    ts = cmd_CreateSyntax("write", writeFile, NULL, 0,
                          "write a file into AFS");
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
                "overwrite existing file");
@@ -339,38 +380,42 @@ main(int argc, char **argv)
                "create data pattern of specified length instead reading from stdin");
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED,
+    ts = cmd_CreateSyntax("fidwrite", writeFile, CMD_REQUIRED, 0,
                          "write a file into AFS");
-    cmd_IsAdministratorCommand(ts);
     cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
                "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-md5", CMD_FLAG, CMD_OPTIONAL, "calculate md5 checksum");
     cmd_AddParm(ts, "-force", CMD_FLAG, CMD_OPTIONAL,
                "overwrite existing file");
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("append", writeFile, NULL,
+    ts = cmd_CreateSyntax("append", writeFile, NULL, 0,
                          "append to a file in AFS");
     cmd_AddParm(ts, "-file", CMD_SINGLE, CMD_REQUIRED, "AFS-filename");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
-    ts = cmd_CreateSyntax("fidappend", writeFile, NULL,
+    ts = cmd_CreateSyntax("fidappend", writeFile, NULL, 0,
                          "append to a file in AFS");
-    cmd_IsAdministratorCommand(ts);
     cmd_AddParm(ts, "-vnode", CMD_SINGLE, CMD_REQUIRED,
                "volume.vnode.uniquifier");
     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cellname");
     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-clear", CMD_FLAG, CMD_OPTIONAL, (char *)0);
+    cmd_AddParm(ts, "-crypt", CMD_FLAG, CMD_OPTIONAL, (char *)0);
     cmd_AddParm(ts, "-realm", CMD_SINGLE, CMD_OPTIONAL, "REALMNAME");
 
     if (afscp_Init(NULL) != 0)
        exit(1);
 
-    code = cmd_Dispatch(argc, argv);
+    cmd_Dispatch(argc, argv);
 
     afscp_Finalize();
     exit(0);
@@ -436,13 +481,12 @@ GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
     struct afscp_volume *avolp;
 
     if (*avfpp == NULL) {
-       *avfpp = malloc(sizeof(struct afscp_venusfid));
+       *avfpp = calloc(1, sizeof(struct afscp_venusfid));
        if ( *avfpp == NULL ) {
            code = ENOMEM;
            return code;
        }
     }
-    memset(*avfpp, 0, sizeof(struct afscp_venusfid));
 
     if (cellName == NULL) {
        (*avfpp)->cell = afscp_DefaultCell();
@@ -500,22 +544,25 @@ GetVenusFidByFid(char *fidString, char *cellName, int onlyRW,
  * Split a full path up into dirName and baseName components
  *
  * \param[in]  fullPath        can be absolute, relative, or local
- * \param[out] dirName         pointer to allocated char buffer or NULL
- * \param[out] baseName        pointer to allocated char buffer or NULL
+ * \param[out] dirName         pointer to output string or NULL
+ * \param[out] baseName        pointer to output string or NULL
  *
- * \post To the fulleset extent possible, the rightmost full path
- *       component will be copied into baseName and all other
- *       components into dirName (minus the trailing path separator).
- *       If either dirName or baseName are NULL, only the non-NULL
- *       pointer will be filled in (but both can't be null or it would
- *       be pointless) -- so the caller can retrieve, say, only baseName
- *       if desired.  The return code is the number of strings copied:
+ * \post A buffer of appropriate size will be allocated into the output
+ *       parameter baseName and the rightmost full path component of the
+ *       fullPath copied into it; likewise, the other components of the
+ *       fullPath (minus the trailing path separator) will be placed into
+ *       the dirName output, which is also allocated to be the appropriate
+ *       size.  If either dirName or baseName are NULL, only the non-NULL
+ *       pointer will be allocated and filled in (but both can't be null
+ *       or it would be pointless) -- so the caller can retrieve, say,
+ *       only baseName if desired.  The return code is the number of
+ *       strings allocated and copied:
  *       0 if neither dirName nor baseName could be filled in
  *       1 if either dirName or baseName were filled in
  *       2 if both dirName and baseName were filled in
  */
 static int
-BreakUpPath(char *fullPath, char *dirName, char *baseName)
+BreakUpPath(char *fullPath, char **dirName, char **baseName)
 {
     char *lastSlash;
     size_t dirNameLen = 0;
@@ -525,36 +572,43 @@ BreakUpPath(char *fullPath, char *dirName, char *baseName)
        return code;
     }
 
+    /* Track what we need to output and initialize output variables to NULL. */
     if (dirName == NULL)
        useDirName = 0;
+    else
+       *dirName = NULL;
     if (baseName == NULL)
        useBaseName = 0;
+    else
+       *baseName = NULL;
     if (!useBaseName && !useDirName) {
        /* would be pointless to continue -- must be error in call */
        return code;
     }
-#ifdef AFS_NT40_ENV
-    lastSlash = strrchr(fullPath, '\\');
-#else
     lastSlash = strrchr(fullPath, '/');
-#endif
     if (lastSlash != NULL) {
        /* then lastSlash points to the last path separator in fullPath */
        if (useDirName) {
            dirNameLen = strlen(fullPath) - strlen(lastSlash);
-           strlcpy(dirName, fullPath, dirNameLen + 1);
-           code++;
+           *dirName = strdup(fullPath);
+           if (*dirName != NULL) {
+               code++;
+               /* Wastes some memory, but avoids needing libroken. */
+               *dirName[dirNameLen] = '\0';
+           }
        }
        if (useBaseName) {
            lastSlash++;
-           strlcpy(baseName, lastSlash, strlen(lastSlash) + 1);
-           code++;
+           *baseName = strdup(lastSlash);
+           if (*baseName != NULL)
+               code++;
        }
     } else {
        /* there are no path separators in fullPath -- it's just a baseName */
        if (useBaseName) {
-           strlcpy(baseName, fullPath, strlen(fullPath) + 1);
-           code++;
+           *baseName = strdup(fullPath);
+           if (*baseName != NULL)
+               code++;
        }
     }
     return code;
@@ -623,15 +677,17 @@ lockFile(struct cmd_syndesc *as, void *arock)
 
     CmdProlog(as, &cell, &realm, &fname, NULL);
     afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
 
     if ((locktype == LockWrite) && readlock)
        locktype = LockRead;
 
     if (realm != NULL)
-       code = afscp_SetDefaultRealm(realm);
+       afscp_SetDefaultRealm(realm);
 
     if (cell != NULL)
-       code = afscp_SetDefaultCell(cell);
+       afscp_SetDefaultCell(cell);
 
     if (useFid)
        code = GetVenusFidByFid(fname, cell, 0, &avfp);
@@ -639,6 +695,7 @@ lockFile(struct cmd_syndesc *as, void *arock)
        code = GetVenusFidByPath(fname, cell, &avfp);
     if (code != 0) {
        afs_com_err(pnp, code, "(file not found: %s)", fname);
+       afscp_FreeFid(avfp);
        return code;
     }
 
@@ -709,21 +766,24 @@ readFile(struct cmd_syndesc *as, void *unused)
 
     CmdProlog(as, &cell, &realm, &fname, NULL);
     afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
 
     if (md5sum)
        MD5_Init(&md5);
 
     if (realm != NULL)
-       code = afscp_SetDefaultRealm(realm);
+       afscp_SetDefaultRealm(realm);
 
     if (cell != NULL)
-       code = afscp_SetDefaultCell(cell);
+       afscp_SetDefaultCell(cell);
 
     if (useFid)
        code = GetVenusFidByFid(fname, cell, 0, &avfp);
     else
        code = GetVenusFidByPath(fname, cell, &avfp);
     if (code != 0) {
+       afscp_FreeFid(avfp);
        afs_com_err(pnp, code, "(file not found: %s)", fname);
        return code;
     }
@@ -752,14 +812,13 @@ readFile(struct cmd_syndesc *as, void *unused)
     Len <<= 32;
     Len += OutStatus.Length;
     ZeroInt64(Pos);
-    buf = (char *) malloc(bufflen * sizeof(char));
+    buf = calloc(bufflen, sizeof(char));
     if (buf == NULL) {
        code = ENOMEM;
        afs_com_err(pnp, code, "(cannot allocate buffer)");
        afscp_FreeFid(avfp);
        return code;
     }
-    memset(buf, 0, bufflen * sizeof(char));
     length = Len;
     while (!code && NonZeroInt64(length)) {
        if (length > bufflen)
@@ -811,35 +870,37 @@ writeFile(struct cmd_syndesc *as, void *unused)
     afs_int64 Pos;
     afs_int64 length, Len, synthlength = 0, offset = 0;
     afs_int64 bytes;
-    int worstCode = 0;
     int synthesize = 0;
     int overWrite = 0;
     struct wbuf *bufchain = 0;
     struct wbuf *previous, *tbuf;
-    char dirName[AFSPATHMAX];
-    char baseName[AFSNAMEMAX];
+    char *dirName = NULL;
+    char *baseName = NULL;
     char ipv4_addr[16];
 
 #ifdef AFS_NT40_ENV
     /* stdin on Windows defaults to _O_TEXT mode */
     _setmode(0, _O_BINARY);
 #endif
+    memset(&InStatus, 0, sizeof(InStatus));
 
     CmdProlog(as, &cell, &realm, &fname, &sSynthLen);
     afscp_AnonymousAuth(1);
+    if (clear)
+       afscp_Insecure();
 
     if (realm != NULL)
-       code = afscp_SetDefaultRealm(realm);
+       afscp_SetDefaultRealm(realm);
 
     if (cell != NULL)
-       code = afscp_SetDefaultCell(cell);
+       afscp_SetDefaultCell(cell);
 
     if (sSynthLen) {
        code = util_GetInt64(sSynthLen, &synthlength);
        if (code != 0) {
            afs_com_err(pnp, code, "(invalid value for synthesize length %s)",
                        sSynthLen);
-           return code;
+           goto cleanup;
        }
        synthesize = 1;
     }
@@ -848,7 +909,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
        code = GetVenusFidByFid(fname, cell, 1, &newvfp);
        if (code != 0) {
            afs_com_err(pnp, code, "(GetVenusFidByFid returned code %d)", code);
-           return code;
+           goto cleanup;
        }
     } else {
        code = GetVenusFidByPath(fname, cell, &newvfp);
@@ -861,23 +922,21 @@ writeFile(struct cmd_syndesc *as, void *unused)
                 * appending to it unless user forces overwrite
                 */
                code = EEXIST;
-               afscp_FreeFid(newvfp);
                afs_com_err(pnp, code, "(use -force to overwrite)");
-               return code;
+               goto cleanup;
            }
        } else { /* file not found */
            if (append) {
                code = ENOENT;
                afs_com_err(pnp, code, "(cannot append to non-existent file)");
-               return code;
+               goto cleanup;
            }
        }
        if (!append && !overWrite) { /* must create a new file in this case */
-           if ( BreakUpPath(fname, dirName, baseName) != 2 ) {
+           if ( BreakUpPath(fname, &dirName, &baseName) != 2 ) {
                code = EINVAL;
                afs_com_err(pnp, code, "(must provide full AFS path)");
-               afscp_FreeFid(newvfp);
-               return code;
+               goto cleanup;
            }
 
            code = GetVenusFidByPath(dirName, cell, &dirvfp);
@@ -885,7 +944,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
            newvfp = NULL;
            if (code != 0) {
                afs_com_err(pnp, code, "(is dir %s in AFS?)", dirName);
-               return code;
+               goto cleanup;
            }
        }
     }
@@ -893,9 +952,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
     if ( (newvfp != NULL) && (newvfp->fid.Vnode & 1) ) {
        code = EISDIR;
        afs_com_err(pnp, code, "(%s is a directory, not a file)", fname);
-       afscp_FreeFid(newvfp);
-       afscp_FreeFid(dirvfp);
-       return code;
+       goto cleanup;
     }
     gettimeofday(&starttime, &Timezone);
 
@@ -909,7 +966,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
                        baseName, afs_printable_uint32_lu(dirvfp->fid.Volume),
                        afs_printable_uint32_lu(dirvfp->fid.Vnode),
                        afs_printable_uint32_lu(dirvfp->fid.Unique));
-           return code;
+           goto cleanup;
        }
     }
     code = afscp_GetStatus(newvfp, &OutStatus);
@@ -917,9 +974,7 @@ writeFile(struct cmd_syndesc *as, void *unused)
        afs_inet_ntoa_r(newvfp->cell->fsservers[0]->addrs[0], ipv4_addr);
        afs_com_err(pnp, code, "(failed to get status of file %s from"
                    "server %s, code = %d)", fname, ipv4_addr, code);
-       afscp_FreeFid(newvfp);
-       afscp_FreeFid(dirvfp);
-       return code;
+       goto cleanup;
     }
 
     if ( !append && !force &&
@@ -930,10 +985,8 @@ writeFile(struct cmd_syndesc *as, void *unused)
         * (covers fidwrite edge case)
         */
        code = EEXIST;
-       afscp_FreeFid(newvfp);
-       afscp_FreeFid(dirvfp);
        afs_com_err(pnp, code, "(use -force to overwrite)");
-       return code;
+       goto cleanup;
     }
 
     if (append) {
@@ -956,18 +1009,15 @@ writeFile(struct cmd_syndesc *as, void *unused)
      */
     Len = 0;
     while (Len < WRITEBUFLEN) {
-       tbuf = (struct wbuf *)malloc(sizeof(struct wbuf));
+       tbuf = calloc(1, sizeof(struct wbuf));
        if (tbuf == NULL) {
            if (!bufchain) {
                code = ENOMEM;
-               afscp_FreeFid(newvfp);
-               afscp_FreeFid(dirvfp);
                afs_com_err(pnp, code, "(cannot allocate buffer)");
-               return code;
+               goto cleanup;
            }
            break;
        }
-       memset(tbuf, 0, sizeof(struct wbuf));
        tbuf->buflen = BUFFLEN;
        if (synthesize) {
            afs_int64 ll, l = tbuf->buflen;
@@ -1001,7 +1051,6 @@ writeFile(struct cmd_syndesc *as, void *unused)
     while (!code && bytes) {
        Len = bytes;
        length = Len;
-       tbuf = bufchain;
        if (Len) {
            for (tbuf = bufchain; tbuf; tbuf = tbuf->next) {
                if (tbuf->used == 0)
@@ -1048,8 +1097,6 @@ writeFile(struct cmd_syndesc *as, void *unused)
            }
        }
     }
-    afscp_FreeFid(newvfp);
-    afscp_FreeFid(dirvfp);
 
     gettimeofday(&writetime, &Timezone);
     if (code) {
@@ -1067,5 +1114,10 @@ writeFile(struct cmd_syndesc *as, void *unused)
     if (md5sum)
        summarizeMD5(fname);
 
-    return worstCode;
+cleanup:
+    free(baseName);
+    free(dirName);
+    afscp_FreeFid(newvfp);
+    afscp_FreeFid(dirvfp);
+    return code;
 } /* writeFile */