Mercurial > trustbridge
comparison common/util.c @ 841:216a65d7fc4b
(issue66) Implement is_system_install and use it
This has completly different implementations for linux
and Windows. The commit also moves some code into util.c
for better reuse.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Tue, 29 Jul 2014 18:12:57 +0200 |
parents | 4ad764bfb39c |
children | f89b41fa7048 |
comparison
equal
deleted
inserted
replaced
840:c9a31544aaab | 841:216a65d7fc4b |
---|---|
17 #include <string.h> | 17 #include <string.h> |
18 #else | 18 #else |
19 #include <windows.h> | 19 #include <windows.h> |
20 #endif | 20 #endif |
21 | 21 |
22 #ifndef APPNAME | |
23 #define APPNAME "TrustBridge" | |
24 #endif | |
25 | |
22 #ifdef WIN32 | 26 #ifdef WIN32 |
23 char * get_install_dir() | 27 char* |
28 read_registry_string (const HKEY root, const wchar_t *key, | |
29 const wchar_t *name) | |
30 { | |
31 HKEY key_handle = NULL; | |
32 DWORD size = 0, | |
33 type = 0, | |
34 ex_size = 0, | |
35 dwRet = 0; | |
36 LONG ret = 0; | |
37 char *retval = NULL; | |
38 wchar_t *buf = NULL, | |
39 *ex_buf = NULL; | |
40 if (root == NULL || key == NULL || name == NULL) | |
41 { | |
42 ERRORPRINTF ("Invalid call to read_registry_string"); | |
43 return NULL; | |
44 } | |
45 | |
46 ret = RegOpenKeyExW (root, key, 0, KEY_READ, &key_handle); | |
47 if (ret != ERROR_SUCCESS) | |
48 { | |
49 ERRORPRINTF ("Failed to open key."); | |
50 return NULL; | |
51 } | |
52 | |
53 /* Get the size */ | |
54 ret = RegQueryValueExW (key_handle, name, 0, NULL, NULL, &size); | |
55 if (ret != ERROR_MORE_DATA && !(ret == ERROR_SUCCESS && size != 0)) | |
56 { | |
57 ERRORPRINTF ("Failed to get required registry size."); | |
58 return retval; | |
59 } | |
60 | |
61 /* Size is size in bytes not in characters */ | |
62 buf = xmalloc (size + sizeof(wchar_t)); | |
63 | |
64 /* If the stored value is not zero terminated the returned value also | |
65 is not zero terminated. That's why we reserve more and ensure it's | |
66 initialized. */ | |
67 memset (buf, 0, size + sizeof(wchar_t)); | |
68 | |
69 ret = RegQueryValueExW (key_handle, name, 0, &type, (LPBYTE) buf, &size); | |
70 if (ret != ERROR_SUCCESS) | |
71 { | |
72 ERRORPRINTF ("Failed get registry value."); | |
73 return retval; | |
74 } | |
75 | |
76 if (type == REG_SZ || (type == REG_EXPAND_SZ && wcschr (buf, '%') == NULL)) | |
77 { | |
78 /* Nothing to expand, we are done */ | |
79 retval = wchar_to_utf8 (buf, wcslen (buf)); | |
80 goto done; | |
81 } | |
82 | |
83 if (type != REG_EXPAND_SZ) | |
84 { | |
85 ERRORPRINTF ("Unhandled registry type %i", type); | |
86 goto done; | |
87 } | |
88 | |
89 /* Expand the registry string */ | |
90 ex_size = ExpandEnvironmentStringsW (buf, NULL, 0); | |
91 | |
92 if (ex_size == 0) | |
93 { | |
94 PRINTLASTERROR ("Failed to determine expanded environment size."); | |
95 goto done; | |
96 } | |
97 | |
98 ex_buf = xmalloc ((ex_size + 1) * sizeof(wchar_t)); | |
99 | |
100 dwRet = ExpandEnvironmentStringsW (buf, ex_buf, ex_size); | |
101 | |
102 ex_buf[ex_size] = '\0'; /* Make sure it's a string */ | |
103 | |
104 if (dwRet == 0 || dwRet != ex_size) | |
105 { | |
106 PRINTLASTERROR ("Failed to expand environment variables."); | |
107 goto done; | |
108 } | |
109 | |
110 retval = wchar_to_utf8 (ex_buf, ex_size); | |
111 | |
112 done: | |
113 xfree (ex_buf); | |
114 xfree (buf); | |
115 | |
116 RegCloseKey (key_handle); | |
117 return retval; | |
118 } | |
119 | |
120 | |
121 /** @brief Compare two paths for equality based on the filename. | |
122 * | |
123 * Expand the paths by using GetFullPathName and do a string | |
124 * comparison on the result to check for equality. | |
125 * | |
126 * To be sure if it is really the same file it would be better | |
127 * to open the files and compare the serial number but this | |
128 * suffices for checks that only impact on the options presented | |
129 * to the user (try a system wide installation or not) | |
130 * | |
131 * If one file does not exist the function returns false. If | |
132 * The path is longer then MAX_PATH this function also returns | |
133 * false. | |
134 * | |
135 * @param [in] path1 first path to compare | |
136 * @paran [in] path2 first path to compare | |
137 * @returns true if the paths are the same. | |
138 */ | |
139 bool | |
140 paths_equal (const char *path1, const char *path2) | |
141 { | |
142 bool ret = false; | |
143 wchar_t buf1[MAX_PATH], | |
144 buf2[MAX_PATH]; | |
145 wchar_t *wpath1 = NULL, | |
146 *wpath2 = NULL; | |
147 DWORD retval = 0; | |
148 | |
149 if (!path1 || !path2) | |
150 { | |
151 return false; | |
152 } | |
153 | |
154 wpath1 = utf8_to_wchar(path1, strnlen(path1, MAX_PATH)); | |
155 wpath2 = utf8_to_wchar(path2, strnlen(path2, MAX_PATH)); | |
156 | |
157 if (wpath1 == NULL || wpath2 == NULL) | |
158 { | |
159 ERRORPRINTF ("Failed to convert paths to wchar."); | |
160 goto done; | |
161 } | |
162 | |
163 retval = GetFullPathNameW (wpath1, MAX_PATH, buf1, NULL); | |
164 if (retval >= MAX_PATH || retval != wcsnlen (buf1, MAX_PATH)) | |
165 { | |
166 ERRORPRINTF ("Path1 too long."); | |
167 goto done; | |
168 } | |
169 if (retval == 0) | |
170 { | |
171 PRINTLASTERROR ("Failed to get Full Path name."); | |
172 goto done; | |
173 } | |
174 | |
175 retval = GetFullPathNameW (wpath2, MAX_PATH, buf2, NULL); | |
176 if (retval >= MAX_PATH || retval != wcsnlen (buf2, MAX_PATH)) | |
177 { | |
178 ERRORPRINTF ("Path2 too long."); | |
179 goto done; | |
180 } | |
181 if (retval == 0) | |
182 { | |
183 PRINTLASTERROR ("Failed to get Full Path name."); | |
184 goto done; | |
185 } | |
186 | |
187 ret = wcscmp (buf1, buf2) == 0; | |
188 done: | |
189 xfree (wpath1); | |
190 xfree (wpath2); | |
191 | |
192 return ret; | |
193 } | |
194 | |
195 char * | |
196 get_install_dir() | |
24 { | 197 { |
25 wchar_t wPath[MAX_PATH]; | 198 wchar_t wPath[MAX_PATH]; |
26 char *utf8path = NULL; | 199 char *utf8path = NULL; |
27 char *dirsep = NULL; | 200 char *dirsep = NULL; |
28 | 201 |
65 DWORD sidLength = GetLengthSid(from); | 238 DWORD sidLength = GetLengthSid(from); |
66 PSID to = (PSID) xmalloc(sidLength); | 239 PSID to = (PSID) xmalloc(sidLength); |
67 CopySid(sidLength, to, from); | 240 CopySid(sidLength, to, from); |
68 return to; | 241 return to; |
69 } | 242 } |
70 | |
71 | 243 |
72 PSID | 244 PSID |
73 get_process_owner(HANDLE hProcess) | 245 get_process_owner(HANDLE hProcess) |
74 { | 246 { |
75 HANDLE hToken = NULL; | 247 HANDLE hToken = NULL; |
99 xfree (userStruct); | 271 xfree (userStruct); |
100 return sid; | 272 return sid; |
101 } | 273 } |
102 } | 274 } |
103 return NULL; | 275 return NULL; |
276 } | |
277 | |
278 bool | |
279 is_system_install() | |
280 { | |
281 char *reg_inst_dir = NULL, | |
282 *real_prefix = NULL; | |
283 bool ret = false; | |
284 | |
285 reg_inst_dir = read_registry_string (HKEY_LOCAL_MACHINE, | |
286 L"Software\\"APPNAME, L""); | |
287 | |
288 if (reg_inst_dir == NULL) | |
289 { | |
290 return false; | |
291 } | |
292 DEBUGPRINTF ("Registered installation directory: %s\n", reg_inst_dir); | |
293 | |
294 real_prefix = get_install_dir(); | |
295 | |
296 if (!real_prefix) | |
297 { | |
298 DEBUGPRINTF ("Failed to obtain installation prefix."); | |
299 xfree (reg_inst_dir); | |
300 return false; | |
301 } | |
302 | |
303 ret = paths_equal (real_prefix, reg_inst_dir); | |
304 | |
305 xfree (real_prefix); | |
306 xfree (reg_inst_dir); | |
307 DEBUGPRINTF ("Is system install? %s\n", ret ? "true" : "false"); | |
308 return ret; | |
309 } | |
310 #else /* WIN32 */ | |
311 | |
312 char * | |
313 get_install_dir() | |
314 { | |
315 char *retval = NULL, | |
316 *p = NULL, | |
317 buf[MAX_PATH_LINUX]; | |
318 ssize_t ret; | |
319 size_t path_len = 0; | |
320 | |
321 ret = readlink ("/proc/self/exe", buf, MAX_PATH_LINUX); | |
322 if (ret <= 0) | |
323 { | |
324 ERRORPRINTF ("readlink failed\n"); | |
325 return NULL; | |
326 } | |
327 | |
328 buf[ret] = '\0'; | |
329 | |
330 /* cut off the filename */ | |
331 p = strrchr (buf, '/'); | |
332 if (p == NULL) | |
333 { | |
334 ERRORPRINTF ("No filename found.\n"); | |
335 return NULL; | |
336 } | |
337 *(p + 1) = '\0'; | |
338 | |
339 path_len = strlen (buf); | |
340 retval = xmalloc (path_len + 1); | |
341 strncpy (retval, buf, path_len); | |
342 retval[path_len] = '\0'; | |
343 | |
344 return retval; | |
345 } | |
346 | |
347 bool | |
348 is_system_install() | |
349 { | |
350 FILE *system_config; | |
351 int read_lines = 0; | |
352 char linebuf[MAX_PATH_LINUX + 7], | |
353 * inst_dir = NULL; | |
354 bool retval = false; | |
355 size_t inst_dir_len = 0; | |
356 | |
357 system_config = fopen ("/etc/"APPNAME"/"APPNAME"-inst.cfg", "r"); | |
358 if (system_config == NULL) | |
359 { | |
360 DEBUGPRINTF ("No system wide install configuration found.\n"); | |
361 return false; | |
362 } | |
363 inst_dir = get_install_dir (); | |
364 | |
365 if (inst_dir == NULL) | |
366 { | |
367 ERRORPRINTF ("Failed to find installation directory.\n"); | |
368 fclose(system_config); | |
369 return false; | |
370 } | |
371 | |
372 inst_dir_len = strnlen (inst_dir, MAX_PATH_LINUX); | |
373 | |
374 if (inst_dir_len == 0 || inst_dir_len >= MAX_PATH_LINUX) | |
375 { | |
376 ERRORPRINTF ("Installation directory invalid.\n"); | |
377 fclose(system_config); | |
378 return false; | |
379 } | |
380 | |
381 /* Read the first 10 lines and look for PREFIX. if it is not found | |
382 we return false. */ | |
383 while (read_lines < 10 && fgets (linebuf, MAX_PATH_LINUX + 7, | |
384 system_config) != NULL) | |
385 { | |
386 if (str_starts_with (linebuf, "PREFIX=")) | |
387 { | |
388 /* The last character is always a linebreak in a valid system_config | |
389 file so we can strip it. If this is not true the file is invalid. | |
390 linebuf is > 7 atm otherwise prefix= would not have been matched. */ | |
391 linebuf[strlen(linebuf) - 1] = '\0'; | |
392 retval = str_starts_with (inst_dir, linebuf + 7); | |
393 break; | |
394 } | |
395 read_lines++; | |
396 } | |
397 | |
398 fclose (system_config); | |
399 xfree (inst_dir); | |
400 DEBUGPRINTF ("Is system install? %s\n", retval ? "true" : "false"); | |
401 return retval; | |
104 } | 402 } |
105 #endif | 403 #endif |
106 | 404 |
107 bool | 405 bool |
108 is_elevated() | 406 is_elevated() |
126 CloseHandle (hToken); | 424 CloseHandle (hToken); |
127 #endif | 425 #endif |
128 return ret; | 426 return ret; |
129 } | 427 } |
130 | 428 |
131 bool is_admin() | 429 bool |
430 is_admin() | |
132 { | 431 { |
133 #ifndef _WIN32 | 432 #ifndef _WIN32 |
134 struct passwd *current_user = getpwuid (geteuid()); | 433 struct passwd *current_user = getpwuid (geteuid()); |
135 int ngroups = 0, | 434 int ngroups = 0, |
136 ret = 0, | 435 ret = 0, |