*
*/
#ifndef __RPCASYNC_H__
-#define __RPCASYNC_H__ /* Skip asynch rpc inclusion */
+#define __RPCASYNC_H__ /* Skip asynch rpc inclusion */
#endif
#include <windows.h>
#include <stdio.h>
#define PERR(api) printf("\n%s: Error %d from %s on line %d", \
- __FILE__, GetLastError(), api, __LINE__);
+ __FILE__, GetLastError(), api, __LINE__);
#define MSG_FOR_ACCESS_DENIED "You aren't authorized to do this - please see your system Administrator"
#define MSG_1_FOR_BAD_PATH "The fully qualified path name to the .exe must be given, and"
#define MSG_2_FOR_BAD_PATH " the drive letter must be for a fixed disk (e.g., not a net drive)"
+/* Building an initialised REG_MULTISZ needs a bit of care: The array must be big enough
+** to hold the closing double-NUL and should have *exactly* the required size. Since the
+** dependencies are fixed here, we take exactly the required 11 bytes:
+*/
+static const char s_acSvcDeps[11] = "TcpIp\0Afd\0\0";
+/* likewise we do with the PPAS API list... */
+static const char s_acPpsDlls[30] = "loopback-ppsapi-provider.dll\0\0";
+
SC_HANDLE schService;
SC_HANDLE schSCManager;
int ok2;
-VOID DisplayHelp(VOID);
+void DisplayHelp(void);
/* --------------------------------------------------------------------------------------- */
-
-int InstallService(LPCTSTR serviceName, LPCTSTR displayName, LPCTSTR serviceExe)
+static const char *
+getServicePath(
+ const char * const * const argv,
+ const int argc) /* MUST be >= 1 !! */
{
- LPCTSTR lpszBinaryPathName = serviceExe;
- TCHAR lpszRootPathName[] ="?:\\";
-
- if ( (':' != *(lpszBinaryPathName+1)) || ('\\' != *(lpszBinaryPathName+2)) )
- { printf("\n%s",MSG_1_FOR_BAD_PATH);
- printf("\n%s\n",MSG_2_FOR_BAD_PATH);
- return 1;
- }
-
- #define DRIVE_TYPE_INDETERMINATE 0
- #define ROOT_DIR_DOESNT_EXIST 1
-
- *lpszRootPathName = *(lpszBinaryPathName+0) ;
-
- switch ( GetDriveType(lpszRootPathName) )
- {
- case DRIVE_FIXED :
- { // OK
- break;
+ static const char * const s_chars_to_quote = " []()";
+ size_t minsize = argc * 3; /* may need separator/NUL + quotes */
+ int i;
+ const char *execPath = argv[0];
+ char *cbuf, *cpos;
+
+ /* if just the executable and no dangerous chars, return the exe path. */
+ if (argc == 1 && !strpbrk(execPath, s_chars_to_quote))
+ return execPath;
+
+ /* calculate buffer size and get the buffer */
+ for (i = 0; i < argc; ++i)
+ minsize += strlen(argv[i]);
+
+ cpos = cbuf = malloc(minsize);
+ if (NULL == cbuf) {
+ printf("malloc() failed\n");
+ exit(2);
}
- case ROOT_DIR_DOESNT_EXIST :
- { printf("\n%s",MSG_1_FOR_BAD_PATH);
- printf("\n the root directory where the .exe is specified to be must exist, and");
- printf("\n%s\n",MSG_2_FOR_BAD_PATH);
- return 1;
+
+ /* program name must be quoted in all cases */
+ *cpos++ = '"';
+ strcpy(cpos, execPath);
+ cpos += strlen(cpos);
+ *cpos++ = '"';
+
+ /* append additional args */
+ for (i = 1; i < argc; ++i) {
+ *cpos++ = ' ';
+ if (strpbrk(argv[i], s_chars_to_quote)) { /* needs quotes? */
+ *cpos++ = '"';
+ strcpy(cpos, argv[i]);
+ cpos += strlen(cpos);
+ *cpos++ = '"';
+ } else {
+ strcpy(cpos, argv[i]);
+ cpos += strlen(cpos);
+ }
}
- case DRIVE_TYPE_INDETERMINATE :
- case DRIVE_REMOVABLE :
- case DRIVE_REMOTE :
- case DRIVE_CDROM :
- case DRIVE_RAMDISK :
- { printf("\n%s",MSG_1_FOR_BAD_PATH);
- printf("\n%s\n",MSG_2_FOR_BAD_PATH);
- return 1;
+ *cpos = '\0';
+ return cbuf;
+}
+
+/* --------------------------------------------------------------------------------------- */
+BOOL
+validateExeName(
+ const char *exePath)
+{
+ char rootPath[] = "?:\\";
+
+ /* check for absolute path */
+ if ((':' != exePath[1]) || ('\\' != exePath[2])) {
+ printf("\n%s", MSG_1_FOR_BAD_PATH);
+ printf("\n%s\n", MSG_2_FOR_BAD_PATH);
+ return 1;
}
- default :
- { printf("\n%s",MSG_1_FOR_BAD_PATH);
- printf("\n%s\n",MSG_2_FOR_BAD_PATH);
- return 1;
+
+#define DRIVE_TYPE_INDETERMINATE 0
+#define ROOT_DIR_DOESNT_EXIST 1
+
+ /* check drive type -- must be local HDD! */
+ rootPath[0] = exePath[0];
+ switch (GetDriveTypeA(rootPath))
+ {
+ case DRIVE_FIXED:
+ // OK
+ break;
+
+ case ROOT_DIR_DOESNT_EXIST:
+ printf("\n%s", MSG_1_FOR_BAD_PATH);
+ printf("\n the root directory where the .exe is specified to be must exist, and");
+ printf("\n%s\n", MSG_2_FOR_BAD_PATH);
+ return 1;
+
+ case DRIVE_TYPE_INDETERMINATE:
+ case DRIVE_REMOVABLE:
+ case DRIVE_REMOTE:
+ case DRIVE_CDROM:
+ case DRIVE_RAMDISK:
+ printf("\n%s", MSG_1_FOR_BAD_PATH);
+ printf("\n%s\n", MSG_2_FOR_BAD_PATH);
+ return 1;
+
+ default:
+ printf("\n%s", MSG_1_FOR_BAD_PATH);
+ printf("\n%s\n", MSG_2_FOR_BAD_PATH);
+ return 1;
}
- }
-
- if (INVALID_HANDLE_VALUE == CreateFile(lpszBinaryPathName,
- GENERIC_READ,
- FILE_SHARE_READ,
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL,
- NULL))
- {
- printf("\n%s",MSG_1_FOR_BAD_PATH);
- printf("\n the file must exist, and");
- printf("\n%s\n",MSG_2_FOR_BAD_PATH);
- return 1;
- }
+
+ /* check if file exists. We just drop the handle. This is a one-shot program! */
+ if (INVALID_HANDLE_VALUE == CreateFileA(
+ exePath, GENERIC_READ, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL))
+ {
+ printf("\n%s", MSG_1_FOR_BAD_PATH);
+ printf("\n the file must exist, and");
+ printf("\n%s\n", MSG_2_FOR_BAD_PATH);
+ return 1;
+ }
+
+ return 0;
+}
+/* --------------------------------------------------------------------------------------- */
- schService = CreateService(
+int
+InstallService(
+ LPCSTR serviceName,
+ LPCSTR displayName,
+ LPCSTR serviceExe ,
+ LPCSTR servDepends)
+{
+
+ /* create the service now. */
+ schService = CreateServiceA(
schSCManager, // SCManager database
serviceName, // name of service
displayName, // name to display
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
- lpszBinaryPathName, // service's binary
+ serviceExe, // service's binary
NULL, // no load ordering group
NULL, // no tag identifier
- NULL, // no dependencies
+ servDepends, // possible dependencies
NULL, // Local System account
NULL); // null password
- if (NULL == schService)
- { switch (GetLastError())
- {
- case ERROR_ACCESS_DENIED :
- { printf("\n%s",MSG_FOR_ACCESS_DENIED);
- break;
- }
- case ERROR_SERVICE_EXISTS :
- { printf("\nThe %s service is already installed",serviceName);
- printf("\nRemove it first if you need to re-install a new version\n");
- break;
- }
- default :
- { PERR("CreateService");
- }
+ if (NULL == schService) {
+ switch (GetLastError())
+ {
+ case ERROR_ACCESS_DENIED :
+ printf("\n%s",MSG_FOR_ACCESS_DENIED);
+ break;
+
+ case ERROR_SERVICE_EXISTS :
+ printf("\nThe %s service is already installed",serviceName);
+ printf("\nRemove it first if you need to re-install a new version\n");
+ break;
+
+ default :
+ PERR("CreateService");
+ break;
+ }
+ return 1;
}
- return 1;
- }
- else
- CloseServiceHandle(schService);
- return 0;
+ CloseServiceHandle(schService);
+ return 0;
}
/* --------------------------------------------------------------------------------------- */
-int RemoveService(LPCTSTR serviceName)
+int
+RemoveService(
+ LPCSTR serviceName)
{
- {
- #define SZ_ENUM_BUF 4096
- ENUM_SERVICE_STATUS essServiceStatus[SZ_ENUM_BUF];
- DWORD dwBufSize = sizeof(essServiceStatus);
- DWORD dwBytesNeeded = 0;
- DWORD dwServicesReturned = 0;
- DWORD dwResumeHandle = 0;
- DWORD dwI = 0;
- BOOLEAN bFound = FALSE;
-
- if (!EnumServicesStatus(schSCManager,
- SERVICE_WIN32,
- SERVICE_ACTIVE,
- (LPENUM_SERVICE_STATUS)&essServiceStatus,
- dwBufSize,
- &dwBytesNeeded,
- &dwServicesReturned,
- &dwResumeHandle))
- { switch (GetLastError())
- {
- case ERROR_ACCESS_DENIED :
- { printf("\n%s",MSG_FOR_ACCESS_DENIED);
- break;
+ {
+# define SZ_ENUM_BUF 4096
+ ENUM_SERVICE_STATUS essServiceStatus[SZ_ENUM_BUF];
+ DWORD dwBufSize = sizeof(essServiceStatus);
+ DWORD dwBytesNeeded = 0;
+ DWORD dwServicesReturned = 0;
+ DWORD dwResumeHandle = 0;
+ DWORD dwI = 0;
+ BOOLEAN bFound = FALSE;
+
+ if (!EnumServicesStatusA(schSCManager, SERVICE_WIN32, SERVICE_ACTIVE,
+ (LPENUM_SERVICE_STATUS)&essServiceStatus,
+ dwBufSize, &dwBytesNeeded, &dwServicesReturned,
+ &dwResumeHandle))
+ {
+ switch (GetLastError())
+ {
+ case ERROR_ACCESS_DENIED :
+ printf("\n%s", MSG_FOR_ACCESS_DENIED);
+ break;
+
+ default :
+ PERR("EnumServicesStatus");
+ break;
+ }
+ return 1;
}
- default :
- { PERR("EnumServicesStatus");
+
+ for (dwI = 0; dwI < dwServicesReturned; ++dwI) {
+ if(0 == _stricmp(essServiceStatus[dwI].lpServiceName, serviceName)) {
+ bFound = TRUE;
+ break;
+ }
+ }
+
+ if (bFound) {
+ printf("\nThe %s service cannot be removed until it has been stopped.", serviceName);
+ printf("\nTo stop the %s service, use the Stop button in the Control" , serviceName);
+ printf("\n Panel Services applet\n");
+ return 1;
}
- }
- return 1;
}
+
+ schService = OpenServiceA(schSCManager, serviceName, SERVICE_ALL_ACCESS);
+ if (NULL == schService) {
+ switch (GetLastError())
+ {
+ case ERROR_ACCESS_DENIED :
+ printf("\n%s", MSG_FOR_ACCESS_DENIED);
+ break;
- for (dwI=0; dwI<dwServicesReturned; dwI++)
- { if(0 == _stricmp(essServiceStatus[dwI].lpServiceName,serviceName))
- { bFound = TRUE;
- break;
- }
- }
+ case ERROR_SERVICE_DOES_NOT_EXIST :
+ printf("\nThe %s service is not installed, so cannot be removed\n", serviceName);
+ break;
- if (bFound)
- { printf("\nThe %s service cannot be removed until it has been stopped.",serviceName);
- printf("\nTo stop the %s service, use the Stop button in the Control",serviceName);
- printf("\n Panel Services applet\n");
- return 1;
+ default :
+ PERR("OpenService");
+ break;
+ }
+ return 1;
+ }
+
+ if (DeleteService(schService)) {
+ printf("\nDelete of Service \"Network Time Protocol\" was SUCCESSFUL\n");
+ return 0;
}
- }
- schService = OpenService(schSCManager,
- serviceName,
- SERVICE_ALL_ACCESS);
- if (NULL == schService)
- { switch (GetLastError())
+ switch (GetLastError())
{
- case ERROR_ACCESS_DENIED :
- { printf("\n%s",MSG_FOR_ACCESS_DENIED);
+ case ERROR_ACCESS_DENIED :
+ printf("\n%s", MSG_FOR_ACCESS_DENIED);
break;
- }
- case ERROR_SERVICE_DOES_NOT_EXIST :
- { printf("\nThe %s service is not installed, so cannot be removed\n",serviceName);
+
+ default :
+ PERR("DeleteService");
break;
- }
- default :
- { PERR("OpenService");
- }
}
+
return 1;
- }
-
- if (DeleteService(schService))
- { printf("\nDelete of Service \"Network Time Protocol\" was SUCCESSFUL\n");
- return 0;
- }
- else
- { switch (GetLastError())
- {
- case ERROR_ACCESS_DENIED :
- { printf("\n%s",MSG_FOR_ACCESS_DENIED);
- break;
- }
- default :
- { PERR("DeleteService");
- }
- }
- return 1;
- }
}
/* --------------------------------------------------------------------------------------- */
-int addSourceToRegistry(const char * pszAppname, const char * pszMsgDLL)
+int
+addSourceToRegistry(
+ const char * pszAppname,
+ const char * pszMsgDLL )
{
- HKEY hk; /* registry key handle */
- DWORD dwData;
- BOOL bSuccess;
- char regarray[200];
- int rc;
-
- /* When an application uses the RegisterEventSource or OpenEventLog
- function to get a handle of an event log, the event loggging service
- searches for the specified source name in the registry. You can add a
- new source name to the registry by opening a new registry subkey
- under the Application key and adding registry values to the new
- subkey. */
-
- rc = snprintf(regarray, sizeof(regarray), "%s%s",
- "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\",
- pszAppname);
- if (rc < 0 || rc >= sizeof(regarray))
- {
- fputs("addSourceToRegistry: buffer overrun(app name)", stderr);
- return 1;
- }
- /* Create a new key for our application */
- bSuccess = RegCreateKeyA(HKEY_LOCAL_MACHINE, regarray, &hk);
- if(bSuccess != ERROR_SUCCESS)
- {
- PERR("RegCreateKey");
- return 1;
- }
+ HKEY hk; /* registry key handle */
+ DWORD dwData;
+ BOOL bSuccess;
+ char regarray[200];
+ int rc;
+
+ /* When an application uses the RegisterEventSource or OpenEventLog function to get a
+ handle of an event log, the event loggging service searches for the specified
+ source name in the registry. You can add a new source name to the registry by
+ opening a new registry subkey under the Application key and adding registry values
+ to the new subkey.
+ */
+
+ rc = snprintf(regarray, sizeof(regarray), "%s%s",
+ "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\",
+ pszAppname);
+ if (rc < 0 || rc >= sizeof(regarray)) {
+ fputs("addSourceToRegistry: buffer overrun(app name)", stderr);
+ return 1;
+ }
+ /* Create a new key for our application */
+ bSuccess = RegCreateKeyA(HKEY_LOCAL_MACHINE, regarray, &hk);
+ if(bSuccess != ERROR_SUCCESS) {
+ PERR("RegCreateKey");
+ return 1;
+ }
- /* Add the Event-ID message-file name to the subkey. */
- bSuccess = RegSetValueExA(hk, /* subkey handle */
- "EventMessageFile", /* value name */
- 0, /* must be zero */
- REG_EXPAND_SZ, /* value type */
- (LPBYTE)pszMsgDLL, /* address of value data */
- (DWORD)(strlen(pszMsgDLL) + 1)); /* length of value data */
- if(bSuccess != ERROR_SUCCESS)
- {
- PERR("RegSetValueEx");
- return 1;
- }
+ /* Add the Event-ID message-file name to the subkey. */
+ bSuccess = RegSetValueExA(hk, /* subkey handle */
+ "EventMessageFile", /* value name */
+ 0, /* must be zero */
+ REG_EXPAND_SZ, /* value type */
+ (LPBYTE)pszMsgDLL, /* address of value data */
+ (DWORD)(strlen(pszMsgDLL) + 1)); /* length of value data */
+ if(bSuccess != ERROR_SUCCESS) {
+ PERR("RegSetValueEx");
+ return 1;
+ }
- /* Set the supported types flags and addit to the subkey. */
- dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
- EVENTLOG_INFORMATION_TYPE;
- bSuccess = RegSetValueExA(hk, /* subkey handle */
- "TypesSupported", /* value name */
- 0, /* must be zero */
- REG_DWORD, /* value type */
- (LPBYTE) &dwData, /* address of value data */
- sizeof(DWORD)); /* length of value data */
- if(bSuccess != ERROR_SUCCESS)
- {
- PERR("RegSetValueEx");
- return 1;
- }
- RegCloseKey(hk);
- return 0;
+ /* Set the supported types flags and addit to the subkey. */
+ dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+ bSuccess = RegSetValueExA(hk, /* subkey handle */
+ "TypesSupported", /* value name */
+ 0, /* must be zero */
+ REG_DWORD, /* value type */
+ (LPBYTE) &dwData, /* address of value data */
+ sizeof(DWORD)); /* length of value data */
+ if(bSuccess != ERROR_SUCCESS) {
+ PERR("RegSetValueEx");
+ return 1;
+ }
+
+ RegCloseKey(hk);
+ return 0;
}
/* --------------------------------------------------------------------------------------- */
-int addKeysToRegistry()
+int
+addKeysToRegistry(void)
{
- HKEY hk; /* registry key handle */
- BOOL bSuccess;
-
- /* Building an initialised REG_MULTISZ needs a bit of care: The array must be big enough
- ** to hold the closing double-NUL and should have *exactly* the required size. Since the
- ** dependencies are fixed here, we take exactly the required 11 bytes:
- */
- static const char s_acSvcDeps[11] = "TcpIp\0Afd\0\0";
- /* now add the depends on service key */
+ HKEY hk; /* registry key handle */
+ BOOL bSuccess;
+
+ /* now add the depends on service key */
- /* Create a new key for our application */
- bSuccess = RegCreateKeyA(HKEY_LOCAL_MACHINE,
- "SYSTEM\\CurrentControlSet\\Services\\NTP", &hk);
- if(bSuccess != ERROR_SUCCESS) {
- PERR("RegCreateKey");
- return 1;
- }
-
- bSuccess = RegSetValueExA(hk, /* subkey handle */
- "DependOnService", /* value name */
- 0, /* must be zero */
- REG_MULTI_SZ, /* value type */
- (LPBYTE)s_acSvcDeps, /* address of value data */
- (DWORD)sizeof(s_acSvcDeps)); /* length of value data */
- if(bSuccess != ERROR_SUCCESS)
- {
- PERR("RegSetValueEx");
- return 1;
- }
+ /* Create a new key for our application */
+ bSuccess = RegCreateKeyA(HKEY_LOCAL_MACHINE,
+ "SYSTEM\\CurrentControlSet\\Services\\NTP", &hk);
+ if(bSuccess != ERROR_SUCCESS) {
+ PERR("RegCreateKey");
+ return 1;
+ }
+
+ bSuccess = RegSetValueExA(hk, /* subkey handle */
+ "PPSProviders", /* value name */
+ 0, /* must be zero */
+ REG_MULTI_SZ, /* value type */
+ (LPBYTE)s_acPpsDlls, /* address of value data */
+ (DWORD)sizeof(s_acPpsDlls)); /* length of value data */
+ if (bSuccess != ERROR_SUCCESS) {
+ PERR("RegSetValueEx");
+ return 1;
+ }
- RegCloseKey(hk);
- return 0;
+ RegCloseKey(hk);
+ return 0;
}
/* --------------------------------------------------------------------------------------- */
int main(int argc, char *argv[])
{
- #define SZ_NAME_BUF 270 // 256 is max, add a little
- UCHAR ucNameBuf[SZ_NAME_BUF] = "NTP";
- LPTSTR lpszServName = (LPTSTR)&ucNameBuf;
-
- UCHAR ucDNameBuf[SZ_NAME_BUF] = "Network Time Protocol";
- LPTSTR lpszDispName = (LPTSTR)&ucDNameBuf;
+ static const char * const szServiceName = "NTP";
+ static const char * const szDisplayName = "Network Time Protocol";
+ BOOL bRemovingService = FALSE;
+ char *p;
+ int ok = 0;
+
+ // check if Win32s, if so, display notice and terminate
+ if (GetVersion() & 0x80000000) {
+ MessageBoxA(NULL,
+ "This application cannot run on Windows 3.1.\n"
+ "This application will now terminate.",
+ "NAMED",
+ MB_OK | MB_ICONSTOP | MB_SETFOREGROUND );
+ return 1;
+ }
- UCHAR ucExeNBuf[SZ_NAME_BUF] = "";
- LPTSTR lpszExeName = (LPTSTR)&ucExeNBuf;
+ if (argc >= 2)
+ bRemovingService = (!stricmp(argv[1], "remove"));
- BOOL bRemovingService = FALSE;
- char *p;
+ if ((bRemovingService && argc != 2) || (!bRemovingService && argc < 2)) {
+ DisplayHelp();
+ return 1;
+ }
- int ok = 0;
-
- // check if Win32s, if so, display notice and terminate
- if( GetVersion() & 0x80000000 )
- {
- MessageBox( NULL,
- "This application cannot run on Windows 3.1.\n"
- "This application will now terminate.",
- "NAMED",
- MB_OK | MB_ICONSTOP | MB_SETFOREGROUND );
- return( 1 );
- }
- if (argc == 2)
- bRemovingService = (!stricmp(argv[1], "remove"));
-
- if(!bRemovingService)
- {
+ if(!bRemovingService) {
+ p = argv[1];
+ if (('/' == *p) || ('-' == *p) || validateExeName(p)) {
+ DisplayHelp();
+ return 1;
+ }
+ }
-
- if (argc != 2)
- {
- DisplayHelp();
- return(1);
- }
-
- p=argv[1];
- if ( ('/' == *p)
- || ('-' == *p) )
- {
- DisplayHelp();
- return(1);
- }
-
-
- }
- if (strlen(argv[1]) > 256)
- {
- printf("\nThe service name cannot be longer than 256 characters\n");
- return(1);
+ if (strlen(argv[1]) > 256) {
+ printf("\nThe service name cannot be longer than 256 characters\n");
+ return 1;
}
+ schSCManager = OpenSCManagerA(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+ SC_MANAGER_ALL_ACCESS); // access required
+ if (NULL == schSCManager) {
+ switch (GetLastError())
+ {
+ case ERROR_ACCESS_DENIED :
+ printf("\n%s", MSG_FOR_ACCESS_DENIED);
+ break;
- bRemovingService = (!stricmp(argv[1], "remove"));
- schSCManager = OpenSCManager(
- NULL, // machine (NULL == local)
- NULL, // database (NULL == default)
- SC_MANAGER_ALL_ACCESS); // access required
-
- if (NULL == schSCManager)
- { switch (GetLastError())
- {
- case ERROR_ACCESS_DENIED :
- { printf("\n%s",MSG_FOR_ACCESS_DENIED);
- break;
- }
- default :
- { PERR("OpenSCManager");
- }
+ default :
+ PERR("OpenSCManager");
+ break;
+ }
+ return 0;
}
- return (0);
- }
- if (bRemovingService)
- {
- ok = RemoveService(lpszServName);
- }
- else
- {
- /* get the exe name */
- strcpy(lpszExeName,argv[1]);
- ok = InstallService(lpszServName, lpszDispName, lpszExeName);
- }
-
- CloseServiceHandle(schSCManager);
-
- if (!bRemovingService)
- {
- if (ok == 0)
- { /* Set the Event-ID message-file name. */
- ok = addSourceToRegistry("NTP", lpszExeName);
- if (ok == 0)
- ok = addKeysToRegistry();
- else return ok;
-
- if (ok == 0)
- {
- printf("\nThe \"Network Time Protocol\" service was successfully created.\n");
- printf("\nDon't forget!!! You must now go to the Control Panel and");
- printf("\n use the Services applet to change the account name and");
- printf("\n password that the NTP Service will use when");
- printf("\n it starts.");
- printf("\nTo do this: use the Startup button in the Services applet,");
- printf("\n and (for example) specify the desired account and");
- printf("\n correct password.");
- printf("\nAlso, use the Services applet to ensure this newly installed");
- printf("\n service starts automatically on bootup.\n");
- return 0;
+ if (bRemovingService)
+ ok = RemoveService(szServiceName);
+ else
+ ok = InstallService(szServiceName, szDisplayName,
+ getServicePath(argv+1, argc-1), s_acSvcDeps);
+
+ CloseServiceHandle(schSCManager);
+
+ if (!bRemovingService) {
+ if (ok == 0)
+ ok = addSourceToRegistry("NTP", argv[1]);/* Set the Event-ID message-file name. */
+ if (ok == 0)
+ ok = addKeysToRegistry(); /* add other stuff */
+
+ if (ok == 0)
+ {
+ static const char s_msg[] =
+ "\nThe \"Network Time Protocol\" service was successfully created.\n"
+ "\nDon't forget!!! You must now go to the Control Panel and"
+ "\n use the Services applet to change the account name and"
+ "\n password that the NTP Service will use when"
+ "\n it starts."
+ "\nTo do this: use the Startup button in the Services applet,"
+ "\n and (for example) specify the desired account and"
+ "\n correct password."
+ "\nAlso, use the Services applet to ensure this newly installed"
+ "\n service starts automatically on bootup.\n";
+ fputs(s_msg, stdout);
+ }
}
- }
- else return ok;
- }
- return 0;
+ return ok;
}
/* --------------------------------------------------------------------------------------- */
-VOID DisplayHelp(VOID)
+void
+DisplayHelp(void)
{
- printf("Installs or removes the NTP service.\n");
- printf("To install the NTP service,\n");
- printf("type INSTSRV <path> \n");
- printf("Where:\n");
- printf(" path Absolute path to the NTP service, name.exe. You must\n");
- printf(" use a fully qualified path and the drive letter must be for a\n");
- printf(" fixed, local drive.\n\n");
- printf("For example, INSTSRV i:\\winnt\\system32\\ntpd.exe\n");
- printf("To remove the NTP service,\n");
- printf("type INSTSRV remove \n");
-
+ static const char s_hlpmsg[] =
+ "Installs or removes the NTP service.\n"
+ "To install the NTP service,\n"
+ "type INSTSRV <path> [args]\n"
+ "Where:\n"
+ " path Absolute path to the NTP service. (ntpd.exe) You must\n"
+ " use a fully qualified path and the drive letter must be for a\n"
+ " fixed, local drive.\n\n"
+ " args Additional command line arguments for the service\n"
+ "For example, INSTSRV i:\\winnt\\system32\\ntpd.exe\n"
+ "To remove the NTP service,\n"
+ "type INSTSRV remove \n";
+ fputs(s_hlpmsg, stdout);
}
/* EOF */
#include "timepps.h"
#include "ntp_stdlib.h"
#include "lib_strbuf.h"
+#include "ntp_iocpltypes.h"
+#include "ntp_iocplmem.h"
+struct InstListNode {
+ struct InstListNode * next;
+ pps_handle_t ppsu;
+ DevCtx_t * devu;
+};
+typedef struct ProvListNode ProvListNode_t;
+
+static struct InstListNode * g_active_units;
static ppsapi_provider * g_provider_list;
static ppsapi_provider * g_curr_provider;
+static void
+ppsu_register(
+ pps_handle_t ppsu,
+ DevCtx_t * devu)
+{
+ struct InstListNode * node;
+
+ if (devu && (node = IOCPLPoolAlloc(sizeof(*node), "PPS registration"))) {
+ node->next = g_active_units;
+ node->ppsu = ppsu;
+ node->devu = DevCtxAttach(devu);
+ devu->pps_active = TRUE;
+ g_active_units = node;
+ }
+}
+
+static void
+ppsu_remove(
+ pps_handle_t ppsu)
+{
+ struct InstListNode ** link;
+ struct InstListNode * node;
+
+ link = &g_active_units;
+ while (NULL != (node = *link)) {
+ if (node->ppsu == ppsu) {
+ node->devu->pps_active = FALSE;
+ DevCtxDetach(node->devu);
+ *link = node->next;
+ IOCPLPoolFree(node, "PPS registration");
+ } else {
+ link = &node->next;
+ }
+ }
+}
+
+static HKEY
+myRegOpenKey(
+ const char * szSubKey)
+{
+ static const char * const s_RegKey =
+ "SYSTEM\\CurrentControlSet\\services\\NTP";
+
+ HKEY hkey1 = NULL;
+ HKEY hkey2 = NULL;
+ DWORD rc;
+
+ rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, s_RegKey, 0, KEY_READ, &hkey1);
+ if (ERROR_SUCCESS != rc)
+ return NULL;
+ if (!(szSubKey && *szSubKey))
+ return hkey1;
+
+ rc = RegOpenKeyExA(hkey1, szSubKey, 0, KEY_READ, &hkey2);
+ RegCloseKey(hkey1);
+ if (ERROR_SUCCESS != rc)
+ return NULL;
+ return hkey2;
+}
+
+static char*
+myRegReadMultiString(
+ HKEY hKey ,
+ const char *szValue,
+ DWORD *pSize )
+{
+ char * endp;
+ char * retv = NULL;
+ DWORD rSize = 0, rType = REG_NONE, rc;
+
+ /* take two turns: one to get the size, another one to malloc & read */
+ do {
+ if (rType != REG_NONE) {
+ retv = malloc(rSize += 2);
+ if (NULL == retv)
+ goto fail;
+ }
+ rc = RegQueryValueExA(hKey, szValue, NULL, &rType, retv, &rSize);
+ if (ERROR_SUCCESS != rc || (REG_SZ != rType && REG_MULTI_SZ != rType))
+ goto fail;
+ } while (NULL == retv);
+
+ /* trim trailing NULs and ensure two of them */
+ endp = retv + rSize;
+ while (endp != retv && endp[-1])
+ --endp;
+ if (endp != retv) {
+ endp[0] = endp[1] = '\0';
+ if (NULL != pSize)
+ *pSize = (DWORD)(endp - retv);
+ return retv;
+ }
+fail:
+ free(retv);
+ if (NULL != pSize)
+ *pSize = 0;
+ return NULL;
+}
+
+static DWORD
+myRegReadDWord(
+ HKEY hKey ,
+ const char *szValue,
+ DWORD Default)
+{
+ DWORD rc, rSize, rType, rValue;
+
+ rSize = sizeof(rValue);
+ rc = RegQueryValueExA(hKey, szValue, NULL, &rType, (PBYTE)&rValue, &rSize);
+ if (rc != ERROR_SUCCESS || rSize != sizeof(rValue) || rType != REG_DWORD)
+ rValue = Default;
+ return rValue;
+}
+
+
static pps_handle_t
internal_create_pps_handle(
void * prov_context
return NULL;
}
+static char *
+get_provider_list(void)
+{
+ static char * s_Value = NULL;
+
+ HKEY hKey;
+ DWORD rSize;
+ char *cp, *op;
+
+ if (s_Value != NULL)
+ return (*s_Value) ? s_Value : NULL;
+
+ /*
+ ** try registry first
+ */
+ hKey = myRegOpenKey(NULL);
+ if (NULL == hKey)
+ goto regfail;
+
+ s_Value = myRegReadMultiString(hKey, "PPSProviders", &rSize);
+ if (NULL == s_Value)
+ goto regfail;
+
+ /* make sure we have backslashes in the path */
+ for (cp = s_Value; rSize; --rSize, ++cp)
+ if (*cp == '/')
+ *cp = '\\';
+regfail:
+ if (NULL != hKey)
+ RegCloseKey(hKey);
+
+ if (s_Value && *s_Value)
+ return s_Value;
+
+ /*
+ ** try environment next.
+ */
+ free(s_Value);
+ s_Value = NULL;
+
+ /* try to get env var */
+ cp = getenv("PPSAPI_DLLS");
+ if (!(cp && *cp))
+ goto envfail;
+
+ /* get size & allocate buffer */
+ rSize = strlen(cp);
+ s_Value = malloc(rSize + 2);
+ if (s_Value == NULL)
+ goto envfail;
+
+ /* copy string value and convert to MULTI_SZ.
+ * Converts sequences of ';' to a single NUL byte, and rplaces
+ * slashes by backslashes on the fly.
+ */
+ for (op = s_Value; *cp; ++cp) {
+ if (*cp == '/') {
+ *op++ = '\\';
+ } else if (*cp == ';') {
+ if (op != s_Value && op[-1])
+ *op++ = '\0';
+ } else {
+ *op++ = *cp;
+ }
+ }
+ cp[0] = '\0';
+ cp[1] = '\0';
+ return s_Value;
+
+envfail:
+ free(s_Value);
+ s_Value = calloc(2, 1);
+ return s_Value;
+}
+
+
/* Iteration helper for the provider list. Naked names (without *any*
* path) will be prepended with path to the executable running this
* code. While this was not necessary until Win7, newer versions of
*/
static char*
provlist_next_item(
- const char ** const ppath
+ const char ** iter
)
{
static char * s_modpath /* = NULL */;
static char s_nullstr[1] /* = { '\0' } */;
- const char * phead;
- const char * ptail;
- char * retv;
- char * endp;
+ const char *phead, *phold;
+ char *retv, *endp;
int/*BOOL*/ nodir;
- int ch;
- DWORD slen;
+ DWORD slen, mlen;
- /* check if we're already done */
- if (NULL == (phead = *ppath))
+ /* get next item -- might be start of a new round or the end */
+again:
+ if (*iter == NULL)
+ *iter = phead = get_provider_list();
+ else
+ *iter = phead = *iter + strlen(*iter) + 1;
+ if (!(phead && *phead)) {
+ *iter = NULL;
return NULL;
- /* Skip any leading ';' -- should not happen, but this is
- * user-provided input after all...
+ }
+
+ /* Inspect the next section of input string. It must be
+ * either an absolute path or just a name.
*/
- while (*phead == ';')
- ++phead;
- /* check if we're already done */
- if (!*phead) {
- *ppath = NULL;
- return NULL;
+ if (isalpha((u_char)phead[0]) && phead[1] == ':' && phead[2] == '\\') {
+ nodir = FALSE;
+ } else {
+ nodir = TRUE;
+ phold = phead;
+ while (NULL != (endp = strpbrk(phold, "\\:")))
+ phold = endp + 1;
+ if (phead != phold) {
+ msyslog(LOG_WARNING,
+ "pps api: path component(s) of '%s' ignored, use '%s'",
+ phead, phold);
+ phead = phold;
+ }
}
- /* Inspect the next section of input string. */
- nodir = TRUE;
- for (ptail = phead; (ch = *ptail) && ch != ';'; ++ptail)
- if (ch == '\\' || ch == '/')
- nodir = FALSE;
+ if (!*phead || strchr("\\.:", (u_char)phead[strlen(phead) - 1]))
+ goto again; /* empty or looks like a directory! */
+
/* Make sure we have a proper module path when we need one. */
if (nodir && NULL == s_modpath) {
s_modpath = get_module_path();
}
/* Prepare buffer for copy of file name. */
- slen = (DWORD)(ptail - phead); /* 4GB string should be enough... */
+ slen = (DWORD)strlen(phead); /* 4GB string should be enough... */
if (nodir && NULL != s_modpath) {
/* Prepend full path to executable to the name. */
- endp = retv = malloc(strlen(s_modpath) + slen + 1);
+ mlen = (DWORD)strlen(s_modpath);
+ endp = retv = malloc(mlen + slen + 1);
if (NULL != endp) {
- strcpy(endp, s_modpath);
- endp += strlen(endp);
+ memcpy(endp, s_modpath, mlen);
+ endp += mlen;
}
} else {
endp = retv = malloc(slen + 1u);
}
/* Copy with conversion from '/' to '\\' */
if (NULL != endp) {
- while (phead != ptail) {
- ch = (u_char)*phead++;
- *endp++ = (ch != '/') ? ch : '\\';
- }
- *endp = '\0';
+ memcpy(endp, phead, slen);
+ endp[slen] = '\0';
}
- /*Update scan pointer & return result. */
- *ppath = (*ptail) ? (ptail + 1) : NULL;
return retv;
}
}
+static ppsapi_provider*
+get_first_provider(void)
+{
+ const char * itpos;
+ char * dll;
+ ppsapi_provider *prov, *hold;
+ int err;
+
+ /* check if we have done our work so far... */
+ if (g_provider_list == INVALID_HANDLE_VALUE)
+ return NULL;
+ if (g_provider_list != NULL)
+ return g_provider_list;
+
+ itpos = NULL;
+ while (NULL != (dll = provlist_next_item(&itpos))) {
+ err = load_pps_provider(dll);
+ if (err)
+ msyslog(LOG_ERR, "time_pps_create: load failed (%s) --> %d / %s",
+ dll, err, strerror(err));
+ else
+ msyslog(LOG_INFO, "time_pps_create: loaded '%s'",
+ dll);
+ free(dll);
+ }
+
+ /* reverse the list, possibly mark as EMPTY */
+ prov = g_provider_list;
+ if (NULL != prov) {
+ g_provider_list = NULL;
+ do {
+ hold = prov;
+ prov = hold->next;
+ hold->next = g_provider_list;
+ g_provider_list = hold;
+ } while (prov);
+ prov = g_provider_list;
+ } else {
+ g_provider_list = INVALID_HANDLE_VALUE;
+ }
+ return prov;
+}
+
int
time_pps_create(
int filedes,/* device file descriptor */
)
{
HANDLE winhandle;
- const char * dlls;
- char * dll;
ppsapi_provider * prov;
pps_handle_t ppshandle;
int err;
if (INVALID_HANDLE_VALUE == winhandle)
return set_pps_errno(EBADF);
- /* For initial testing the list of PPSAPI backend providers is
- * provided by the environment variable PPSAPI_DLLS, separated by
- * semicolons such as
- * PPSAPI_DLLS=c:\ntp\serial_ppsapi.dll;..\parport_ppsapi.dll
- * There are a million better ways, such as a well-known registry
- * key under which a value is created for each provider DLL
- * installed, or even a platform-specific ntp.conf directive or
- * command-line switch.
- *
- * [Bug 3139] Since nothing is more durable than a provisional
- * implementation, we're still stuck with that...
- */
- dlls = getenv("PPSAPI_DLLS");
- if (NULL != dlls && NULL == g_provider_list) {
- msyslog(LOG_INFO, "time_pps_create: load list '%s'",
- dlls);
- } else
- dlls = NULL;
-
- while (NULL != (dll = provlist_next_item(&dlls))) {
- err = load_pps_provider(dll);
- if (err) {
- msyslog(LOG_ERR, "time_pps_create: load failed (%s) --> %d / %s",
- dll, err, strerror(err));
- } else {
- msyslog(LOG_INFO, "time_pps_create: loaded '%s'",
- dll);
- }
- free(dll);
- }
-
/* Hand off to each provider in turn until one returns a PPS
* handle or they've all declined.
*
* this provides slightly more information.
*/
err = ENOEXEC;
- if (NULL == g_provider_list) {
+ prov = get_first_provider();
+ if (NULL == prov) {
msyslog(LOG_ERR, "time_pps_create: %s",
"no providers available");
return set_pps_errno(err);
- }
- for (prov = g_provider_list; NULL != prov; prov = prov->next) {
+ } else do {
ppshandle = 0;
g_curr_provider = prov;
err = (*prov->ptime_pps_create)(winhandle, &ppshandle);
g_curr_provider = NULL;
if (!err && ppshandle) {
*phandle = ppshandle;
+ ppsu_register(ppshandle, serial_devctx(winhandle));
return 0;
}
msyslog(LOG_INFO, "time_pps_create: provider '%s' failed: %d / %s",
prov->short_name, err, strerror(err));
- }
+ } while (NULL != (prov = prov->next));
+
msyslog(LOG_ERR, "time_pps_create: %s",
"all providers failed");
return set_pps_errno(err);
if (NULL == punit)
return set_pps_errno(EBADF);
/* Call provider. Note the handle is gone anyway... */
+ ppsu_remove(handle);
err = (*punit->provider->ptime_pps_destroy)(punit, punit->context);
free(punit);
if (err)