From 4cbee84b4c1d1eca5913a64a392e2b31779ca7b5 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Thu, 28 Oct 2004 02:13:51 +0000 Subject: [PATCH] windows-freelance-symlink-20041027 * Remove the fallback to KRB4 in afskfw when obtaining tokens * Add support for symlinks to Freelance root.afs volume Stored at HKLM\SOFTWARE\OpenAFS\Client\Freelance\Symlinks = ":." Use symlink.exe to create, list, or remove --- src/WINNT/afsd/afskfw.c | 15 +- src/WINNT/afsd/cm_freelance.c | 309 ++++++++++++++++++++++++++++++++-- src/WINNT/afsd/cm_freelance.h | 8 +- src/WINNT/afsd/cm_ioctl.c | 30 ++++ src/WINNT/afsd/cm_scache.c | 2 +- src/WINNT/afsd/symlink.c | 10 ++ 6 files changed, 348 insertions(+), 26 deletions(-) diff --git a/src/WINNT/afsd/afskfw.c b/src/WINNT/afsd/afskfw.c index c0b31ec5a..01ace95a8 100644 --- a/src/WINNT/afsd/afskfw.c +++ b/src/WINNT/afsd/afskfw.c @@ -56,7 +56,7 @@ #define USE_MS2MIT -#define USE_KRB4 +#undef USE_KRB4 #include "afskfw-int.h" #include "afskfw.h" @@ -288,6 +288,7 @@ FUNC_INFO k5_fi[] = { END_FUNC_INFO }; +#ifdef USE_KRB4 FUNC_INFO k4_fi[] = { MAKE_FUNC_INFO(krb_get_cred), MAKE_FUNC_INFO(krb_get_tf_realm), @@ -295,6 +296,7 @@ FUNC_INFO k4_fi[] = { MAKE_FUNC_INFO(tkt_string), END_FUNC_INFO }; +#endif FUNC_INFO k524_fi[] = { MAKE_FUNC_INFO(krb524_init_ets), @@ -388,7 +390,9 @@ KFW_initialize(void) if ( !inited ) { inited = 1; LoadFuncs(KRB5_DLL, k5_fi, &hKrb5, 0, 1, 0, 0); +#ifdef USE_KRB4 LoadFuncs(KRB4_DLL, k4_fi, &hKrb4, 0, 1, 0, 0); +#endif /* USE_KRB4 */ LoadFuncs(COMERR_DLL, ce_fi, &hComErr, 0, 0, 1, 0); LoadFuncs(SERVICE_DLL, service_fi, &hService, 0, 1, 0, 0); #ifdef USE_MS2MIT @@ -2639,7 +2643,8 @@ KFW_AFS_klog( } } #else - goto cleanup; + if (!try_krb5) + goto cleanup; #endif strcpy(realm_of_cell, afs_realm_of_cell(ctx, &ak_cellconfig)); @@ -2696,7 +2701,7 @@ KFW_AFS_klog( code = pkrb5_get_credentials(ctx, 0, cc, &increds, &k5creds); if (code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || code == KRB5KRB_ERR_GENERIC /* heimdal */ || - code == KRB5KRB_AP_ERR_MSG_TYPE) { + code == KRB5KRB_AP_ERR_MSG_TYPE) { /* Or service@REALM */ pkrb5_free_principal(ctx,increds.server); increds.server = 0; @@ -2726,7 +2731,7 @@ KFW_AFS_klog( if ((code == KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN || code == KRB5KRB_ERR_GENERIC /* heimdal */ || - code == KRB5KRB_AP_ERR_MSG_TYPE) && + code == KRB5KRB_AP_ERR_MSG_TYPE) && strcmp(RealmName, realm_of_cell)) { /* Or service/cell@REALM_OF_CELL */ strcpy(RealmName, realm_of_cell); @@ -3017,7 +3022,7 @@ KFW_AFS_klog( if (ctx && (ctx != alt_ctx)) pkrb5_free_context(ctx); - return(rc? rc : code); + return(rc? rc : code); } /**************************************/ diff --git a/src/WINNT/afsd/cm_freelance.c b/src/WINNT/afsd/cm_freelance.c index 2933c0f50..e6b0a859e 100644 --- a/src/WINNT/afsd/cm_freelance.c +++ b/src/WINNT/afsd/cm_freelance.c @@ -73,6 +73,45 @@ void cm_FreelanceChangeNotifier(void * parmp) { } } } + +void cm_FreelanceSymlinkChangeNotifier(void * parmp) { + HANDLE hFreelanceSymlinkChangeEvent = 0; + HKEY hkFreelance = 0; + + if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, + "SOFTWARE\\OpenAFS\\Client\\Freelance\\Symlinks", + 0, + KEY_NOTIFY, + &hkFreelance) == ERROR_SUCCESS) { + + hFreelanceSymlinkChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); + if (hFreelanceSymlinkChangeEvent == NULL) { + RegCloseKey(hkFreelance); + return; + } + } + + while ( TRUE ) { + /* check hFreelanceSymlinkChangeEvent to see if it is set. + * if so, call cm_noteLocalMountPointSymlinkChange() + */ + if (RegNotifyChangeKeyValue( hkFreelance, /* hKey */ + FALSE, /* bWatchSubtree */ + REG_NOTIFY_CHANGE_LAST_SET, /* dwNotifyFilter */ + hFreelanceSymlinkChangeEvent, /* hEvent */ + TRUE /* fAsynchronous */ + ) != ERROR_SUCCESS) { + RegCloseKey(hkFreelance); + CloseHandle(hFreelanceSymlinkChangeEvent); + return; + } + + if (WaitForSingleObject(hFreelanceSymlinkChangeEvent, INFINITE) == WAIT_OBJECT_0) + { + cm_noteLocalMountPointChange(); + } + } +} #endif void cm_InitFreelance() { @@ -98,13 +137,17 @@ void cm_InitFreelance() { NULL, 0, &lpid, "cm_FreelanceChangeNotifier"); osi_assert(phandle != NULL); thrd_CloseHandle(phandle); + + phandle = thrd_Create(NULL, 65536, (ThreadFunc) cm_FreelanceSymlinkChangeNotifier, + NULL, 0, &lpid, "cm_FreelanceSymlinkChangeNotifier"); + osi_assert(phandle != NULL); + thrd_CloseHandle(phandle); #endif } /* yj: Initialization of the fake root directory */ /* to be called while holding freelance lock unless during init. */ void cm_InitFakeRootDir() { - int i, t1, t2; char* currentPos; int noChunks; @@ -398,12 +441,12 @@ long cm_InitLocalMountPoints() { long code; char rootCellName[256]; #if !defined(DJGPP) - HKEY hkFreelance = 0; + HKEY hkFreelance = 0, hkFreelanceSymlinks = 0; DWORD dwType, dwSize; - DWORD dwMountPoints; + DWORD dwMountPoints = 0; DWORD dwIndex; + DWORD dwSymlinks = 0; FILETIME ftLastWriteTime; - afs_uint32 unixTime; #endif #if !defined(DJGPP) @@ -440,9 +483,34 @@ long cm_InitLocalMountPoints() { dwMountPoints = 2; } + if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, + "SOFTWARE\\OpenAFS\\Client\\Freelance\\Symlinks", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ|KEY_WRITE|KEY_QUERY_VALUE, + NULL, + &hkFreelanceSymlinks, + NULL) == ERROR_SUCCESS) { + + RegQueryInfoKey( hkFreelanceSymlinks, + NULL, /* lpClass */ + NULL, /* lpcClass */ + NULL, /* lpReserved */ + NULL, /* lpcSubKeys */ + NULL, /* lpcMaxSubKeyLen */ + NULL, /* lpcMaxClassLen */ + &dwSymlinks, /* lpcValues */ + NULL, /* lpcMaxValueNameLen */ + NULL, /* lpcMaxValueLen */ + NULL, /* lpcbSecurityDescriptor */ + NULL /* lpftLastWriteTime */ + ); + } + // get the number of entries there are from the first line // that we read - cm_noLocalMountPoints = dwMountPoints; + cm_noLocalMountPoints = dwMountPoints + dwSymlinks; // create space to store the local mount points cm_localMountPoints = malloc(sizeof(cm_localMountPoint_t) * cm_noLocalMountPoints); @@ -478,14 +546,16 @@ long cm_InitLocalMountPoints() { cm_noLocalMountPoints--; continue; } + + aLocalMountPoint->fileType = CM_SCACHETYPE_MOUNTPOINT; aLocalMountPoint->namep=malloc(t-line+1); strncpy(aLocalMountPoint->namep, line, t-line); aLocalMountPoint->namep[t-line] = '\0'; - /* copy the mount point string without the trailing dot */ + /* copy the mount point string */ aLocalMountPoint->mountPointStringp=malloc(strlen(t)); - strncpy(aLocalMountPoint->mountPointStringp, t, strlen(t)-1); - aLocalMountPoint->mountPointStringp[strlen(t)-1] = '\0'; + strncpy(aLocalMountPoint->mountPointStringp, t, strlen(t)-1); + aLocalMountPoint->mountPointStringp[strlen(t)-1] = '\0'; osi_Log2(afsd_logp,"found mount point: name %s, string %s", osi_LogSaveString(afsd_logp,aLocalMountPoint->namep), @@ -494,6 +564,48 @@ long cm_InitLocalMountPoints() { aLocalMountPoint++; } + for ( dwIndex = 0 ; dwIndex < dwSymlinks; dwIndex++ ) { + TCHAR szValueName[16]; + DWORD dwValueSize = 16; + dwSize = sizeof(line); + RegEnumValue( hkFreelanceSymlinks, dwIndex, szValueName, &dwValueSize, NULL, + &dwType, line, &dwSize); + + /* find the trailing dot; null terminate after it */ + t2 = strrchr(line, '.'); + if (t2) + *(t2+1) = '\0'; + + // line is not empty, so let's parse it + t = strchr(line, ':'); + + // make sure that there is a ':' separator in the line + if (!t) { + afsi_log("error occurred while parsing symlink entry: no ':' separator in line %d", dwIndex); + fprintf(stderr, "error occurred while parsing symlink entry: no ':' separator in line %d", dwIndex); + cm_noLocalMountPoints--; + continue; + } + + aLocalMountPoint->fileType = CM_SCACHETYPE_SYMLINK; + aLocalMountPoint->namep=malloc(t-line+1); + strncpy(aLocalMountPoint->namep, line, t-line); + aLocalMountPoint->namep[t-line] = '\0'; + + /* copy the symlink string */ + aLocalMountPoint->mountPointStringp=malloc(strlen(t)-1); + strncpy(aLocalMountPoint->mountPointStringp, t+1, strlen(t)-2); + aLocalMountPoint->mountPointStringp[strlen(t)-2] = '\0'; + + osi_Log2(afsd_logp,"found symlink: name %s, string %s", + osi_LogSaveString(afsd_logp,aLocalMountPoint->namep), + osi_LogSaveString(afsd_logp,aLocalMountPoint->mountPointStringp)); + + aLocalMountPoint++; + } + + if ( hkFreelanceSymlinks ) + RegCloseKey( hkFreelanceSymlinks ); RegCloseKey(hkFreelance); return 0; } @@ -625,10 +737,6 @@ int cm_getNoLocalMountPoints() { return cm_noLocalMountPoints; } -cm_localMountPoint_t* cm_getLocalMountPoint(int vnode) { - return 0; -} - long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp) { FILE *fp; @@ -668,7 +776,7 @@ long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, #if !defined(DJGPP) if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, - "SOFTWARE\\OpenAFS\\Client\\Freelance", + "SOFTWARE\\OpenAFS\\Client\\Freelance\\Symlinks", 0, KEY_READ|KEY_WRITE|KEY_QUERY_VALUE, &hkFreelance) == ERROR_SUCCESS) { @@ -688,22 +796,35 @@ long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, ); if (rw) - sprintf(line, "%s%%%s:%s\n", filename, fullname, volume); + sprintf(line, "%s%%%s:%s", filename, fullname, volume); else - sprintf(line, "%s#%s:%s\n", filename, fullname, volume); + sprintf(line, "%s#%s:%s", filename, fullname, volume); /* If we are adding a new value, there must be an unused name * within the range 0 to dwMountPoints */ for ( dwIndex = 0; dwIndex <= dwMountPoints; dwIndex++ ) { char szIndex[16]; + char szMount[1024]; + + dwSize = sizeof(szMount); sprintf(szIndex, "%d", dwIndex); - if (RegQueryValueEx( hkFreelance, szIndex, 0, &dwType, NULL, &dwSize) != ERROR_SUCCESS) { + if (RegQueryValueEx( hkFreelance, szIndex, 0, &dwType, szMount, &dwSize) != ERROR_SUCCESS) { /* found an unused value */ dwType = REG_SZ; dwSize = strlen(line) + 1; RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize); break; + } else { + int len = strlen(filename); + if ( dwType == REG_SZ && !strncmp(filename, szMount, len) && + (szMount[len] == '%' || szMount[len] == '#')) { + /* Replace the existing value */ + dwType = REG_SZ; + dwSize = strlen(line) + 1; + RegSetValueEx( hkFreelance, szIndex, 0, dwType, line, dwSize); + break; + } } } RegCloseKey(hkFreelance); @@ -847,4 +968,160 @@ long cm_FreelanceRemoveMount(char *toremove) return 0; } +long cm_FreelanceAddSymlink(char *filename, char *destination, cm_fid_t *fidp) +{ + FILE *fp; + char hfile[120]; + char line[512]; + char fullname[200]; + int n; + int alias = 0; +#if !defined(DJGPP) + HKEY hkFreelanceSymlinks = 0; + DWORD dwType, dwSize; + DWORD dwSymlinks; + DWORD dwIndex; +#endif + + /* before adding, verify the cell name; if it is not a valid cell, + don't add the mount point. + allow partial matches as a means of poor man's alias. */ + /* major performance issue? */ + osi_Log2(afsd_logp,"Freelance Add Symlink request: filename=%s destination=%s", + osi_LogSaveString(afsd_logp,filename), + osi_LogSaveString(afsd_logp,destination)); + + lock_ObtainMutex(&cm_Freelance_Lock); + +#if !defined(DJGPP) + if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, + "SOFTWARE\\OpenAFS\\Client\\Freelance\\Symlinks", + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_READ|KEY_WRITE|KEY_QUERY_VALUE, + NULL, + &hkFreelanceSymlinks, + NULL) == ERROR_SUCCESS) { + + RegQueryInfoKey( hkFreelanceSymlinks, + NULL, /* lpClass */ + NULL, /* lpcClass */ + NULL, /* lpReserved */ + NULL, /* lpcSubKeys */ + NULL, /* lpcMaxSubKeyLen */ + NULL, /* lpcMaxClassLen */ + &dwSymlinks, /* lpcValues */ + NULL, /* lpcMaxValueNameLen */ + NULL, /* lpcMaxValueLen */ + NULL, /* lpcbSecurityDescriptor */ + NULL /* lpftLastWriteTime */ + ); + + sprintf(line, "%s:%s.", filename, destination); + + /* If we are adding a new value, there must be an unused name + * within the range 0 to dwSymlinks + */ + for ( dwIndex = 0; dwIndex <= dwSymlinks; dwIndex++ ) { + char szIndex[16]; + char szLink[1024]; + + dwSize = sizeof(szLink); + sprintf(szIndex, "%d", dwIndex); + if (RegQueryValueEx( hkFreelanceSymlinks, szIndex, 0, &dwType, szLink, &dwSize) != ERROR_SUCCESS) { + /* found an unused value */ + dwType = REG_SZ; + dwSize = strlen(line) + 1; + RegSetValueEx( hkFreelanceSymlinks, szIndex, 0, dwType, line, dwSize); + break; + } else { + int len = strlen(filename); + if ( dwType == REG_SZ && !strncmp(filename, szLink, len) && szLink[len] == ':') { + /* Replace the existing value */ + dwType = REG_SZ; + dwSize = strlen(line) + 1; + RegSetValueEx( hkFreelanceSymlinks, szIndex, 0, dwType, line, dwSize); + break; + } + } + } + RegCloseKey(hkFreelanceSymlinks); + } +#endif + lock_ReleaseMutex(&cm_Freelance_Lock); + + /* cm_reInitLocalMountPoints(); */ + if (fidp) { + fidp->unique = 1; + fidp->vnode = cm_noLocalMountPoints + 1; /* vnode value of last mt pt */ + } + cm_noteLocalMountPointChange(); + return 0; +} + +long cm_FreelanceRemoveSymlink(char *toremove) +{ + int i, n; + char* cp; + char line[512]; + char shortname[200]; + char hfile[120], hfile2[120]; + FILE *fp1, *fp2; + int found=0; +#if !defined(DJGPP) + HKEY hkFreelanceSymlinks = 0; + DWORD dwType, dwSize; + DWORD dwSymlinks; + DWORD dwIndex; +#endif + + lock_ObtainMutex(&cm_Freelance_Lock); + + +#if !defined(DJGPP) + if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, + "SOFTWARE\\OpenAFS\\Client\\Freelance\\Symlinks", + 0, + KEY_READ|KEY_WRITE|KEY_QUERY_VALUE, + &hkFreelanceSymlinks) == ERROR_SUCCESS) { + + RegQueryInfoKey( hkFreelanceSymlinks, + NULL, /* lpClass */ + NULL, /* lpcClass */ + NULL, /* lpReserved */ + NULL, /* lpcSubKeys */ + NULL, /* lpcMaxSubKeyLen */ + NULL, /* lpcMaxClassLen */ + &dwSymlinks, /* lpcValues */ + NULL, /* lpcMaxValueNameLen */ + NULL, /* lpcMaxValueLen */ + NULL, /* lpcbSecurityDescriptor */ + NULL /* lpftLastWriteTime */ + ); + + for ( dwIndex = 0; dwIndex < dwSymlinks; dwIndex++ ) { + TCHAR szValueName[16]; + DWORD dwValueSize = 16; + dwSize = sizeof(line); + RegEnumValue( hkFreelanceSymlinks, dwIndex, szValueName, &dwValueSize, NULL, + &dwType, line, &dwSize); + + cp=strchr(line, ':'); + memcpy(shortname, line, cp-line); + shortname[cp-line]=0; + + if (!strcmp(shortname, toremove)) { + RegDeleteValue( hkFreelanceSymlinks, szValueName ); + break; + } + } + RegCloseKey(hkFreelanceSymlinks); + } +#endif + + lock_ReleaseMutex(&cm_Freelance_Lock); + cm_noteLocalMountPointChange(); + return 0; +} #endif /* AFS_FREELANCE_CLIENT */ diff --git a/src/WINNT/afsd/cm_freelance.h b/src/WINNT/afsd/cm_freelance.h index 3d02b9e09..b47c66a7e 100644 --- a/src/WINNT/afsd/cm_freelance.h +++ b/src/WINNT/afsd/cm_freelance.h @@ -3,16 +3,16 @@ typedef struct cm_localMountPoint { - char* namep; - char* mountPointStringp; - struct cm_localMountPoint* next; + char* namep; + char* mountPointStringp; + unsigned int fileType; + struct cm_localMountPoint* next; } cm_localMountPoint_t; extern int cm_getNoLocalMountPoints(); extern long cm_InitLocalMountPoints(); extern int cm_getLocalMountPointChange(); extern int cm_reInitLocalMountPoints(); -extern cm_localMountPoint_t* cm_getLocalMountPoint(int vnode); extern void cm_InitFreelance(); extern long cm_FreelanceRemoveMount(char *toremove); extern long cm_FreelanceAddMount(char *filename, char *cellname, char *volume, int rw, cm_fid_t *fidp); diff --git a/src/WINNT/afsd/cm_ioctl.c b/src/WINNT/afsd/cm_ioctl.c index b63c379ea..8ccc32180 100644 --- a/src/WINNT/afsd/cm_ioctl.c +++ b/src/WINNT/afsd/cm_ioctl.c @@ -1510,6 +1510,26 @@ long cm_IoctlSymlink(struct smb_ioctl *ioctlp, struct cm_user *userp) cp = ioctlp->inDatap; /* contents of link */ +#ifdef AFS_FREELANCE_CLIENT + if (cm_freelanceEnabled && dscp == cm_rootSCachep) { + /* we are adding the symlink to the root dir., so call + * the freelance code to do the add. */ + if (cp[0] == cp[1] && cp[1] == '\\' && + !_strnicmp(cm_NetbiosName,cp+2,strlen(cm_NetbiosName))) + { + /* skip \\AFS\ or \\AFS\all\ */ + char * p; + p = cp + 2 + strlen(cm_NetbiosName) + 1; + if ( !_strnicmp("all", p, 3) ) + p += 4; + cp = p; + } + osi_Log0(afsd_logp,"IoctlCreateSymlink within Freelance root dir"); + code = cm_FreelanceAddSymlink(leaf, cp, NULL); + return code; + } +#endif + /* Create symlink with mode 0755. */ tattr.mask = CM_ATTRMASK_UNIXMODEBITS; tattr.unixModeBits = 0755; @@ -1619,6 +1639,16 @@ long cm_IoctlDeletelink(struct smb_ioctl *ioctlp, struct cm_user *userp) cp = ioctlp->inDatap; +#ifdef AFS_FREELANCE_CLIENT + if (cm_freelanceEnabled && dscp == cm_rootSCachep) { + /* we are adding the mount point to the root dir., so call + * the freelance code to do the add. */ + osi_Log0(afsd_logp,"IoctlDeletelink from Freelance root dir"); + code = cm_FreelanceRemoveSymlink(cp); + return code; + } +#endif + code = cm_Lookup(dscp, cp, CM_FLAG_NOMOUNTCHASE, userp, &req, &scp); /* if something went wrong, bail out now */ diff --git a/src/WINNT/afsd/cm_scache.c b/src/WINNT/afsd/cm_scache.c index 89eb79959..cfd3c382c 100644 --- a/src/WINNT/afsd/cm_scache.c +++ b/src/WINNT/afsd/cm_scache.c @@ -329,7 +329,7 @@ long cm_GetSCache(cm_fid_t *fidp, cm_scache_t **outScpp, cm_user_t *userp, cm_hashTablep[hash]=scp; scp->flags |= CM_SCACHEFLAG_INHASH; scp->refCount = 1; - scp->fileType = CM_SCACHETYPE_MOUNTPOINT; + scp->fileType = (cm_localMountPoints+fidp->vnode-2)->fileType; lock_ObtainMutex(&cm_Freelance_Lock); scp->length.LowPart = strlen(mp)+4; diff --git a/src/WINNT/afsd/symlink.c b/src/WINNT/afsd/symlink.c index 69fe625fd..5be151192 100644 --- a/src/WINNT/afsd/symlink.c +++ b/src/WINNT/afsd/symlink.c @@ -232,6 +232,11 @@ static MakeLinkCmd(as) register struct cmd_syndesc *as; { register afs_int32 code; struct ViceIoctl blob; +#ifdef WIN32 + char cm_NetbiosName[MAX_NB_NAME_LENGTH] = ""; + BOOL isGateway = FALSE; + lana_number_t lanaNum; +#endif if (!InAFS(Parent(as->parms[0].items->data))) { fprintf(stderr,"%s: symlinks must be created within the AFS file system\n", pn); @@ -243,6 +248,11 @@ register struct cmd_syndesc *as; { /* create symlink with a special pioctl for Windows NT, since it doesn't * have a symlink system call. */ + + /* TODO: Code needs to go here to prevent the creation of symlinks + * in \\AFS\all when not in the "AFS Client Admins" group. + */ + blob.out_size = 0; blob.in_size = 1 + strlen(space); blob.in = space; -- 2.39.5