afs: Replace strcpy &co by safer alternatives
[openafs.git] / src / afs / VNOPS / afs_vnop_lookup.c
index 2a84a5d..db9de71 100644 (file)
@@ -484,33 +484,43 @@ afs_ENameOK(char *aname)
 
 static int
 afs_getsysname(struct vrequest *areq, struct vcache *adp,
-              char *bufp, int *num, char **sysnamelist[])
+              char *bufp, size_t bufsize, int *num, char **sysnamelist[])
 {
-    struct unixuser *au;
-    afs_int32 error;
+    struct unixuser *au = NULL;
+    afs_int32 error, code = -1;
+    size_t rlen;
 
     AFS_STATCNT(getsysname);
 
     *sysnamelist = afs_sysnamelist;
 
-    if (!afs_nfsexporter)
-       strcpy(bufp, (*sysnamelist)[0]);
-    else {
+    if (!afs_nfsexporter) {
+       rlen = strlcpy(bufp, (*sysnamelist)[0], bufsize);
+       if (rlen >= bufsize)
+           goto done;
+    } else {
        au = afs_GetUser(areq->uid, adp->f.fid.Cell, READ_LOCK);
        if (au->exporter) {
            error = EXP_SYSNAME(au->exporter, (char *)0, sysnamelist, num, 0);
            if (error) {
-               strcpy(bufp, "@sys");
-               afs_PutUser(au, READ_LOCK);
-               return -1;
+               strlcpy(bufp, "@sys", bufsize);
+               goto done;
            } else {
-               strcpy(bufp, (*sysnamelist)[0]);
+               rlen = strlcpy(bufp, (*sysnamelist)[0], bufsize);
+               if (rlen >= bufsize)
+                   goto done;
            }
-       } else
-           strcpy(bufp, afs_sysname);
-       afs_PutUser(au, READ_LOCK);
+       } else {
+           rlen = strlcpy(bufp, afs_sysname, bufsize);
+           if (rlen >= bufsize)
+               goto done;
+       }
     }
-    return 0;
+    code = 0;
+ done:
+    if (au != NULL)
+       afs_PutUser(au, READ_LOCK);
+    return code;
 }
 
 void
@@ -525,7 +535,8 @@ Check_AtSys(struct vcache *avc, const char *aname,
        state->name_size = MAXSYSNAME;
        state->name = osi_AllocLargeSpace(state->name_size);
        state->index =
-           afs_getsysname(areq, avc, state->name, &num, sysnamelist);
+           afs_getsysname(areq, avc, state->name, state->name_size, &num,
+                          sysnamelist);
     } else {
        state->offset = -1;
        state->name_size = 0;
@@ -539,7 +550,8 @@ Next_AtSys(struct vcache *avc, struct vrequest *areq,
           struct sysname_info *state)
 {
     int num = afs_sysnamecount;
-    char **sysnamelist[MAXNUMSYSNAMES];
+    char **sysnamelist[MAXNUMSYSNAMES], *buf;
+    size_t bsz;
 
     if (state->index == -1)
        return 0;               /* No list */
@@ -553,15 +565,35 @@ Next_AtSys(struct vcache *avc, struct vrequest *areq,
            /*Move to the end of the string */ ;
 
        if ((tname > state->name + 4) && (AFS_EQ_ATSYS(tname - 4))) {
-           state->offset = (tname - 4) - state->name;
-           tname = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
-           strncpy(tname, state->name, state->offset);
-           state->name = tname;
-           state->name_size = AFS_LRALLOCSIZ;
+           int idx;
+           size_t len, bufsize = AFS_LRALLOCSIZ;
+
+           len = (tname - 4) - state->name;
+           if (len >= bufsize) {
+               return 0;
+           }
+
+           tname = osi_AllocLargeSpace(bufsize);
+           /* intentionally truncating state->name */
+           strlcpy(tname, state->name, len + 1);
+
+           buf = tname + len;
+           bsz = bufsize - len;
            num = 0;
-           state->index =
-               afs_getsysname(areq, avc, state->name + state->offset, &num,
-                              sysnamelist);
+           idx = afs_getsysname(areq, avc, buf, bsz, &num, sysnamelist);
+           if (idx == -1) {
+               osi_FreeLargeSpace(tname);
+               return 0;
+           }
+           /*
+            * If we got here, state->name isn't pointing to any dynamically
+            * allocated memory. In other words, state->name_size must be 0.
+            */
+           state->name = tname;
+           state->offset = len;
+           state->name_size = bufsize;
+           state->index = idx;
+
            return 1;
        } else
            return 0;           /* .*@sys doesn't match either */
@@ -586,7 +618,16 @@ Next_AtSys(struct vcache *avc, struct vrequest *areq,
        if (++(state->index) >= num || !(*sysnamelist)[(unsigned int)state->index])
            return 0;           /* end of list */
     }
-    strcpy(state->name + state->offset, (*sysnamelist)[(unsigned int)state->index]);
+    /*
+     * If we got here, state->name was allocated by the AtSys iterator. In other
+     * words, state->name_size must be greater than 0.
+     */
+    buf = state->name + state->offset;
+    bsz = state->name_size - state->offset;
+    if (strlcpy(buf, (*sysnamelist)[(unsigned int)state->index], bsz) >= bsz) {
+       state->index = -1;
+       return 0;
+    }
     return 1;
 }