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,

http://wald.intevation.org/projects/trustbridge/