From 70802b37037b2bae7c696a1282d4d3fd623475ef Mon Sep 17 00:00:00 2001 From: Jeff Riegel Date: Sat, 23 Jun 2001 18:01:03 +0000 Subject: [PATCH] afs-web-interface-enhancements-20010623 Changes include: 1) Token caching: Functions to set the current "PAG" (not really a process authentication group, but a generic identifier for a user session) to a specific value, allowing us to switch tokens between different threads of the Web server without reauthenticating. 2) Performance enhancements: The main improvement is that we can check whether a directory is a mount point in advance and avoid doing a stat or contacting the destination cell. We've also enabled bulk statting with kolya's patch from 11/2000. 3) New UAFS API's to call various pioctl functions, etc. enclosed in AFS_WEB_ENHANCEMENTS ifdef --- src/afs/UKERNEL/afs_usrops.c | 230 ++++++++++++++++++++++++++++++-- src/afs/UKERNEL/afs_usrops.h | 3 +- src/afs/UKERNEL/sysincludes.h | 4 + src/afs/VNOPS/afs_vnop_access.c | 25 ++++ src/afs/VNOPS/afs_vnop_lookup.c | 20 ++- src/afs/afs_osi_pag.c | 148 +++++++++++++++++++- 6 files changed, 412 insertions(+), 18 deletions(-) diff --git a/src/afs/UKERNEL/afs_usrops.c b/src/afs/UKERNEL/afs_usrops.c index 0c1e9eb2a..cea99e629 100644 --- a/src/afs/UKERNEL/afs_usrops.c +++ b/src/afs/UKERNEL/afs_usrops.c @@ -637,7 +637,7 @@ struct usr_vnode **compvpp; struct usr_inode *ip; struct usr_vnode *vp; - usr_assert(followlink == 0); + /*usr_assert(followlink == 0);*/ usr_assert(dirvpp == NULL); /* @@ -645,7 +645,7 @@ struct usr_vnode **compvpp; */ if (*fnamep != '/' || uafs_afsPathName(fnamep) != NULL) { AFS_GLOCK(); - code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0); + code = uafs_LookupName(fnamep, afs_CurrentDir, compvpp, 0, 0); AFS_GUNLOCK(); return code; } @@ -2174,7 +2174,8 @@ int uafs_LookupName( char *path, struct usr_vnode *parentVp, struct usr_vnode **vpp, - int follow) + int follow, + int no_eval_mtpt) { int code; int linkCount; @@ -2251,7 +2252,14 @@ int uafs_LookupName( * subdirectory since we hold the global lock */ nextVp = NULL; - code = afs_lookup(vp, pathP, &nextVp, u.u_cred); +#ifdef AFS_WEB_ENHANCEMENTS + if ((nextPathP != NULL && *nextPathP != '\0') || !no_eval_mtpt) + code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0); + else + code = afs_lookup(vp, pathP, &nextVp, u.u_cred, AFS_LOOKUP_NOEVAL); +#else + code = afs_lookup(vp, pathP, &nextVp, u.u_cred, 0); +#endif /* AFS_WEB_ENHANCEMENTS */ if (code != 0) { VN_RELE(vp); afs_osi_Free(tmpPath, strlen(path)+1); @@ -2353,7 +2361,7 @@ int uafs_LookupLink( /* * Find the target of the symbolic link */ - code = uafs_LookupName(pathP, parentVp, &linkVp, 1); + code = uafs_LookupName(pathP, parentVp, &linkVp, 1, 0); if (code) { afs_osi_Free(pathP, MAX_OSI_PATH+1); return code; @@ -2417,7 +2425,7 @@ int uafs_LookupParent( /* * look up the parent */ - code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1); + code = uafs_LookupName(pathP, afs_CurrentDir, &parentP, 1, 0); afs_osi_Free(pathP, len); if (code != 0) { return code; @@ -2471,7 +2479,7 @@ int uafs_chdir_r( int code; struct vnode *dirP; - code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1); + code = uafs_LookupName(path, afs_CurrentDir, &dirP, 1, 0); if (code != 0) { errno = code; return -1; @@ -2661,7 +2669,7 @@ int uafs_open_r( } } else { fileP = NULL; - code = uafs_LookupName(nameP, dirP, &fileP, 1); + code = uafs_LookupName(nameP, dirP, &fileP, 1, 0); VN_RELE(dirP); if (code != 0) { errno = code; @@ -2974,7 +2982,7 @@ int uafs_stat_r( int code; struct vnode *vp; - code = uafs_LookupName(path, afs_CurrentDir, &vp, 1); + code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0); if (code != 0) { errno = code; return -1; @@ -3009,7 +3017,7 @@ int uafs_lstat_r( int code; struct vnode *vp; - code = uafs_LookupName(path, afs_CurrentDir, &vp, 0); + code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0); if (code != 0) { errno = code; return -1; @@ -3080,7 +3088,7 @@ int uafs_chmod_r( struct vnode *vp; struct usr_vattr attrs; - code = uafs_LookupName(path, afs_CurrentDir, &vp, 1); + code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0); if (code != 0) { errno = code; return -1; @@ -3155,7 +3163,7 @@ int uafs_truncate_r( struct vnode *vp; struct usr_vattr attrs; - code = uafs_LookupName(path, afs_CurrentDir, &vp, 1); + code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0); if (code != 0) { errno = code; return -1; @@ -3367,7 +3375,7 @@ int uafs_link_r( /* * Look up the existing node. */ - code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1); + code = uafs_LookupName(existing, afs_CurrentDir, &existP, 1, 0); if (code != 0) { errno = code; return -1; @@ -3508,7 +3516,7 @@ int uafs_readlink_r( struct usr_uio uio; struct iovec iov[1]; - code = uafs_LookupName(path, afs_CurrentDir, &vp, 0); + code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 0); if (code != 0) { errno = code; return -1; @@ -3808,6 +3816,7 @@ usr_DIR *uafs_opendir_r( char *path) { usr_DIR *dirp; + struct usr_vnode *fileP; int fd; /* @@ -3818,6 +3827,17 @@ usr_DIR *uafs_opendir_r( return NULL; } + fileP = afs_FileTable[fd]; + if (fileP == NULL) { + return NULL; + } + + if (fileP->v_type != VDIR) { + uafs_close_r(fd); + errno = ENOTDIR; + return NULL; + } + /* * Set up the directory structures */ @@ -4108,4 +4128,186 @@ char *uafs_afsPathName(char *path) return NULL; } +#ifdef AFS_WEB_ENHANCEMENTS +/* + * uafs_klog_nopag + * klog but don't allocate a new pag + */ +int uafs_klog_nopag( + char *user, + char *cell, + char *passwd, + char **reason) +{ + int code; + afs_int32 password_expires = -1; + + usr_mutex_lock(&osi_authenticate_lock); + code = ka_UserAuthenticateGeneral( + KA_USERAUTH_VERSION /*+KA_USERAUTH_DOSETPAG2*/, user, + NULL, cell, passwd, 0, &password_expires, + 0, reason); + usr_mutex_unlock(&osi_authenticate_lock); + return code; +} + +/* + * uafs_getcellstatus + * get the cell status + */ +int uafs_getcellstatus(char *cell, afs_int32 *status) +{ + int rc; + struct afs_ioctl iob; + + iob.in = cell; + iob.in_size = strlen(cell)+1; + iob.out = 0; + iob.out_size = 0; + + rc = call_syscall(AFSCALL_PIOCTL, /*path*/0, _VICEIOCTL(35), + (long)&iob, 0, 0); + + if (rc < 0) { + errno = rc; + return -1; + } + + *status = iob.out; + return 0; +} + +/* + * uafs_getvolquota + * Get quota of volume associated with path + */ +int uafs_getvolquota(char *path, afs_int32 *BlocksInUse, afs_int32 *MaxQuota) +{ + int rc; + struct afs_ioctl iob; + VolumeStatus *status; + char buf[1024]; + + iob.in = 0; + iob.in_size = 0; + iob.out = buf; + iob.out_size = 1024; + + rc = call_syscall(AFSCALL_PIOCTL, path, _VICEIOCTL(4), + (long)&iob, 0, 0); + + if (rc != 0) { + errno = rc; + return -1; + } + + status = (VolumeStatus *) buf; + *BlocksInUse = status->BlocksInUse; + *MaxQuota = status->MaxQuota; + return 0; +} + +/* + * uafs_setvolquota + * Set quota of volume associated with path + */ +int uafs_setvolquota(char *path, afs_int32 MaxQuota) +{ + int rc; + struct afs_ioctl iob; + VolumeStatus *status; + char buf[1024]; + + iob.in = buf; + iob.in_size = 1024; + iob.out = 0; + iob.out_size = 0; + + memset(buf, 0, sizeof(VolumeStatus)); + status = (VolumeStatus *) buf; + status->MaxQuota = MaxQuota; + status->MinQuota = -1; + + rc = call_syscall(AFSCALL_PIOCTL, path, _VICEIOCTL(5), + (long)&iob, 0, 0); + + if (rc != 0) { + errno = rc; + return -1; + } + + return 0; +} + +/* + * uafs_statmountpoint + * Determine whether a dir. is a mount point or not + * return 1 if mount point, 0 if not + */ +int uafs_statmountpoint(char *path) +{ + int retval; + int code; + char buf[256]; + + AFS_GLOCK(); + retval = uafs_statmountpoint_r(path); + AFS_GUNLOCK(); + return retval; +} + +int uafs_statmountpoint_r(char *path) +{ + int code; + struct vnode *vp; + struct vcache *avc; + struct vrequest treq; + int r; + + code = uafs_LookupName(path, afs_CurrentDir, &vp, 0, 1); + if (code != 0) { + errno = code; + return -1; + } + + avc = (struct vcache *) vp; + + r = avc->mvstat; + VN_RELE(vp); + return r; +} + +/* + * uafs_getRights + * Get a list of rights for the current user on path. + */ +int uafs_getRights(char *path) +{ + int code, rc; + struct vnode *vp; + int afs_rights; + + AFS_GLOCK(); + code = uafs_LookupName(path, afs_CurrentDir, &vp, 1, 0); + if (code != 0) { + errno = code; + AFS_GUNLOCK(); + return -1; + } + + afs_rights = PRSFS_READ | + PRSFS_WRITE | + PRSFS_INSERT | + PRSFS_LOOKUP | + PRSFS_DELETE | + PRSFS_LOCK | + PRSFS_ADMINISTER; + + afs_rights = afs_getRights (vp, afs_rights, u.u_cred); + + AFS_GUNLOCK(); + return afs_rights; +} +#endif /* AFS_WEB_ENHANCEMENTS */ + #endif /* UKERNEL */ diff --git a/src/afs/UKERNEL/afs_usrops.h b/src/afs/UKERNEL/afs_usrops.h index 97923964c..0ef5fe6e4 100644 --- a/src/afs/UKERNEL/afs_usrops.h +++ b/src/afs/UKERNEL/afs_usrops.h @@ -74,7 +74,8 @@ extern void uafs_RxServerProc(void); extern int uafs_LookupLink(struct usr_vnode *vp, struct usr_vnode *parentP, struct usr_vnode **vpp); extern int uafs_LookupName(char *path, struct usr_vnode *parentP, - struct usr_vnode **vpp, int follow); + struct usr_vnode **vpp, int follow, + int no_eval_mtpt); extern int uafs_LookupParent(char *path, struct usr_vnode **vpp); extern int uafs_GetAttr(struct usr_vnode *vp, struct stat *stats); diff --git a/src/afs/UKERNEL/sysincludes.h b/src/afs/UKERNEL/sysincludes.h index 367b6e20b..7ff6254fe 100644 --- a/src/afs/UKERNEL/sysincludes.h +++ b/src/afs/UKERNEL/sysincludes.h @@ -932,6 +932,8 @@ extern pthread_cond_t usr_sleep_cond; #define usr_cond_signal(A) assert(pthread_cond_signal(A) == 0) #define usr_cond_broadcast(A) assert(pthread_cond_broadcast(A) == 0) #define usr_cond_wait(A,B) pthread_cond_wait(A,B) +#define usr_cond_timedwait(A,B,C) pthread_cond_timedwait(A,B,C) + #define usr_thread_create(A,B,C) \ do { \ pthread_attr_t attr; \ @@ -1378,4 +1380,6 @@ typedef struct { extern unsigned short usr_rx_port; +#define AFS_LOOKUP_NOEVAL 1 + #endif /* __AFS_SYSINCLUDESH__ so idempotent */ diff --git a/src/afs/VNOPS/afs_vnop_access.c b/src/afs/VNOPS/afs_vnop_access.c index 2b4de1a27..2c3f6af9c 100644 --- a/src/afs/VNOPS/afs_vnop_access.c +++ b/src/afs/VNOPS/afs_vnop_access.c @@ -273,3 +273,28 @@ afs_access(OSI_VC_ARG(avc), amode, acred) } } +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) +/* + * afs_getRights + * This function is just an interface to afs_GetAccessBits + */ +int afs_getRights(OSI_VC_ARG(avc), arights, acred) + OSI_VC_DECL(avc); + register afs_int32 arights; + struct AFS_UCRED *acred; +{ + register afs_int32 code; + struct vrequest treq; + OSI_VC_CONVERT(avc) + + if (code = afs_InitReq(&treq, acred)) return code; + + code = afs_VerifyVCache(avc, &treq); + if (code) { + code = afs_CheckCode(code, &treq, 16); + return code; + } + + return afs_GetAccessBits(avc, arights, &treq); +} +#endif /* defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) */ diff --git a/src/afs/VNOPS/afs_vnop_lookup.c b/src/afs/VNOPS/afs_vnop_lookup.c index 93980d2e6..a1f22b246 100644 --- a/src/afs/VNOPS/afs_vnop_lookup.c +++ b/src/afs/VNOPS/afs_vnop_lookup.c @@ -866,8 +866,13 @@ afs_lookup(OSI_VC_ARG(adp), aname, avcp, pnp, flags, rdir, acred) int flags; struct vnode *rdir; #else +#if defined(UKERNEL) +afs_lookup(adp, aname, avcp, acred, flags) + int flags; +#else afs_lookup(adp, aname, avcp, acred) -#endif +#endif /* UKERNEL */ +#endif /* SUN5 || SGI */ OSI_VC_DECL(adp); struct vcache **avcp; char *aname; @@ -1152,6 +1157,11 @@ afs_lookup(adp, aname, avcp, acred) tvc->parentVnode = adp->fid.Fid.Vnode; tvc->parentUnique = adp->fid.Fid.Unique; tvc->states &= ~CBulkStat; + +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) + if (!(flags & AFS_LOOKUP_NOEVAL)) + /* don't eval mount points */ +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ if (tvc->mvstat == 1) { /* a mt point, possibly unevaluated */ struct volume *tvolp; @@ -1260,6 +1270,14 @@ done: if (afs_mariner) afs_AddMarinerName(aname, tvc); + +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) + if (!(flags & AFS_LOOKUP_NOEVAL)) + /* Here we don't enter the name into the DNLC because we want the + evaluated mount dir to be there (the vcache for the mounted volume) + rather than the vc of the mount point itself. we can still find the + mount point's vc in the vcache by its fid. */ +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ if (!hit) { osi_dnlc_enter (adp, aname, tvc, &versionNo); } diff --git a/src/afs/afs_osi_pag.c b/src/afs/afs_osi_pag.c index a1b6cec7e..8c833ea6e 100644 --- a/src/afs/afs_osi_pag.c +++ b/src/afs/afs_osi_pag.c @@ -33,7 +33,11 @@ extern int afs_shuttingdown; /* Exported variables */ afs_uint32 pag_epoch; +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) +afs_uint32 pagCounter = 1; +#else afs_uint32 pagCounter = 0; +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ /* Local variables */ @@ -61,14 +65,15 @@ afs_uint32 pagCounter = 0; * anyway, so the pag is an alternative handle which is somewhat more * secure (although of course not absolutely secure). */ +#if !defined(UKERNEL) || !defined(AFS_WEB_ENHANCEMENTS) afs_uint32 genpag(void) { AFS_STATCNT(genpag); #ifdef AFS_LINUX20_ENV /* Ensure unique PAG's (mod 200 days) when reloading the client. */ return (('A' << 24) + ((pag_epoch + pagCounter++) & 0xffffff)); -#else +#else /* AFS_LINUX20_ENV */ return (('A' << 24) + (pagCounter++ & 0xffffff)); -#endif +#endif /* AFS_LINUX20_ENV */ } afs_uint32 getpag(void) { @@ -81,6 +86,30 @@ afs_uint32 getpag(void) { #endif } +#else + +/* Web enhancement: we don't need to restrict pags to 41XXXXXX since + * we are not sharing the space with anyone. So we use the full 32 bits. */ + +afs_uint32 genpag(void) { + AFS_STATCNT(genpag); +#ifdef AFS_LINUX20_ENV + return (pag_epoch + pagCounter++); +#else + return (pagCounter++); +#endif /* AFS_LINUX20_ENV */ +} + +afs_uint32 getpag(void) { + AFS_STATCNT(getpag); +#ifdef AFS_LINUX20_ENV + /* Ensure unique PAG's (mod 200 days) when reloading the client. */ + return (pag_epoch + pagCounter); +#else + return (pagCounter); +#endif +} +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ /* used to require 10 seconds between each setpag to guarantee that * PAGs never wrap - which would be a security hole. If we presume @@ -182,6 +211,115 @@ afs_setpag (void) #endif } +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) +/* + * afs_setpag_val + * This function is like setpag but sets the current thread's pag id to a + * caller-provided value instead of calling genpag(). This implements a + * form of token caching since the caller can recall a particular pag value + * for the thread to restore tokens, rather than reauthenticating. + */ +int +#if defined(AFS_SUN5_ENV) +afs_setpag_val (struct AFS_UCRED **credpp, int pagval) +#elif defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) +afs_setpag_val (struct proc *p, void *args, int *retval, int pagval) +#else +afs_setpag_val (int pagval) +#endif +{ + int code = 0; + +#if defined(AFS_SGI53_ENV) && defined(MP) + /* This is our first chance to get the global lock. */ + AFS_GLOCK(); +#endif /* defined(AFS_SGI53_ENV) && defined(MP) */ + + AFS_STATCNT(afs_setpag); +#ifdef AFS_SUN5_ENV + if (!afs_suser(*credpp)) +#else + if (!afs_suser()) +#endif + { + while (osi_Time() - pag_epoch < pagCounter ) { + afs_osi_Wait(1000, (struct afs_osi_WaitHandle *) 0, 0); + } + } + +#if defined(AFS_SUN5_ENV) + code = AddPag(pagval, credpp); +#elif defined(AFS_OSF_ENV) || defined(AFS_FBSD_ENV) + code = AddPag(p, pagval, &p->p_rcred); +#elif defined(AFS_AIX41_ENV) + { + struct ucred *credp; + struct ucred *credp0; + + credp = crref(); + credp0 = credp; + code = AddPag(pagval, &credp); + /* If AddPag() didn't make a new cred, then free our cred ref */ + if (credp == credp0) { + crfree(credp); + } + } +#elif defined(AFS_HPUX110_ENV) + { + struct ucred *credp = p_cred(u.u_procp); + code = AddPag(pagval, &credp); + } +#elif defined(AFS_SGI_ENV) + { + cred_t *credp; + credp = OSI_GET_CURRENT_CRED(); + code = AddPag(pagval, &credp); + } +#elif defined(AFS_LINUX20_ENV) + { + struct AFS_UCRED *credp = crref(); + code = AddPag(pagval, &credp); + crfree(credp); + } +#elif defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) + { + struct ucred *credp=crdup(p->p_cred->pc_ucred); + code=AddPag(p, pagval, &credp); + crfree(credp); + } +#else + code = AddPag(pagval, &u.u_cred); +#endif + + afs_Trace1(afs_iclSetp, CM_TRACE_SETPAG, ICL_TYPE_INT32, code); +#if defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_OSF_ENV) || defined(AFS_LINUX20_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) +#if defined(AFS_SGI53_ENV) && defined(MP) + AFS_GUNLOCK(); +#endif /* defined(AFS_SGI53_ENV) && defined(MP) */ + return (code); +#else + if (!getuerror()) + setuerror(code); + return (code); +#endif +} +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ + +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) +int afs_getpag_val() +{ + int pagvalue; + struct AFS_UCRED *credp = u.u_cred; + int gidset0, gidset1; + + gidset0 = credp->cr_groups[0]; + gidset1 = credp->cr_groups[1]; + pagvalue=afs_get_pag_from_groups(gidset0, gidset1); + return pagvalue; +} +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ + + #if defined(AFS_OSF_ENV) || defined(AFS_DARWIN_ENV) || defined(AFS_FBSD_ENV) int AddPag(struct proc *p, afs_int32 aval, struct AFS_UCRED **credpp) #else /* AFS_OSF_ENV || AFS_FBSD_ENV */ @@ -244,11 +382,15 @@ afs_uint32 afs_get_pag_from_groups(gid_t g0a, gid_t g1a) h = (g0 >> 14); h = (g1 >> 14) + h + h + h; ret = ((h << 28) | l); +#if defined(UKERNEL) && defined(AFS_WEB_ENHANCEMENTS) + return ret; +#else /* Additional testing */ if (((ret >> 24) & 0xff) == 'A') return ret; else return NOPAG; +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ } return NOPAG; } @@ -260,7 +402,9 @@ void afs_get_groups_from_pag(afs_uint32 pag, gid_t *g0p, gid_t *g1p) AFS_STATCNT(afs_get_groups_from_pag); +#if !defined(UKERNEL) || !defined(AFS_WEB_ENHANCEMENTS) pag &= 0x7fffffff; +#endif /* UKERNEL && AFS_WEB_ENHANCEMENTS */ g0 = 0x3fff & (pag >> 14); g1 = 0x3fff & pag; g0 |= ((pag >> 28) / 3) << 14; -- 2.39.5