1 /* 2 * winrc/w_inst.h - install and remove functions 3 * 4 * Copyright (c) 2009, NLnet Labs. All rights reserved. 5 * 6 * This software is open source. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * Neither the name of the NLNET LABS nor the names of its contributors may 20 * be used to endorse or promote products derived from this software without 21 * specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 36 /** 37 * \file 38 * 39 * Contains install and remove functions that manipulate the 40 * windows services API and windows registry. 41 */ 42 #include "config.h" 43 #include "winrc/w_inst.h" 44 #include "winrc/win_svc.h" 45 46 void wsvc_err2str(char* str, size_t len, const char* fixed, DWORD err) 47 { 48 LPTSTR buf; 49 if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | 50 FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER, 51 NULL, err, 0, (LPTSTR)&buf, 0, NULL) == 0) { 52 /* could not format error message */ 53 snprintf(str, len, "%s GetLastError=%d", fixed, (int)err); 54 return; 55 } 56 snprintf(str, len, "%s (err=%d): %s", fixed, (int)err, buf); 57 LocalFree(buf); 58 } 59 60 /** exit with windows error */ 61 static void 62 fatal_win(FILE* out, const char* str) 63 { 64 char e[256]; 65 wsvc_err2str(e, sizeof(e), str, (int)GetLastError()); 66 if(out) fprintf(out, "%s\n", e); 67 else fprintf(stderr, "%s\n", e); 68 exit(1); 69 } 70 71 /** install registry entries for eventlog */ 72 static void 73 event_reg_install(FILE* out, const char* pathname) 74 { 75 char buf[1024]; 76 HKEY hk; 77 DWORD t; 78 if(out) fprintf(out, "install reg entries for %s\n", pathname); 79 snprintf(buf, sizeof(buf), "SYSTEM\\CurrentControlSet\\Services" 80 "\\EventLog\\Application\\%s", SERVICE_NAME); 81 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)buf, 82 0, /* reserved, mustbezero */ 83 NULL, /* class of key, ignored */ 84 REG_OPTION_NON_VOLATILE, /* values saved on disk */ 85 KEY_WRITE, /* we want write permission */ 86 NULL, /* use default security descriptor */ 87 &hk, /* result */ 88 NULL)) /* not interested if key new or existing */ 89 fatal_win(out, "could not create registry key"); 90 91 /* message file */ 92 if(RegSetValueEx(hk, (LPCTSTR)"EventMessageFile", 93 0, /* reserved, mustbezero */ 94 REG_EXPAND_SZ, /* value type (string w env subst) */ 95 (BYTE*)pathname, /* data */ 96 (DWORD)strlen(pathname)+1)) /* length of data */ 97 { 98 RegCloseKey(hk); 99 fatal_win(out, "could not registry set EventMessageFile"); 100 } 101 102 /* event types */ 103 t = EVENTLOG_SUCCESS | EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE 104 | EVENTLOG_INFORMATION_TYPE; 105 if(RegSetValueEx(hk, (LPCTSTR)"TypesSupported", 0, REG_DWORD, 106 (LPBYTE)&t, sizeof(t))) { 107 RegCloseKey(hk); 108 fatal_win(out, "could not registry set TypesSupported"); 109 } 110 111 /* category message file */ 112 if(RegSetValueEx(hk, (LPCTSTR)"CategoryMessageFile", 0, REG_EXPAND_SZ, 113 (BYTE*)pathname, (DWORD)strlen(pathname)+1)) { 114 RegCloseKey(hk); 115 fatal_win(out, "could not registry set CategoryMessageFile"); 116 } 117 t = 1; 118 if(RegSetValueEx(hk, (LPCTSTR)"CategoryCount", 0, REG_DWORD, 119 (LPBYTE)&t, sizeof(t))) { 120 RegCloseKey(hk); 121 fatal_win(out, "could not registry set CategoryCount"); 122 } 123 124 125 RegCloseKey(hk); 126 if(out) fprintf(out, "installed reg entries\n"); 127 } 128 129 /** remove registry entries for eventlog */ 130 static void 131 event_reg_remove(FILE* out) 132 { 133 char buf[1024]; 134 HKEY hk; 135 if(out) fprintf(out, "remove reg entries\n"); 136 snprintf(buf, sizeof(buf), "SYSTEM\\CurrentControlSet\\Services" 137 "\\EventLog\\Application"); 138 if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, (LPCTSTR)buf, 139 0, /* reserved, mustbezero */ 140 NULL, /* class of key, ignored */ 141 REG_OPTION_NON_VOLATILE, /* values saved on disk */ 142 DELETE, /* we want key delete permission */ 143 NULL, /* use default security descriptor */ 144 &hk, /* result */ 145 NULL)) /* not interested if key new or existing */ 146 fatal_win(out, "could not open registry key"); 147 if(RegDeleteKey(hk, (LPCTSTR)SERVICE_NAME)) { 148 RegCloseKey(hk); 149 fatal_win(out, "could not delete registry key"); 150 } 151 RegCloseKey(hk); 152 if(out) fprintf(out, "removed reg entries\n"); 153 } 154 155 /** 156 * put quotes around string. Needs one space in front 157 * @param out: debugfile 158 * @param str: to be quoted. 159 * @param maxlen: max length of the string buffer. 160 */ 161 static void 162 quote_it(FILE* out, char* str, size_t maxlen) 163 { 164 if(strlen(str) == maxlen) { 165 if(out) fprintf(out, "string too long %s", str); 166 exit(1); 167 } 168 str[0]='"'; 169 str[strlen(str)+1]=0; 170 str[strlen(str)]='"'; 171 } 172 173 /** change suffix */ 174 static void 175 change(FILE* out, char* path, size_t max, const char* from, const char* to) 176 { 177 size_t fromlen = strlen(from); 178 size_t tolen = strlen(to); 179 size_t pathlen = strlen(path); 180 if(pathlen - fromlen + tolen >= max) { 181 if(out) fprintf(out, "string too long %s", path); 182 exit(1); 183 } 184 snprintf(path+pathlen-fromlen, max-(pathlen-fromlen), "%s", to); 185 } 186 187 /* Install service in servicecontrolmanager */ 188 void 189 wsvc_install(FILE* out, const char* rename) 190 { 191 SC_HANDLE scm; 192 SC_HANDLE sv; 193 TCHAR path[2*MAX_PATH+4+256]; 194 TCHAR path_config[2*MAX_PATH+4+256]; 195 if(out) fprintf(out, "installing unbound service\n"); 196 if(!GetModuleFileName(NULL, path+1, MAX_PATH)) 197 fatal_win(out, "could not GetModuleFileName"); 198 /* change 'unbound-service-install' to 'unbound' */ 199 if(rename) { 200 change(out, path+1, sizeof(path)-1, rename, "unbound.exe"); 201 memmove(path_config+1, path+1, sizeof(path)-1); 202 change(out, path_config+1, sizeof(path_config)-1, 203 "unbound.exe", "service.conf"); 204 } 205 206 event_reg_install(out, path+1); 207 208 /* have to quote it because of spaces in directory names */ 209 /* could append arguments to be sent to ServiceMain */ 210 quote_it(out, path, sizeof(path)); 211 212 /* if we started in a different directory, also read config from it. */ 213 if(rename) { 214 quote_it(out, path_config, sizeof(path_config)); 215 strcat(path, " -c "); 216 strcat(path, path_config); 217 } 218 219 strcat(path, " -w service"); 220 scm = OpenSCManager(NULL, NULL, (int)SC_MANAGER_CREATE_SERVICE); 221 if(!scm) fatal_win(out, "could not OpenSCManager"); 222 sv = CreateService( 223 scm, 224 SERVICE_NAME, /* name of service */ 225 "Unbound DNS validator", /* display name */ 226 SERVICE_ALL_ACCESS, /* desired access */ 227 SERVICE_WIN32_OWN_PROCESS, /* service type */ 228 SERVICE_AUTO_START, /* start type */ 229 SERVICE_ERROR_NORMAL, /* error control type */ 230 path, /* path to service's binary */ 231 NULL, /* no load ordering group */ 232 NULL, /* no tag identifier */ 233 NULL, /* no deps */ 234 NULL, /* on LocalSystem */ 235 NULL /* no password */ 236 ); 237 if(!sv) { 238 CloseServiceHandle(scm); 239 fatal_win(out, "could not CreateService"); 240 } 241 CloseServiceHandle(sv); 242 CloseServiceHandle(scm); 243 if(out) fprintf(out, "unbound service installed\n"); 244 } 245 246 247 /* Remove installed service from servicecontrolmanager */ 248 void 249 wsvc_remove(FILE* out) 250 { 251 SC_HANDLE scm; 252 SC_HANDLE sv; 253 if(out) fprintf(out, "removing unbound service\n"); 254 scm = OpenSCManager(NULL, NULL, (int)SC_MANAGER_ALL_ACCESS); 255 if(!scm) fatal_win(out, "could not OpenSCManager"); 256 sv = OpenService(scm, SERVICE_NAME, DELETE); 257 if(!sv) { 258 CloseServiceHandle(scm); 259 fatal_win(out, "could not OpenService"); 260 } 261 if(!DeleteService(sv)) { 262 CloseServiceHandle(sv); 263 CloseServiceHandle(scm); 264 fatal_win(out, "could not DeleteService"); 265 } 266 CloseServiceHandle(sv); 267 CloseServiceHandle(scm); 268 event_reg_remove(out); 269 if(out) fprintf(out, "unbound service removed\n"); 270 } 271 272 273 /* Start daemon */ 274 void 275 wsvc_rc_start(FILE* out) 276 { 277 SC_HANDLE scm; 278 SC_HANDLE sv; 279 if(out) fprintf(out, "start unbound service\n"); 280 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 281 if(!scm) fatal_win(out, "could not OpenSCManager"); 282 sv = OpenService(scm, SERVICE_NAME, SERVICE_START); 283 if(!sv) { 284 CloseServiceHandle(scm); 285 fatal_win(out, "could not OpenService"); 286 } 287 if(!StartService(sv, 0, NULL)) { 288 CloseServiceHandle(sv); 289 CloseServiceHandle(scm); 290 fatal_win(out, "could not StartService"); 291 } 292 CloseServiceHandle(sv); 293 CloseServiceHandle(scm); 294 if(out) fprintf(out, "unbound service started\n"); 295 } 296 297 298 /* Stop daemon */ 299 void 300 wsvc_rc_stop(FILE* out) 301 { 302 SC_HANDLE scm; 303 SC_HANDLE sv; 304 SERVICE_STATUS st; 305 if(out) fprintf(out, "stop unbound service\n"); 306 scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 307 if(!scm) fatal_win(out, "could not OpenSCManager"); 308 sv = OpenService(scm, SERVICE_NAME, SERVICE_STOP); 309 if(!sv) { 310 CloseServiceHandle(scm); 311 fatal_win(out, "could not OpenService"); 312 } 313 if(!ControlService(sv, SERVICE_CONTROL_STOP, &st)) { 314 CloseServiceHandle(sv); 315 CloseServiceHandle(scm); 316 fatal_win(out, "could not ControlService"); 317 } 318 CloseServiceHandle(sv); 319 CloseServiceHandle(scm); 320 if(out) fprintf(out, "unbound service stopped\n"); 321 } 322