dread-do-validation-20041012
[openafs.git] / src / afs / afs_pioctl.c
index 05f5100..a8c3a3b 100644 (file)
@@ -88,6 +88,7 @@ DECL_PIOCTL(PRxStatProc);
 DECL_PIOCTL(PRxStatPeer);
 DECL_PIOCTL(PPrefetchFromTape);
 DECL_PIOCTL(PResidencyCmd);
+DECL_PIOCTL(PCallBackAddr);
 
 /*
  * A macro that says whether we're going to need HandleClientContext().
@@ -188,6 +189,7 @@ static int (*(CpioctlSw[])) () = {
     PBogus,                    /* 0 */
        PNewAlias,              /* 1 -- create new cell alias */
        PListAliases,           /* 2 -- list cell aliases */
+       PCallBackAddr,          /* 3 -- request addr for callback rxcon */
 };
 
 #define PSetClientContext 99   /*  Special pioctl to setup caller's creds  */
@@ -266,7 +268,13 @@ copyin_afs_ioctl(caddr_t cmarg, struct afs_ioctl *dst)
 #elif defined(AFS_AMD64_LINUX20_ENV)
     if (current->thread.flags & THREAD_IA32)
 #elif defined(AFS_PPC64_LINUX20_ENV)
-    if (current->thread.flags & PPC_FLAG_32BIT)
+#ifdef AFS_PPC64_LINUX26_ENV
+      if (current->thread_info->flags & _TIF_32BIT)
+#else /*Linux 2.6*/
+    if (current->thread.flags & PPC_FLAG_32BIT) 
+#endif
+#elif defined(AFS_S390X_LINUX20_ENV)
+    if (current->thread.flags & S390_FLAG_31BIT)
 #else
 #error Not done for this linux type
 #endif
@@ -484,7 +492,7 @@ struct afs_ioctl_sys {
     unsigned int com;
     unsigned long arg;
 };
-asmlinkage int
+int
 afs_xioctl(struct inode *ip, struct file *fp, unsigned int com,
           unsigned long arg)
 {
@@ -1049,6 +1057,8 @@ afs_syscall_pioctl(path, com, cmarg, follow)
 #endif
 }
 
+#define MAXPIOCTLTOKENLEN \
+(3*sizeof(afs_int32)+MAXKTCTICKETLEN+sizeof(struct ClearToken)+MAXKTCREALMLEN)
 
 int
 afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
@@ -1059,7 +1069,7 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     struct vrequest treq;
     register afs_int32 code;
     register afs_int32 function, device;
-    afs_int32 inSize, outSize;
+    afs_int32 inSize, outSize, outSizeMax;
     char *inData, *outData;
     int (*(*pioctlSw)) ();
     int pioctlSwSize;
@@ -1101,37 +1111,66 @@ afs_HandlePioctl(struct vnode *avp, afs_int32 acom,
     inSize = ablob->in_size;
 
     /* Do all range checking before continuing */
-    if (inSize >= PIGGYSIZE || inSize < 0 || ablob->out_size < 0)
+    if (inSize > MAXPIOCTLTOKENLEN || inSize < 0 || ablob->out_size < 0)
        return E2BIG;
 
-    inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    if (inSize > AFS_LRALLOCSIZ) {
+        inData = osi_AllocLargeSpace(inSize+1);
+    } else {
+        inData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    }
+    if (!inData)
+        return ENOMEM;
     if (inSize > 0) {
        AFS_COPYIN(ablob->in, inData, inSize, code);
        inData[inSize] = '\0';
     } else
        code = 0;
     if (code) {
-       osi_FreeLargeSpace(inData);
-       afs_PutFakeStat(&fakestate);
-       return code;
+    if (inSize > AFS_LRALLOCSIZ) {
+        osi_Free(inData, inSize+1);
+    } else {
+        osi_FreeLargeSpace(inData);
+    }
+    afs_PutFakeStat(&fakestate);
+    return code;
+    }
+    if (function == 8 && device == 'V') { /* PGetTokens */
+        outSizeMax = MAXPIOCTLTOKENLEN;
+        outData = osi_Alloc(outSizeMax);
+    } else {
+        outSizeMax = AFS_LRALLOCSIZ;
+        outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
+    }
+    if (!outData) {
+        if (inSize > AFS_LRALLOCSIZ) {
+            osi_Free(inData, inSize+1);
+        } else {
+            osi_FreeLargeSpace(inData);
+        }
+        return ENOMEM;
     }
-    outData = osi_AllocLargeSpace(AFS_LRALLOCSIZ);
     outSize = 0;
     code =
        (*pioctlSw[function]) (avc, function, &treq, inData, outData, inSize,
                               &outSize, acred);
-    osi_FreeLargeSpace(inData);
+    if (inSize > AFS_LRALLOCSIZ) {
+        osi_Free(inData, inSize+1);
+    } else {
+        osi_FreeLargeSpace(inData);
+    }
     if (code == 0 && ablob->out_size > 0) {
-       if (outSize > ablob->out_size)
-           outSize = ablob->out_size;
-       if (outSize >= PIGGYSIZE)
-           code = E2BIG;
-       else if (outSize) {
-           outData[outSize] = '\0';
-           AFS_COPYOUT(outData, ablob->out, outSize, code);
-       }
+        if (outSize > ablob->out_size) {
+            code = E2BIG; /* data wont fit in user buffer */
+        } else if (outSize) {
+            AFS_COPYOUT(outData, ablob->out, outSize, code);
+        }
+    }
+    if (outSizeMax > AFS_LRALLOCSIZ) {
+        osi_Free(outData, outSizeMax);
+    } else {
+        osi_FreeLargeSpace(outData);
     }
-    osi_FreeLargeSpace(outData);
     afs_PutFakeStat(&fakestate);
     return afs_CheckCode(code, &treq, 41);
 }
@@ -1382,10 +1421,8 @@ DECL_PIOCTL(PSetTokens)
     memcpy((char *)&i, ain, sizeof(afs_int32));
     ain += sizeof(afs_int32);
     stp = ain;                 /* remember where the ticket is */
-    if (i < 0 || i > 2000)
+    if (i < 0 || i > MAXKTCTICKETLEN)
        return EINVAL;          /* malloc may fail */
-    if (i > MAXKTCTICKETLEN)
-       return EINVAL;
     stLen = i;
     ain += i;                  /* skip over ticket */
     memcpy((char *)&i, ain, sizeof(afs_int32));
@@ -1544,32 +1581,43 @@ DECL_PIOCTL(PSetVolumeStatus)
     XSTATS_DECLS;
 
     AFS_STATCNT(PSetVolumeStatus);
-    if (!avc)
-       return EINVAL;
+    if (!avc) {
+       code = EINVAL;
+       goto out;
+    }
 
     tvp = afs_GetVolume(&avc->fid, areq, READ_LOCK);
     if (tvp) {
        if (tvp->states & (VRO | VBackup)) {
            afs_PutVolume(tvp, READ_LOCK);
-           return EROFS;
+           code = EROFS;
+           goto out;
        }
        afs_PutVolume(tvp, READ_LOCK);
-    } else
-       return ENODEV;
+    } else {
+       code = ENODEV;
+       goto out;
+    }
     /* Copy the junk out, using cp as a roving pointer. */
     cp = ain;
     memcpy((char *)&volstat, cp, sizeof(AFSFetchVolumeStatus));
     cp += sizeof(AFSFetchVolumeStatus);
-    if (strlen(cp) >= sizeof(volName))
-       return E2BIG;
+    if (strlen(cp) >= sizeof(volName)) {
+       code = E2BIG;
+       goto out;
+    }
     strcpy(volName, cp);
     cp += strlen(volName) + 1;
-    if (strlen(cp) >= sizeof(offLineMsg))
-       return E2BIG;
+    if (strlen(cp) >= sizeof(offLineMsg)) {
+       code = E2BIG;
+       goto out;
+    }
     strcpy(offLineMsg, cp);
     cp += strlen(offLineMsg) + 1;
-    if (strlen(cp) >= sizeof(motd))
-       return E2BIG;
+    if (strlen(cp) >= sizeof(motd)) {
+       code = E2BIG;
+       goto out;
+    }
     strcpy(motd, cp);
     storeStat.Mask = 0;
     if (volstat.MinQuota != -1) {
@@ -1669,7 +1717,7 @@ DECL_PIOCTL(PNewStatMount)
     Check_AtSys(avc, ain, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
-       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+       code = afs_dir_Lookup(&tdc->f, sysState.name, &tfid.Fid);
     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);                /* we're done with the data */
@@ -2349,7 +2397,7 @@ DECL_PIOCTL(PRemoveMount)
     Check_AtSys(avc, ain, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
-       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+       code = afs_dir_Lookup(&tdc->f, sysState.name, &tfid.Fid);
     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
     ReleaseReadLock(&tdc->lock);
     bufp = sysState.name;
@@ -2420,10 +2468,10 @@ DECL_PIOCTL(PRemoveMount)
        ObtainWriteLock(&tdc->lock, 661);
        if (afs_LocalHero(avc, tdc, &OutDirStatus, 1)) {
            /* we can do it locally */
-           code = afs_dir_Delete(&tdc->f.inode, bufp);
+           code = afs_dir_Delete(&tdc->f, bufp);
            if (code) {
                ZapDCE(tdc);    /* surprise error -- invalid value */
-               DZap(&tdc->f.inode);
+               DZap(&tdc->f);
            }
        }
        ReleaseWriteLock(&tdc->lock);
@@ -2643,13 +2691,13 @@ DECL_PIOCTL(PGetVnodeXStatus)
  /* for the reader.  */
 DECL_PIOCTL(PSetSysName)
 {
-    char *cp, inname[MAXSYSNAME], outname[MAXSYSNAME];
+    char *cp, *cp2, inname[MAXSYSNAME], outname[MAXSYSNAME];
     int setsysname, foundname = 0;
     register struct afs_exporter *exporter;
     register struct unixuser *au;
     register afs_int32 pag, error;
-    int t, count;
-
+    int t, count, num = 0;
+    char **sysnamelist[MAXSYSNAME];
 
     AFS_STATCNT(PSetSysName);
     if (!afs_globalVFS) {
@@ -2668,6 +2716,7 @@ DECL_PIOCTL(PSetSysName)
        /* Check my args */
        if (setsysname < 0 || setsysname > MAXNUMSYSNAMES)
            return EINVAL;
+       cp2 = ain;
        for (cp = ain, count = 0; count < setsysname; count++) {
            /* won't go past end of ain since maxsysname*num < ain length */
            t = strlen(cp);
@@ -2680,10 +2729,11 @@ DECL_PIOCTL(PSetSysName)
        }
        /* args ok */
 
-       /* inname gets first entry in case we're being a translater */
+       /* inname gets first entry in case we're being a translator */
        t = strlen(ain);
        memcpy(inname, ain, t + 1);     /* include terminating null */
        ain += t + 1;
+       num = count;
     }
     if ((*acred)->cr_gid == RMTUSER_REQ) {     /* Handles all exporters */
        pag = PagInCred(*acred);
@@ -2697,7 +2747,8 @@ DECL_PIOCTL(PSetSysName)
            afs_PutUser(au, READ_LOCK);
            return EINVAL;      /* Better than panicing */
        }
-       error = EXP_SYSNAME(exporter, (setsysname ? inname : NULL), outname);
+       error = EXP_SYSNAME(exporter, (setsysname ? cp2 : NULL), sysnamelist,
+                           &num);
        if (error) {
            if (error == ENODEV)
                foundname = 0;  /* sysname not set yet! */
@@ -2705,17 +2756,19 @@ DECL_PIOCTL(PSetSysName)
                afs_PutUser(au, READ_LOCK);
                return error;
            }
-       } else
-           foundname = 1;
+       } else {
+            foundname = num;
+            strcpy(outname, (*sysnamelist)[0]);
+       }
        afs_PutUser(au, READ_LOCK);
     } else {
-
        /* Not xlating, so local case */
        if (!afs_sysname)
            osi_Panic("PSetSysName: !afs_sysname\n");
        if (!setsysname) {      /* user just wants the info */
            strcpy(outname, afs_sysname);
            foundname = afs_sysnamecount;
+           *sysnamelist = afs_sysnamelist;
        } else {                /* Local guy; only root can change sysname */
            if (!afs_osi_suser(*acred))
                return EACCES;
@@ -2746,14 +2799,13 @@ DECL_PIOCTL(PSetSysName)
            strcpy(cp, outname);        /* ... the entry, ... */
            cp += strlen(outname) + 1;
            for (count = 1; count < foundname; ++count) {       /* ... or list. */
-               /* Note: we don't support @sys lists for exporters */
-               if (!afs_sysnamelist[count])
+               if (!(*sysnamelist)[count])
                    osi_Panic
                        ("PSetSysName: no afs_sysnamelist entry to read\n");
-               t = strlen(afs_sysnamelist[count]);
+               t = strlen((*sysnamelist)[count]);
                if (t >= MAXSYSNAME)
                    osi_Panic("PSetSysName: sysname entry garbled\n");
-               strcpy(cp, afs_sysnamelist[count]);
+               strcpy(cp, (*sysnamelist)[count]);
                cp += t + 1;
            }
        }
@@ -3451,7 +3503,7 @@ DECL_PIOCTL(PFlushMount)
     Check_AtSys(avc, ain, &sysState, areq);
     ObtainReadLock(&tdc->lock);
     do {
-       code = afs_dir_Lookup(&tdc->f.inode, sysState.name, &tfid.Fid);
+       code = afs_dir_Lookup(&tdc->f, sysState.name, &tfid.Fid);
     } while (code == ENOENT && Next_AtSys(avc, areq, &sysState));
     ReleaseReadLock(&tdc->lock);
     afs_PutDCache(tdc);                /* we're done with the data */
@@ -3700,3 +3752,100 @@ DECL_PIOCTL(PResidencyCmd)
     }
     return code;
 }
+
+DECL_PIOCTL(PCallBackAddr)
+{
+#ifndef UKERNEL
+    afs_uint32 addr, code;
+    int srvAddrCount;
+    struct server *ts;
+    struct srvAddr *sa;
+    struct conn *tc;
+    afs_int32 i, j;
+    struct unixuser *tu;
+    struct srvAddr **addrs;
+
+    /*AFS_STATCNT(PCallBackAddr);*/
+    if ( !afs_resourceinit_flag )      /* afs deamons havn't started yet */
+       return EIO;          /* Inappropriate ioctl for device */
+
+    if (!afs_osi_suser(acred))
+       return EACCES;
+
+    if ( ainSize < sizeof(afs_int32) )
+       return EINVAL;
+
+    memcpy(&addr, ain, sizeof(afs_int32));
+
+    ObtainReadLock(&afs_xinterface);
+    for ( i=0; (unsigned short)i < afs_cb_interface.numberOfInterfaces; i++) {
+       if (afs_cb_interface.addr_in[i] == addr) break;
+    }
+
+    ReleaseWriteLock(&afs_xinterface);
+
+    if (afs_cb_interface.addr_in[i] != addr)
+       return EINVAL;
+
+    ObtainReadLock(&afs_xserver);  /* Necessary? */
+    ObtainReadLock(&afs_xsrvAddr);
+
+    srvAddrCount = 0;
+    for (i=0;i<NSERVERS;i++) {
+        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
+            srvAddrCount++;
+        }
+    }
+
+    addrs = afs_osi_Alloc(srvAddrCount * sizeof(*addrs));
+    j = 0;
+    for (i=0;i<NSERVERS;i++) {
+        for (sa = afs_srvAddrs[i]; sa; sa = sa->next_bkt) {
+            if (j >= srvAddrCount) break;
+            addrs[j++] = sa;
+        }
+    }
+
+    ReleaseReadLock(&afs_xsrvAddr);
+    ReleaseReadLock(&afs_xserver);
+
+    for (i=0; i<j; i++) {
+        sa = addrs[i];
+        ts = sa->server;
+        if (!ts)
+            continue;
+
+        /* vlserver has no callback conn */
+        if (sa->sa_portal == AFS_VLPORT) {
+            continue;
+        }
+
+        if (!ts->cell) /* not really an active server, anyway, it must */
+           continue;  /* have just been added by setsprefs */
+
+        /* get a connection, even if host is down; bumps conn ref count */
+        tu = afs_GetUser(areq->uid, ts->cell->cellNum, SHARED_LOCK);
+        tc = afs_ConnBySA(sa, ts->cell->fsport, ts->cell->cellNum, tu,
+                         1/*force*/, 1/*create*/, SHARED_LOCK);
+        afs_PutUser(tu, SHARED_LOCK);
+        if (!tc)
+           continue;
+
+        if ((sa->sa_flags & SRVADDR_ISDOWN) || afs_HaveCallBacksFrom(ts)) {
+            if (sa->sa_flags & SRVADDR_ISDOWN) {
+                rx_SetConnDeadTime(tc->id, 3);
+            }
+
+#ifdef RX_ENABLE_LOCKS
+            AFS_GUNLOCK();
+#endif /* RX_ENABLE_LOCKS */
+           code = RXAFS_CallBackRxConnAddr(tc->id, &addr);
+#ifdef RX_ENABLE_LOCKS
+            AFS_GLOCK();
+#endif /* RX_ENABLE_LOCKS */
+       }
+       afs_PutConn(tc, SHARED_LOCK);   /* done with it now */
+    } /* Outer loop over addrs */
+#endif /* UKERNEL */
+    return 0;
+}