do-bounds-checking-in-psetvolumestatus-20010315
[openafs.git] / src / afs / afs_pioctl.c
index 5688d72..2044147 100644 (file)
@@ -44,6 +44,7 @@ extern afs_rwlock_t afs_xcbhash;
 extern afs_int32 afs_mariner, afs_marinerHost;
 extern struct srvAddr *afs_srvAddrs[NSERVERS];
 extern int afs_resourceinit_flag;
+extern afs_int32 cryptall;
 
 static int PBogus(), PSetAcl(), PGetAcl(), PSetTokens(), PGetVolumeStatus();
 static int PSetVolumeStatus(), PFlush(), PNewStatMount(), PGetTokens(), PUnlog();
@@ -59,6 +60,8 @@ static int PSetSPrefs(), PGetSPrefs(), PGag(), PTwiddleRx();
 static int PSetSPrefs33(), PStoreBehind(), PGCPAGs();
 static int PGetCPrefs(), PSetCPrefs(); /* client network addresses */
 static int PGetInitParams(), PFlushMount(), PRxStatProc(), PRxStatPeer();
+static int PGetRxkcrypt(), PSetRxkcrypt();
+static int PPrefetchFromTape(), PResidencyCmd();
 int PExportAfs();
 
 static int HandleClientContext(struct afs_ioctl *ablob, int *com, struct AFS_UCRED **acred, struct AFS_UCRED *credp);
@@ -121,6 +124,19 @@ static int (*(pioctlSw[]))() = {
   PFlushMount,                 /* 52 - flush mount symlink data */
   PRxStatProc,                 /* 53 - control process RX statistics */
   PRxStatPeer,                 /* 54 - control peer RX statistics */
+  PGetRxkcrypt,                        /* 55 -- Get rxkad encryption flag */
+  PSetRxkcrypt,                        /* 56 -- Set rxkad encryption flag */
+  PNoop,                       /* 57 -- arla: set file prio */
+  PNoop,                       /* 58 -- arla: fallback getfh */
+  PNoop,                       /* 59 -- arla: fallback fhopen */
+  PNoop,                       /* 60 -- arla: controls xfsdebug */
+  PNoop,                       /* 61 -- arla: controls arla debug */
+  PNoop,                       /* 62 -- arla: debug interface */
+  PNoop,                       /* 63 -- arla: print xfs status */
+  PNoop,                       /* 64 -- arla: force cache check */
+  PNoop,                       /* 65 -- arla: break callback */
+  PPrefetchFromTape,            /* 66 -- MR-AFS: prefetch file from tape */
+  PResidencyCmd,                /* 67 -- MR-AFS: generic commnd interface */
 };
 
 #define PSetClientContext 99   /*  Special pioctl to setup caller's creds  */
@@ -180,6 +196,21 @@ copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
        }
 #endif /* defined(AFS_SGI_ENV) && (_MIPS_SZLONG==64) */
 
+#if defined(AFS_LINUX_64BIT_KERNEL)
+       struct afs_ioctl32 dst32;
+
+#ifdef AFS_SPARC64_LINUX20_ENV
+       if (current->tss.flags & SPARC_FLAG_32BIT) {
+#else
+#error Not done for this linux type
+#endif
+               AFS_COPYIN(cmarg, (caddr_t) &dst32, sizeof dst32, code);
+               if (!code)
+                       afs_ioctl32_to_afs_ioctl(&dst32, dst);
+               return code;
+       }
+#endif /* defined(AFS_LINUX_64BIT_KERNEL) */
+
        AFS_COPYIN(cmarg, (caddr_t) dst, sizeof *dst, code);
        return code;
 }
@@ -792,7 +823,7 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #ifdef AFS_LINUX22_ENV
        code = gop_lookupname(path, AFS_UIOUSER, follow,  (struct vnode **) 0, &dp);
        if (!code)
-           vp = (struct vcache *)dp->d_inode;
+           vp = (struct vnode *)dp->d_inode;
 #else
        code = gop_lookupname(path, AFS_UIOUSER, follow,  (struct vnode **) 0, &vp);
 #endif /* AFS_LINUX22_ENV */
@@ -1471,10 +1502,16 @@ static PSetVolumeStatus(avc, afun, areq, ain, aout, ainSize, aoutSize)
     cp = ain;
     bcopy(cp, (char *)&volstat, sizeof(AFSFetchVolumeStatus));
     cp += sizeof(AFSFetchVolumeStatus);
+    if (strlen(cp) >= sizeof(volName))
+       return E2BIG;
     strcpy(volName, cp);
     cp += strlen(volName)+1;
+    if (strlen(cp) >= sizeof(offLineMsg))
+       return E2BIG;
     strcpy(offLineMsg, cp);
     cp +=  strlen(offLineMsg)+1;
+    if (strlen(cp) >= sizeof(motd))
+       return E2BIG;
     strcpy(motd, cp);
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
@@ -1942,14 +1979,14 @@ struct AFS_UCRED *acred;
 
     AFS_STATCNT(Prefetch);
     if (!apath) return EINVAL;
-    tp = osi_AllocSmallSpace(AFS_SMALLOCSIZ);
+    tp = osi_AllocLargeSpace(1024);
     AFS_COPYINSTR(apath, tp, 1024, &bufferSize, code);
     if (code) {
-       osi_FreeSmallSpace(tp);
+       osi_FreeLargeSpace(tp);
        return code;
     }
     if (afs_BBusy()) { /* do this as late as possible */
-       osi_FreeSmallSpace(tp);
+       osi_FreeLargeSpace(tp);
        return EWOULDBLOCK;     /* pretty close */
     }
     afs_BQueue(BOP_PATH, (struct vcache*)0, 0, 0, acred, (long)tp, 0L, 0L, 0L);
@@ -2421,6 +2458,8 @@ struct AFS_UCRED *acred;
     afs_int32 cell, volume;
 
     AFS_STATCNT(PFlushVolumeData);
+    if (!avc)
+       return EINVAL;
     if ( !afs_resourceinit_flag )      /* afs deamons havn't started yet */
        return EIO;          /* Inappropriate ioctl for device */
 
@@ -2751,7 +2790,7 @@ static int afs_setsprefs(sp, num, vlonly)
       /* Note that it doesn't have a cell yet...     */
       if (!matches) {
         afs_uint32 temp = sp->host.s_addr;
-        srvr = afs_GetServer(&temp, 1, NULL, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
+        srvr = afs_GetServer(&temp, 1, 0, (vlonly ? AFS_VLPORT : AFS_FSPORT), 
                              WRITE_LOCK, (afsUUID *)0,0);
         srvr->addr->sa_iprank = sp->rank + afs_randomMod15();
         afs_PutServer(srvr, WRITE_LOCK);
@@ -3104,6 +3143,46 @@ static cred_t *crget(void)
     return cr;
 }
 #endif
+
+static int
+PGetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
+struct vcache *avc;
+int afun;
+struct vrequest *areq;
+char *ain, *aout;
+afs_int32 ainSize;
+afs_int32 *aoutSize;
+struct AFS_UCRED *acred;
+{
+    bcopy((char *)&cryptall, aout, sizeof(afs_int32));
+    *aoutSize=sizeof(afs_int32);
+    return 0;
+}
+
+static int
+PSetRxkcrypt(avc, afun, areq, ain, aout, ainSize, aoutSize, acred)
+struct vcache *avc;
+int afun;
+struct vrequest *areq;
+char *ain, *aout;
+afs_int32 ainSize;
+afs_int32 *aoutSize;
+struct AFS_UCRED *acred;
+{
+    afs_int32 tmpval;
+
+    if (!afs_osi_suser(acred))
+      return EPERM;
+    if (ainSize != sizeof(afs_int32) || ain == NULL)
+      return EINVAL;
+    bcopy(ain, (char *)&tmpval, sizeof(afs_int32));
+    /* if new mappings added later this will need to be changed */
+    if (tmpval != 0 && tmpval != 1)
+      return EINVAL;
+    cryptall = tmpval;
+    return 0;
+}
+
 /*
  * Create new credentials to correspond to a remote user with given
  * <hostaddr, uid, g0, g1>.  This allows a server running as root to
@@ -3316,8 +3395,10 @@ afs_int32 *aoutSize;
 
        if ( ainSize < sizeof(struct setspref) )
                return EINVAL;
+#if 0  /* num_servers is unsigned */
        if ( sin->num_servers < 0 )
                return EINVAL;
+#endif
        if ( sin->num_servers > AFS_MAX_INTERFACE_ADDR)
                return ENOMEM;
 
@@ -3483,3 +3564,163 @@ out:
     return code;
 }
 
+static PPrefetchFromTape(avc, afun, areq, ain, aout, ainSize, aoutSize)
+  struct vcache *avc;
+  int afun;
+  struct vrequest *areq;
+  char *ain, *aout;
+  afs_int32 ainSize;
+  afs_int32 *aoutSize;  /* set this */
+{
+    register afs_int32 code, code1;
+    afs_int32 bytes;
+    struct conn *tc;
+    struct rx_call *tcall;
+    struct AFSVolSync tsync;
+    struct AFSFetchStatus OutStatus;
+    struct AFSCallBack CallBack;
+    struct VenusFid tfid;
+    struct AFSFid *Fid;
+    struct vcache *tvc;
+    XSTATS_DECLS;
+
+    AFS_STATCNT(PSetAcl);
+    if (!avc)
+      return EINVAL;
+
+    if (ain && (ainSize == 3 * sizeof(afs_int32)))
+        Fid = (struct AFSFid *) ain;
+    else
+        Fid = &avc->fid.Fid;
+    tfid.Cell = avc->fid.Cell;
+    tfid.Fid.Volume = Fid->Volume;
+    tfid.Fid.Vnode = Fid->Vnode;
+    tfid.Fid.Unique = Fid->Unique;
+
+    tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
+                                WRITE_LOCK);
+    if (!tvc) {
+        afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
+                ICL_TYPE_POINTER, tvc,
+                ICL_TYPE_FID, &tfid,
+                ICL_TYPE_FID, &avc->fid);
+        return ENOENT;
+    }
+    afs_Trace3(afs_iclSetp, CM_TRACE_PREFETCHCMD,
+                ICL_TYPE_POINTER, tvc,
+                ICL_TYPE_FID, &tfid,
+                ICL_TYPE_FID, &tvc->fid);
+
+    do {
+        tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+        if (tc) {
+
+#ifdef RX_ENABLE_LOCKS
+            AFS_GUNLOCK();
+#endif /* RX_ENABLE_LOCKS */
+            tcall = rx_NewCall(tc->id);
+            code = StartRXAFS_FetchData(tcall,
+                                (struct AFSFid *) &tvc->fid.Fid, 0, 0);
+            if (!code) {
+                bytes = rx_Read(tcall, (char *) aout, sizeof(afs_int32));
+                code = EndRXAFS_FetchData(tcall, &OutStatus, &CallBack, &tsync);
+            }
+            code1 = rx_EndCall(tcall, code);
+#ifdef RX_ENABLE_LOCKS
+            AFS_GLOCK();
+#endif /* RX_ENABLE_LOCKS */
+        } else
+            code = -1;
+    } while
+        (afs_Analyze(tc, code, &tvc->fid, areq, 
+               AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK, 
+               (struct cell *)0));
+    /* This call is done only to have the callback things handled correctly */
+    afs_FetchStatus(tvc, &tfid, areq, &OutStatus);
+    afs_PutVCache(tvc, WRITE_LOCK);
+
+    if (!code) {
+        *aoutSize = sizeof(afs_int32);
+    }
+    return code;
+}
+
+static PResidencyCmd(avc, afun, areq, ain, aout, ainSize, aoutSize)
+struct vcache *avc;
+int afun;
+struct vrequest *areq;
+char *ain, *aout;
+afs_int32 ainSize;
+afs_int32 *aoutSize;        /* set this */
+{
+    register afs_int32 code;
+    struct conn *tc;
+    struct vcache *tvc;
+    struct ResidencyCmdInputs *Inputs;
+    struct ResidencyCmdOutputs *Outputs;
+    struct VenusFid tfid;
+    struct AFSFid *Fid;
+
+    Inputs = (struct ResidencyCmdInputs *) ain;
+    Outputs = (struct ResidencyCmdOutputs *) aout;
+    if (!avc) return EINVAL;
+    if (!ain || ainSize != sizeof(struct ResidencyCmdInputs)) return EINVAL;
+
+    Fid = &Inputs->fid;
+    if (!Fid->Volume)
+        Fid = &avc->fid.Fid;
+
+    tfid.Cell = avc->fid.Cell;
+    tfid.Fid.Volume = Fid->Volume;
+    tfid.Fid.Vnode = Fid->Vnode;
+    tfid.Fid.Unique = Fid->Unique;
+
+    tvc = afs_GetVCache(&tfid, areq, (afs_int32 *)0, (struct vcache *)0,
+                                WRITE_LOCK);
+    afs_Trace3(afs_iclSetp, CM_TRACE_RESIDCMD,
+                ICL_TYPE_POINTER, tvc,
+                ICL_TYPE_INT32, Inputs->command,
+                ICL_TYPE_FID, &tfid);
+    if (!tvc)
+        return ENOENT;
+
+    if (Inputs->command) {
+        do {
+            tc = afs_Conn(&tvc->fid, areq, SHARED_LOCK);
+            if (tc) {
+#ifdef RX_ENABLE_LOCKS
+                AFS_GUNLOCK();
+#endif /* RX_ENABLE_LOCKS */
+                code = RXAFS_ResidencyCmd(tc->id, Fid,
+                                 Inputs,
+                                 (struct ResidencyCmdOutputs *) aout);
+#ifdef RX_ENABLE_LOCKS
+                AFS_GLOCK();
+#endif /* RX_ENABLE_LOCKS */
+            } else
+                code = -1;
+        } while
+          (afs_Analyze(tc, code, &tvc->fid, areq, 
+               AFS_STATS_FS_RPCIDX_RESIDENCYRPCS, SHARED_LOCK,
+                (struct cell *)0));
+       /* This call is done to have the callback things handled correctly */
+       afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
+    } else { /* just a status request, return also link data */
+        code = 0;
+        Outputs->code = afs_FetchStatus(tvc, &tfid, areq, &Outputs->status);
+        Outputs->chars[0] = 0;
+        if (vType(tvc) == VLNK) {
+            ObtainWriteLock(&tvc->lock,555);
+            if (afs_HandleLink(tvc, areq) == 0)
+                strncpy((char *) &Outputs->chars, tvc->linkData, MAXCMDCHARS);
+            ReleaseWriteLock(&tvc->lock);
+        }
+    }
+
+    afs_PutVCache(tvc, WRITE_LOCK);
+
+    if (!code) {
+        *aoutSize = sizeof(struct ResidencyCmdOutputs);
+    }
+    return code;
+}