From 946d2c1699be7ec8d31251d54d603d321b1f7936 Mon Sep 17 00:00:00 2001 From: Jeffrey Altman Date: Mon, 4 May 2015 13:25:04 -0400 Subject: [PATCH] Windows: Network Provider registration at service start Windows 8, 8.1 and pre-releases of 10 have a horrible bug as part of the upgrade process. All non-Microsoft network provider services are removed from the NetworkProvider "Order" registry value. For OpenAFS this has the side effect of breaking integrated logon and all drive letter mappings to \\AFS. During service start add code to: 1. Add "AFSRedirector" before "LanmanWorkstation" if not present 2. Add "TransarcAFSDaemon" to the end of the list if not present If the service is running in SMB mode 3. Remove "AFSRedirector" if present Change-Id: I14a703e44c6e0ee1bd36afd306f92a17dcc0d2a5 Reviewed-on: http://gerrit.openafs.org/12024 Tested-by: BuildBot Reviewed-by: Jeffrey Altman --- src/WINNT/afsd/afsd_service.c | 136 +++++++++++++++++++++++++++++++++- src/WINNT/afsreg/afsreg.h | 6 ++ 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/src/WINNT/afsd/afsd_service.c b/src/WINNT/afsd/afsd_service.c index 3ae290aad..436188893 100644 --- a/src/WINNT/afsd/afsd_service.c +++ b/src/WINNT/afsd/afsd_service.c @@ -1175,6 +1175,134 @@ BOOL AFSModulesVerify(void) return success; } +/* + * Add or remove the specified service from the Network Provider "Order" value + * in the registry: + * + * str : target string + * str2: string to add/remove + * bInst: == 1 if string should be added to target if not already there, otherwise remove string from target if present. + * if before != NULL, add string before + */ + +enum INP_ERR { + inp_err_error=0, + inp_err_present=1, + inp_err_added=2, + inp_err_absent=3, + inp_err_removed=4 +}; + +static enum INP_ERR +npi_CheckAndAddRemove(char *str, const char *str2, int bInst, + const char *before) +{ + char *target = NULL; + char *charset = NULL; + char *match, *bmatch; + int code; + enum INP_ERR rv = inp_err_error; + + code = asprintf(&target, ",%s,", str); + if (code < 0) + goto out; + + code = asprintf(&charset, ",%s,", str2); + if (code < 0) + goto out; + + match = strstr(target, charset); + if (match && bInst) { + if (before != NULL) { + bmatch = strstr(target, before); + if (bmatch == NULL || bmatch > match) { + rv = inp_err_present; + goto out; + } + + strcpy(str+(match-target), match + strlen(str2) + 2); + str[strlen(str)-1] = '\0'; + match = NULL; + } else { + rv = inp_err_present; + goto out; + } + } + + if (match == NULL && !bInst) { + rv = inp_err_absent; + } + else if (bInst) + { + if (before == NULL || (bmatch = strstr(str, before)) == NULL) { + /* append to list */ + strcat(str, ","); + strcat(str, str2); + } else { + /* insert before str2 */ + size_t s2len = strlen(str2); + memmove(bmatch + s2len + 1, bmatch, strlen(bmatch) + 1); + memcpy(bmatch, str2, s2len); + bmatch[s2len] = ','; + } + rv = inp_err_added; + } + else + { + /* remove from list */ + strcpy(str + (match-target), match + strlen(str2) + 2); + str[strlen(str)-1] = '\0'; + rv = inp_err_removed; + } + + out: + free(target); + free(charset); + return rv; +} + + +static DWORD +InstNetProvider(const char *svcname, int bInst, const char *before) +{ + const char *strOrder = NULL; + HKEY hkOrder; + LONG rv; + DWORD dwSize; + HANDLE hProcHeap; + + rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, AFSREG_NP_ORDER, 0, + KEY_READ | KEY_WRITE, &hkOrder); + if (rv != ERROR_SUCCESS) + goto out; + + dwSize = 0; + rv = RegQueryValueEx(hkOrder, AFSREG_NP_ORDER_VALUE, + NULL, NULL, NULL, &dwSize); + if (rv != ERROR_SUCCESS) + goto out; + + strOrder = malloc(dwSize + 2 + strlen(svcname)); + + rv = RegQueryValueEx(hkOrder, AFSREG_NP_ORDER_VALUE, + NULL, NULL, (LPBYTE) strOrder, &dwSize); + if (rv != ERROR_SUCCESS) + goto out; + + switch(npi_CheckAndAddRemove(strOrder, svcname , bInst, before)) { + case inp_err_added: + case inp_err_removed: + dwSize = strlen(strOrder) + 1; + rv = RegSetValueEx(hkOrder, AFSREG_NP_ORDER_VALUE, 0, REG_SZ, + strOrder, dwSize); + break; + } + + out: + free(strOrder); + return rv; +} + /* control serviceex exists only on 2000/xp. These functions will be loaded dynamically. */ @@ -1427,7 +1555,13 @@ afsd_Main(DWORD argc, LPTSTR *argv) else if (cm_sysNameCount) RDR_SysName( AFS_SYSNAME_ARCH_64BIT, cm_sysNameCount, cm_sysNameList ); #endif - } + + InstNetProvider("AFSRedirector", TRUE, "LanmanWorkstation"); + } else { + InstNetProvider("AFSRedirector", FALSE, NULL); + } + + InstNetProvider("TransarcAFSDaemon", TRUE, NULL); /* * Set the default for the SMB interface based upon the state of the diff --git a/src/WINNT/afsreg/afsreg.h b/src/WINNT/afsreg/afsreg.h index c3274e61b..d334460bc 100644 --- a/src/WINNT/afsreg/afsreg.h +++ b/src/WINNT/afsreg/afsreg.h @@ -191,6 +191,12 @@ TEXT("HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services") #define AFSREG_USER_OPENAFS_SUBKEY TEXT("Software\\OpenAFS\\Client") #define AFSREG_USER_OPENAFS_KEY TEXT("HKEY_CURRENT_USER") AFSREG_USER_OPENAFS_SUBKEY +/* Network Provider Order */ + +#define AFSREG_NP_ORDER \ + TEXT("SYSTEM\\CurrentControlSet\\Control\\NetworkProvider\\Order") + +#define AFSREG_NP_ORDER_VALUE TEXT("ProviderOrder") /* Extended (alternative) versions of registry access functions */ -- 2.39.5