settings.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. #include "nssm.h"
  2. /* XXX: (value && value->string) is probably bogus because value is probably never null */
  3. extern const TCHAR *exit_action_strings[];
  4. extern const TCHAR *startup_strings[];
  5. /* Does the parameter refer to the default value of the AppExit setting? */
  6. static inline int is_default_exit_action(const TCHAR *value) {
  7. return (str_equiv(value, _T("default")) || str_equiv(value, _T("*")) || ! value[0]);
  8. }
  9. static int value_from_string(const TCHAR *name, value_t *value, const TCHAR *string) {
  10. size_t len = _tcslen(string);
  11. if (! len++) {
  12. value->string = 0;
  13. return 0;
  14. }
  15. value->string = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));
  16. if (! value->string) {
  17. print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, name, _T("value_from_string()"));
  18. return -1;
  19. }
  20. if (_sntprintf_s(value->string, len, _TRUNCATE, _T("%s"), string) < 0) {
  21. HeapFree(GetProcessHeap(), 0, value->string);
  22. print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, name, _T("value_from_string()"));
  23. return -1;
  24. }
  25. return 1;
  26. }
  27. /* Functions to manage NSSM-specific settings in the registry. */
  28. static int setting_set_number(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  29. HKEY key = (HKEY) param;
  30. if (! key) return -1;
  31. unsigned long number;
  32. long error;
  33. /* Resetting to default? */
  34. if (! value || ! value->string) {
  35. error = RegDeleteValue(key, name);
  36. if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
  37. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
  38. return -1;
  39. }
  40. if (str_number(value->string, &number)) return -1;
  41. if (default_value && number == (unsigned long) default_value) {
  42. error = RegDeleteValue(key, name);
  43. if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
  44. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
  45. return -1;
  46. }
  47. if (set_number(key, (TCHAR *) name, number)) return -1;
  48. return 1;
  49. }
  50. static int setting_get_number(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  51. HKEY key = (HKEY) param;
  52. return get_number(key, (TCHAR *) name, &value->numeric, false);
  53. }
  54. static int setting_set_string(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  55. HKEY key = (HKEY) param;
  56. if (! key) return -1;
  57. long error;
  58. /* Resetting to default? */
  59. if (! value || ! value->string) {
  60. if (default_value) value->string = (TCHAR *) default_value;
  61. else {
  62. error = RegDeleteValue(key, name);
  63. if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
  64. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
  65. return -1;
  66. }
  67. }
  68. if (default_value && _tcslen((TCHAR *) default_value) && str_equiv(value->string, (TCHAR *) default_value)) {
  69. error = RegDeleteValue(key, name);
  70. if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
  71. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
  72. return -1;
  73. }
  74. if (set_expand_string(key, (TCHAR *) name, value->string)) return -1;
  75. return 1;
  76. }
  77. static int setting_get_string(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  78. HKEY key = (HKEY) param;
  79. TCHAR buffer[VALUE_LENGTH];
  80. if (expand_parameter(key, (TCHAR *) name, (TCHAR *) buffer, (unsigned long) sizeof(buffer), false, false)) return -1;
  81. return value_from_string(name, value, buffer);
  82. }
  83. static int setting_set_exit_action(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  84. unsigned long exitcode;
  85. TCHAR *code;
  86. TCHAR action_string[ACTION_LEN];
  87. if (additional) {
  88. /* Default action? */
  89. if (is_default_exit_action(additional)) code = 0;
  90. else {
  91. if (str_number(additional, &exitcode)) return -1;
  92. code = (TCHAR *) additional;
  93. }
  94. }
  95. HKEY key = open_registry(service_name, name, KEY_WRITE);
  96. if (! key) return -1;
  97. long error;
  98. int ret = 1;
  99. /* Resetting to default? */
  100. if (value && value->string) _sntprintf_s(action_string, _countof(action_string), _TRUNCATE, _T("%s"), value->string);
  101. else {
  102. if (code) {
  103. /* Delete explicit action. */
  104. error = RegDeleteValue(key, code);
  105. RegCloseKey(key);
  106. if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
  107. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, code, service_name, error_string(error));
  108. return -1;
  109. }
  110. else {
  111. /* Explicitly keep the default action. */
  112. if (default_value) _sntprintf_s(action_string, _countof(action_string), _TRUNCATE, _T("%s"), (TCHAR *) default_value);
  113. ret = 0;
  114. }
  115. }
  116. /* Validate the string. */
  117. for (int i = 0; exit_action_strings[i]; i++) {
  118. if (! _tcsnicmp((const TCHAR *) action_string, exit_action_strings[i], ACTION_LEN)) {
  119. if (default_value && str_equiv(action_string, (TCHAR *) default_value)) ret = 0;
  120. if (RegSetValueEx(key, code, 0, REG_SZ, (const unsigned char *) action_string, (unsigned long) (_tcslen(action_string) + 1) * sizeof(TCHAR)) != ERROR_SUCCESS) {
  121. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, code, service_name, error_string(GetLastError()));
  122. RegCloseKey(key);
  123. return -1;
  124. }
  125. RegCloseKey(key);
  126. return ret;
  127. }
  128. }
  129. print_message(stderr, NSSM_MESSAGE_INVALID_EXIT_ACTION, action_string);
  130. for (int i = 0; exit_action_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), exit_action_strings[i]);
  131. return -1;
  132. }
  133. static int setting_get_exit_action(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  134. unsigned long exitcode = 0;
  135. unsigned long *code = 0;
  136. if (additional) {
  137. if (! is_default_exit_action(additional)) {
  138. if (str_number(additional, &exitcode)) return -1;
  139. code = &exitcode;
  140. }
  141. }
  142. TCHAR action_string[ACTION_LEN];
  143. bool default_action;
  144. if (get_exit_action(service_name, code, action_string, &default_action)) return -1;
  145. value_from_string(name, value, action_string);
  146. if (default_action && ! _tcsnicmp((const TCHAR *) action_string, (TCHAR *) default_value, ACTION_LEN)) return 0;
  147. return 1;
  148. }
  149. static int setting_set_environment(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  150. HKEY key = (HKEY) param;
  151. if (! param) return -1;
  152. if (! value || ! value->string || ! value->string[0]) {
  153. long error = RegDeleteValue(key, name);
  154. if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0;
  155. print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error));
  156. return -1;
  157. }
  158. unsigned long envlen = (unsigned long) _tcslen(value->string) + 1;
  159. TCHAR *unformatted = 0;
  160. unsigned long newlen;
  161. if (unformat_environment(value->string, envlen, &unformatted, &newlen)) return -1;
  162. if (test_environment(unformatted)) {
  163. HeapFree(GetProcessHeap(), 0, unformatted);
  164. print_message(stderr, NSSM_GUI_INVALID_ENVIRONMENT);
  165. return -1;
  166. }
  167. if (RegSetValueEx(key, name, 0, REG_MULTI_SZ, (const unsigned char *) unformatted, (unsigned long) newlen * sizeof(TCHAR)) != ERROR_SUCCESS) {
  168. if (newlen) HeapFree(GetProcessHeap(), 0, unformatted);
  169. log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_SETVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);
  170. return -1;
  171. }
  172. if (newlen) HeapFree(GetProcessHeap(), 0, unformatted);
  173. return 1;
  174. }
  175. static int setting_get_environment(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  176. HKEY key = (HKEY) param;
  177. if (! param) return -1;
  178. TCHAR *env = 0;
  179. unsigned long envlen;
  180. if (set_environment((TCHAR *) service_name, key, (TCHAR *) name, &env, &envlen)) return -1;
  181. if (! envlen) return 0;
  182. TCHAR *formatted;
  183. unsigned long newlen;
  184. if (format_environment(env, envlen, &formatted, &newlen)) return -1;
  185. int ret;
  186. if (additional) {
  187. /* Find named environment variable. */
  188. TCHAR *s;
  189. size_t len = _tcslen(additional);
  190. for (s = env; *s; s++) {
  191. /* Look for <additional>=<string> NULL NULL */
  192. if (! _tcsnicmp(s, additional, len) && s[len] == _T('=')) {
  193. /* Strip <key>= */
  194. s += len + 1;
  195. ret = value_from_string(name, value, s);
  196. HeapFree(GetProcessHeap(), 0, env);
  197. return ret;
  198. }
  199. /* Skip this string. */
  200. for ( ; *s; s++);
  201. }
  202. HeapFree(GetProcessHeap(), 0, env);
  203. return 0;
  204. }
  205. HeapFree(GetProcessHeap(), 0, env);
  206. ret = value_from_string(name, value, formatted);
  207. if (newlen) HeapFree(GetProcessHeap(), 0, formatted);
  208. return ret;
  209. }
  210. /* Functions to manage native service settings. */
  211. int native_set_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  212. SC_HANDLE service_handle = (SC_HANDLE) param;
  213. if (! service_handle) return -1;
  214. TCHAR *description = 0;
  215. if (value) description = value->string;
  216. if (set_service_description(service_name, service_handle, description)) return -1;
  217. if (description && description[0]) return 1;
  218. return 0;
  219. }
  220. int native_get_description(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  221. SC_HANDLE service_handle = (SC_HANDLE) param;
  222. if (! service_handle) return -1;
  223. TCHAR buffer[VALUE_LENGTH];
  224. if (get_service_description(service_name, service_handle, _countof(buffer), buffer)) return -1;
  225. if (buffer[0]) return value_from_string(name, value, buffer);
  226. value->string = 0;
  227. return 0;
  228. }
  229. int native_set_displayname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  230. SC_HANDLE service_handle = (SC_HANDLE) param;
  231. if (! service_handle) return -1;
  232. TCHAR *displayname = 0;
  233. if (value && value->string) displayname = value->string;
  234. else displayname = (TCHAR *) service_name;
  235. if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, displayname)) {
  236. print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
  237. return -1;
  238. }
  239. /*
  240. If the display name and service name differ only in case,
  241. ChangeServiceConfig() will return success but the display name will be
  242. set to the service name, NOT the value passed to the function.
  243. This appears to be a quirk of Windows rather than a bug here.
  244. */
  245. if (displayname != service_name && ! str_equiv(displayname, service_name)) return 1;
  246. return 0;
  247. }
  248. int native_get_displayname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  249. SC_HANDLE service_handle = (SC_HANDLE) param;
  250. if (! service_handle) return -1;
  251. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  252. if (! qsc) return -1;
  253. int ret = value_from_string(name, value, qsc->lpDisplayName);
  254. HeapFree(GetProcessHeap(), 0, qsc);
  255. return ret;
  256. }
  257. int native_set_imagepath(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  258. SC_HANDLE service_handle = (SC_HANDLE) param;
  259. if (! service_handle) return -1;
  260. /* It makes no sense to try to reset the image path. */
  261. if (! value || ! value->string) {
  262. print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
  263. return -1;
  264. }
  265. if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, value->string, 0, 0, 0, 0, 0, 0)) {
  266. print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
  267. return -1;
  268. }
  269. return 1;
  270. }
  271. int native_get_imagepath(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  272. SC_HANDLE service_handle = (SC_HANDLE) param;
  273. if (! service_handle) return -1;
  274. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  275. if (! qsc) return -1;
  276. int ret = value_from_string(name, value, qsc->lpBinaryPathName);
  277. HeapFree(GetProcessHeap(), 0, qsc);
  278. return ret;
  279. }
  280. int native_set_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  281. SC_HANDLE service_handle = (SC_HANDLE) param;
  282. if (! service_handle) return -1;
  283. /*
  284. Logical syntax is: nssm set <service> ObjectName <username> <password>
  285. That means the username is actually passed in the additional parameter.
  286. */
  287. bool localsystem = true;
  288. TCHAR *username = NSSM_LOCALSYSTEM_ACCOUNT;
  289. TCHAR *password = 0;
  290. if (additional) {
  291. if (! str_equiv(additional, NSSM_LOCALSYSTEM_ACCOUNT)) {
  292. localsystem = false;
  293. username = (TCHAR *) additional;
  294. if (value && value->string) password = value->string;
  295. else {
  296. /* We need a password if the account is not LOCALSYSTEM. */
  297. print_message(stderr, NSSM_MESSAGE_MISSING_PASSWORD, name);
  298. return -1;
  299. }
  300. }
  301. }
  302. /*
  303. ChangeServiceConfig() will fail to set the username if the service is set
  304. to interact with the desktop.
  305. */
  306. unsigned long type = SERVICE_NO_CHANGE;
  307. if (! localsystem) {
  308. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  309. if (! qsc) {
  310. if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
  311. return -1;
  312. }
  313. type = qsc->dwServiceType & ~SERVICE_INTERACTIVE_PROCESS;
  314. HeapFree(GetProcessHeap(), 0, qsc);
  315. }
  316. if (grant_logon_as_service(username)) {
  317. if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
  318. print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username);
  319. return -1;
  320. }
  321. if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, username, password, 0)) {
  322. if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
  323. print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
  324. return -1;
  325. }
  326. if (password) SecureZeroMemory(password, _tcslen(password) * sizeof(TCHAR));
  327. if (localsystem) return 0;
  328. return 1;
  329. }
  330. int native_get_objectname(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  331. SC_HANDLE service_handle = (SC_HANDLE) param;
  332. if (! service_handle) return -1;
  333. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  334. if (! qsc) return -1;
  335. int ret = value_from_string(name, value, qsc->lpServiceStartName);
  336. HeapFree(GetProcessHeap(), 0, qsc);
  337. return ret;
  338. }
  339. int native_set_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  340. SC_HANDLE service_handle = (SC_HANDLE) param;
  341. if (! service_handle) return -1;
  342. /* It makes no sense to try to reset the startup type. */
  343. if (! value || ! value->string) {
  344. print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
  345. return -1;
  346. }
  347. /* Map NSSM_STARTUP_* constant to Windows SERVICE_*_START constant. */
  348. int service_startup = -1;
  349. int i;
  350. for (i = 0; startup_strings[i]; i++) {
  351. if (str_equiv(value->string, startup_strings[i])) {
  352. service_startup = i;
  353. break;
  354. }
  355. }
  356. if (service_startup < 0) {
  357. print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_STARTUP, value->string);
  358. for (i = 0; startup_strings[i]; i++) _ftprintf(stderr, _T("%s\n"), startup_strings[i]);
  359. return -1;
  360. }
  361. unsigned long startup;
  362. switch (service_startup) {
  363. case NSSM_STARTUP_MANUAL: startup = SERVICE_DEMAND_START; break;
  364. case NSSM_STARTUP_DISABLED: startup = SERVICE_DISABLED; break;
  365. default: startup = SERVICE_AUTO_START;
  366. }
  367. if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, startup, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
  368. print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
  369. return -1;
  370. }
  371. SERVICE_DELAYED_AUTO_START_INFO delayed;
  372. ZeroMemory(&delayed, sizeof(delayed));
  373. if (service_startup == NSSM_STARTUP_DELAYED) delayed.fDelayedAutostart = 1;
  374. else delayed.fDelayedAutostart = 0;
  375. if (! ChangeServiceConfig2(service_handle, SERVICE_CONFIG_DELAYED_AUTO_START_INFO, &delayed)) {
  376. unsigned long error = GetLastError();
  377. /* Pre-Vista we expect to fail with ERROR_INVALID_LEVEL */
  378. if (error != ERROR_INVALID_LEVEL) {
  379. log_event(EVENTLOG_ERROR_TYPE, NSSM_MESSAGE_SERVICE_CONFIG_DELAYED_AUTO_START_INFO_FAILED, service_name, error_string(error), 0);
  380. }
  381. }
  382. return 1;
  383. }
  384. int native_get_startup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  385. SC_HANDLE service_handle = (SC_HANDLE) param;
  386. if (! service_handle) return -1;
  387. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  388. if (! qsc) return -1;
  389. unsigned long startup;
  390. int ret = get_service_startup(service_name, service_handle, qsc, &startup);
  391. HeapFree(GetProcessHeap(), 0, qsc);
  392. if (ret) return -1;
  393. unsigned long i;
  394. for (i = 0; startup_strings[i]; i++);
  395. if (startup >= i) return -1;
  396. return value_from_string(name, value, startup_strings[startup]);
  397. }
  398. int native_set_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  399. SC_HANDLE service_handle = (SC_HANDLE) param;
  400. if (! service_handle) return -1;
  401. /* It makes no sense to try to reset the service type. */
  402. if (! value || ! value->string) {
  403. print_message(stderr, NSSM_MESSAGE_NO_DEFAULT_VALUE, name);
  404. return -1;
  405. }
  406. /*
  407. We can only manage services of type SERVICE_WIN32_OWN_PROCESS
  408. and SERVICE_INTERACTIVE_PROCESS.
  409. */
  410. unsigned long type = SERVICE_WIN32_OWN_PROCESS;
  411. if (str_equiv(value->string, NSSM_INTERACTIVE_PROCESS)) type |= SERVICE_INTERACTIVE_PROCESS;
  412. else if (! str_equiv(value->string, NSSM_WIN32_OWN_PROCESS)) {
  413. print_message(stderr, NSSM_MESSAGE_INVALID_SERVICE_TYPE, value->string);
  414. _ftprintf(stderr, _T("%s\n"), NSSM_WIN32_OWN_PROCESS);
  415. _ftprintf(stderr, _T("%s\n"), NSSM_INTERACTIVE_PROCESS);
  416. return -1;
  417. }
  418. /*
  419. ChangeServiceConfig() will fail if the service runs under an account
  420. other than LOCALSYSTEM and we try to make it interactive.
  421. */
  422. if (type & SERVICE_INTERACTIVE_PROCESS) {
  423. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  424. if (! qsc) return -1;
  425. if (! str_equiv(qsc->lpServiceStartName, NSSM_LOCALSYSTEM_ACCOUNT)) {
  426. HeapFree(GetProcessHeap(), 0, qsc);
  427. print_message(stderr, NSSM_MESSAGE_INTERACTIVE_NOT_LOCALSYSTEM, value->string, service_name, NSSM_LOCALSYSTEM_ACCOUNT);
  428. return -1;
  429. }
  430. HeapFree(GetProcessHeap(), 0, qsc);
  431. }
  432. if (! ChangeServiceConfig(service_handle, type, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, 0, 0, 0, 0)) {
  433. print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));
  434. return -1;
  435. }
  436. return 1;
  437. }
  438. int native_get_type(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {
  439. SC_HANDLE service_handle = (SC_HANDLE) param;
  440. if (! service_handle) return -1;
  441. QUERY_SERVICE_CONFIG *qsc = query_service_config(service_name, service_handle);
  442. if (! qsc) return -1;
  443. value->numeric = qsc->dwServiceType;
  444. HeapFree(GetProcessHeap(), 0, qsc);
  445. const TCHAR *string;
  446. switch (value->numeric) {
  447. case SERVICE_KERNEL_DRIVER: string = NSSM_KERNEL_DRIVER; break;
  448. case SERVICE_FILE_SYSTEM_DRIVER: string = NSSM_FILE_SYSTEM_DRIVER; break;
  449. case SERVICE_WIN32_OWN_PROCESS: string = NSSM_WIN32_OWN_PROCESS; break;
  450. case SERVICE_WIN32_SHARE_PROCESS: string = NSSM_WIN32_SHARE_PROCESS; break;
  451. case SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_INTERACTIVE_PROCESS; break;
  452. case SERVICE_WIN32_SHARE_PROCESS|SERVICE_INTERACTIVE_PROCESS: string = NSSM_SHARE_INTERACTIVE_PROCESS; break;
  453. default: string = NSSM_UNKNOWN;
  454. }
  455. return value_from_string(name, value, string);
  456. }
  457. int set_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
  458. if (! key) return -1;
  459. int ret;
  460. if (setting->set) ret = setting->set(service_name, (void *) key, setting->name, setting->default_value, value, additional);
  461. else ret = -1;
  462. if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
  463. else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
  464. else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
  465. return ret;
  466. }
  467. int set_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
  468. if (! service_handle) return -1;
  469. int ret;
  470. if (setting->set) ret = setting->set(service_name, service_handle, setting->name, setting->default_value, value, additional);
  471. else ret = -1;
  472. if (! ret) print_message(stdout, NSSM_MESSAGE_RESET_SETTING, setting->name, service_name);
  473. else if (ret > 0) print_message(stdout, NSSM_MESSAGE_SET_SETTING, setting->name, service_name);
  474. else print_message(stderr, NSSM_MESSAGE_SET_SETTING_FAILED, setting->name, service_name);
  475. return ret;
  476. }
  477. /*
  478. Returns: 1 if the value was retrieved.
  479. 0 if the default value was retrieved.
  480. -1 on error.
  481. */
  482. int get_setting(const TCHAR *service_name, HKEY key, settings_t *setting, value_t *value, const TCHAR *additional) {
  483. if (! key) return -1;
  484. int ret;
  485. switch (setting->type) {
  486. case REG_EXPAND_SZ:
  487. case REG_MULTI_SZ:
  488. case REG_SZ:
  489. value->string = (TCHAR *) setting->default_value;
  490. if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
  491. else ret = -1;
  492. break;
  493. case REG_DWORD:
  494. value->numeric = (unsigned long) setting->default_value;
  495. if (setting->get) ret = setting->get(service_name, (void *) key, setting->name, setting->default_value, value, additional);
  496. else ret = -1;
  497. break;
  498. default:
  499. ret = -1;
  500. break;
  501. }
  502. if (ret < 0) print_message(stderr, NSSM_MESSAGE_GET_SETTING_FAILED, setting->name, service_name);
  503. return ret;
  504. }
  505. int get_setting(const TCHAR *service_name, SC_HANDLE service_handle, settings_t *setting, value_t *value, const TCHAR *additional) {
  506. if (! service_handle) return -1;
  507. return setting->get(service_name, service_handle, setting->name, 0, value, additional);
  508. }
  509. settings_t settings[] = {
  510. { NSSM_REG_EXE, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
  511. { NSSM_REG_FLAGS, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
  512. { NSSM_REG_DIR, REG_EXPAND_SZ, (void *) _T(""), false, 0, setting_set_string, setting_get_string },
  513. { NSSM_REG_EXIT, REG_SZ, (void *) exit_action_strings[NSSM_EXIT_RESTART], false, ADDITIONAL_MANDATORY, setting_set_exit_action, setting_get_exit_action },
  514. { NSSM_REG_ENV, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
  515. { NSSM_REG_ENV_EXTRA, REG_MULTI_SZ, NULL, false, ADDITIONAL_CRLF, setting_set_environment, setting_get_environment },
  516. { NSSM_REG_STDIN, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
  517. { NSSM_REG_STDIN NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDIN_SHARING, false, 0, setting_set_number, setting_get_number },
  518. { NSSM_REG_STDIN NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDIN_DISPOSITION, false, 0, setting_set_number, setting_get_number },
  519. { NSSM_REG_STDIN NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDIN_FLAGS, false, 0, setting_set_number, setting_get_number },
  520. { NSSM_REG_STDOUT, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
  521. { NSSM_REG_STDOUT NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDOUT_SHARING, false, 0, setting_set_number, setting_get_number },
  522. { NSSM_REG_STDOUT NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDOUT_DISPOSITION, false, 0, setting_set_number, setting_get_number },
  523. { NSSM_REG_STDOUT NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDOUT_FLAGS, false, 0, setting_set_number, setting_get_number },
  524. { NSSM_REG_STDERR, REG_EXPAND_SZ, NULL, false, 0, setting_set_string, setting_get_string },
  525. { NSSM_REG_STDERR NSSM_REG_STDIO_SHARING, REG_DWORD, (void *) NSSM_STDERR_SHARING, false, 0, setting_set_number, setting_get_number },
  526. { NSSM_REG_STDERR NSSM_REG_STDIO_DISPOSITION, REG_DWORD, (void *) NSSM_STDERR_DISPOSITION, false, 0, setting_set_number, setting_get_number },
  527. { NSSM_REG_STDERR NSSM_REG_STDIO_FLAGS, REG_DWORD, (void *) NSSM_STDERR_FLAGS, false, 0, setting_set_number, setting_get_number },
  528. { NSSM_REG_STOP_METHOD_SKIP, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
  529. { NSSM_REG_KILL_CONSOLE_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_CONSOLE_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
  530. { NSSM_REG_KILL_WINDOW_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_WINDOW_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
  531. { NSSM_REG_KILL_THREADS_GRACE_PERIOD, REG_DWORD, (void *) NSSM_KILL_THREADS_GRACE_PERIOD, false, 0, setting_set_number, setting_get_number },
  532. { NSSM_REG_THROTTLE, REG_DWORD, (void *) NSSM_RESET_THROTTLE_RESTART, false, 0, setting_set_number, setting_get_number },
  533. { NSSM_REG_ROTATE, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
  534. { NSSM_REG_ROTATE_SECONDS, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
  535. { NSSM_REG_ROTATE_BYTES_LOW, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
  536. { NSSM_REG_ROTATE_BYTES_HIGH, REG_DWORD, 0, false, 0, setting_set_number, setting_get_number },
  537. { NSSM_NATIVE_DESCRIPTION, REG_SZ, _T(""), true, 0, native_set_description, native_get_description },
  538. { NSSM_NATIVE_DISPLAYNAME, REG_SZ, NULL, true, 0, native_set_displayname, native_get_displayname },
  539. { NSSM_NATIVE_IMAGEPATH, REG_EXPAND_SZ, NULL, true, 0, native_set_imagepath, native_get_imagepath },
  540. { NSSM_NATIVE_OBJECTNAME, REG_SZ, NSSM_LOCALSYSTEM_ACCOUNT, true, ADDITIONAL_SETTING, native_set_objectname, native_get_objectname },
  541. { NSSM_NATIVE_STARTUP, REG_SZ, NULL, true, 0, native_set_startup, native_get_startup },
  542. { NSSM_NATIVE_TYPE, REG_SZ, NULL, true, 0, native_set_type, native_get_type },
  543. { NULL, NULL, NULL, NULL, NULL }
  544. };