diff --git a/common/t-w32-reg.c b/common/t-w32-reg.c index 01816db54..9665003ea 100644 --- a/common/t-w32-reg.c +++ b/common/t-w32-reg.c @@ -1,80 +1,87 @@ /* t-w32-reg.c - Regression tests for W32 registry functions * Copyright (C) 2010 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute and/or modify this * part of GnuPG under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * GnuPG is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #include #include #include #include #include #include #include "mischelp.h" #include "t-support.h" #include "w32help.h" static void test_read_registry (void) { - char *string; + char *string1, *string2; -#ifdef HAVE_W32CE_SYSTEM - string = read_w32_registry_string ("HKEY_CLASSES_ROOT", - "BOOTSTRAP\\CLSID", NULL); - if (!string) - fail (0); - fprintf (stderr, "Bootstrap clsid: %s\n", string); - xfree (string); -#endif - - string = read_w32_registry_string + string1 = read_w32_registry_string ("HKEY_CURRENT_USER", "Software\\Microsoft\\Windows\\CurrentVersion\\Internet Settings", "User Agent"); - if (!string) + if (!string1) fail (0); - fprintf (stderr, "User agent: %s\n", string); - xfree (string); + fprintf (stderr, "User agent: %s\n", string1); + + string2 = read_w32_reg_string + ("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion" + "\\Internet Settings:User Agent"); + if (!string2) + fail (1); + fprintf (stderr, "User agent: %s\n", string2); + if (strcmp (string1, string2)) + fail (2); + + + xfree (string1); + xfree (string2); } int main (int argc, char **argv) { - (void)argc; - (void)argv; - - test_read_registry (); + if (argc > 1) + { + char *string = read_w32_reg_string (argv[1]); + printf ("%s -> %s\n", argv[1], string? string : "(null)"); + xfree (string); + } + else + test_read_registry (); return 0; } diff --git a/common/w32-reg.c b/common/w32-reg.c index d8d94b90e..f36c66453 100644 --- a/common/w32-reg.c +++ b/common/w32-reg.c @@ -1,230 +1,278 @@ /* w32-reg.c - MS-Windows Registry access * Copyright (C) 1999, 2002, 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute and/or modify this * part of GnuPG under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * GnuPG is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #include #ifdef HAVE_W32_SYSTEM /* This module is only used in this environment */ #include #include #include #include #ifdef HAVE_WINSOCK2_H # include #endif #include #include "util.h" #include "common-defs.h" #include "utf8conv.h" #include "w32help.h" static HKEY get_root_key(const char *root) { HKEY root_key; if (!root) root_key = HKEY_CURRENT_USER; else if (!strcmp( root, "HKEY_CLASSES_ROOT" ) ) root_key = HKEY_CLASSES_ROOT; else if (!strcmp( root, "HKEY_CURRENT_USER" ) ) root_key = HKEY_CURRENT_USER; else if (!strcmp( root, "HKEY_LOCAL_MACHINE" ) ) root_key = HKEY_LOCAL_MACHINE; else if (!strcmp( root, "HKEY_USERS" ) ) root_key = HKEY_USERS; else if (!strcmp( root, "HKEY_PERFORMANCE_DATA" ) ) root_key = HKEY_PERFORMANCE_DATA; else if (!strcmp( root, "HKEY_CURRENT_CONFIG" ) ) root_key = HKEY_CURRENT_CONFIG; else return NULL; return root_key; } /* Return a string from the Win32 Registry or NULL in case of error. Caller must release the return value. A NULL for root is an alias for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */ char * read_w32_registry_string (const char *root, const char *dir, const char *name) { #ifdef HAVE_W32CE_SYSTEM HKEY root_key, key_handle; DWORD n1, nbytes, type; char *result = NULL; wchar_t *wdir, *wname; if ( !(root_key = get_root_key(root) ) ) return NULL; wdir = utf8_to_wchar (dir); if (!wdir) return NULL; if (RegOpenKeyEx (root_key, wdir, 0, KEY_READ, &key_handle) ) { if (root) { xfree (wdir); return NULL; /* No need for a RegClose, so return immediately. */ } /* It seems to be common practise to fall back to HKLM. */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, wdir, 0, KEY_READ, &key_handle) ) { xfree (wdir); return NULL; /* Still no need for a RegClose. */ } } xfree (wdir); if (name) { wname = utf8_to_wchar (name); if (!wname) goto leave; } else wname = NULL; nbytes = 2; if (RegQueryValueEx (key_handle, wname, 0, NULL, NULL, &nbytes)) goto leave; result = xtrymalloc ((n1=nbytes+2)); if (!result) goto leave; if (RegQueryValueEx (key_handle, wname, 0, &type, result, &n1)) { xfree (result); result = NULL; goto leave; } result[nbytes] = 0; /* Make sure it is a string. */ result[nbytes+1] = 0; if (type == REG_SZ || type == REG_EXPAND_SZ) { wchar_t *tmp = (void*)result; result = wchar_to_utf8 (tmp); xfree (tmp); } leave: xfree (wname); RegCloseKey (key_handle); return result; #else /*!HAVE_W32CE_SYSTEM*/ HKEY root_key, key_handle; DWORD n1, nbytes, type; char *result = NULL; if ( !(root_key = get_root_key(root) ) ) return NULL; if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle) ) { if (root) return NULL; /* No need for a RegClose, so return immediately. */ /* It seems to be common practise to fall back to HKLM. */ if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) ) return NULL; /* Still no need for a RegClose. */ } nbytes = 1; if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) ) goto leave; result = xtrymalloc ((n1=nbytes+1)); if (!result) goto leave; if (RegQueryValueEx( key_handle, name, 0, &type, result, &n1 )) { xfree (result); result = NULL; goto leave; } result[nbytes] = 0; /* Make sure it is a string. */ if (type == REG_EXPAND_SZ && strchr (result, '%')) { char *tmp; n1 += 1000; tmp = xtrymalloc (n1+1); if (!tmp) goto leave; nbytes = ExpandEnvironmentStrings (result, tmp, n1); if (nbytes && nbytes > n1) { xfree (tmp); n1 = nbytes; tmp = xtrymalloc (n1 + 1); if (!tmp) goto leave; nbytes = ExpandEnvironmentStrings (result, tmp, n1); if (nbytes && nbytes > n1) { /* Oops - truncated, better don't expand at all. */ xfree (tmp); goto leave; } tmp[nbytes] = 0; xfree (result); result = tmp; } else if (nbytes) { /* Okay, reduce the length. */ tmp[nbytes] = 0; xfree (result); result = xtrymalloc (strlen (tmp)+1); if (!result) result = tmp; else { strcpy (result, tmp); xfree (tmp); } } else { /* Error - don't expand. */ xfree (tmp); } } leave: RegCloseKey (key_handle); return result; #endif /*!HAVE_W32CE_SYSTEM*/ } +/* Compact version of read_w32_registry_string. This version expects + * a single string as key described here using an example: + * + * HKCU\Software\GNU\GnuPG:HomeDir + * + * HKCU := the class, other supported classes are HKLM, HKCR, HKU, and + * HKCC. If no class is given and the string thus starts with + * a backslash HKCU with a fallback to HKLM is used. + * Software\GNU\GnuPG := The actual key. + * HomeDir := the name of the item. The name is optional to use the default + * value. + * + * Note that the first backslash and the first colon act as delimiters. + * + * Returns a malloced string or NULL if not found. + */ +char * +read_w32_reg_string (const char *key_arg) +{ + char *key; + char *p1, *p2; + char *result; + + if (!key_arg) + return NULL; + key = xtrystrdup (key_arg); + if (!key) + { + log_info ("warning: malloc failed while reading registry key\n"); + return NULL; + } + + p1 = strchr (key, '\\'); + if (!p1) + { + xfree (key); + return NULL; + } + *p1++ = 0; + p2 = strchr (p1, ':'); + if (p2) + *p2++ = 0; + + result = read_w32_registry_string (*key? key : NULL, p1, p2); + xfree (key); + return result; +} + #endif /*HAVE_W32_SYSTEM*/ diff --git a/common/w32help.h b/common/w32help.h index edb51b8b7..a79081f8e 100644 --- a/common/w32help.h +++ b/common/w32help.h @@ -1,65 +1,66 @@ /* w32help.h - W32 speicif functions * Copyright (C) 2007 Free Software Foundation, Inc. * * This file is part of GnuPG. * * GnuPG is free software; you can redistribute and/or modify this * part of GnuPG under the terms of either * * - the GNU Lesser General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at * your option) any later version. * * or * * - the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at * your option) any later version. * * or both in parallel, as here. * * GnuPG is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copies of the GNU General Public License * and the GNU Lesser General Public License along with this program; * if not, see . */ #ifndef GNUPG_COMMON_W32HELP_H #define GNUPG_COMMON_W32HELP_H /*-- w32-cmdline.c --*/ /* This module is also part of the Unix tests. */ char **w32_parse_commandline (char *cmdline, int globing, int *r_argv, int *r_itemsalloced); #ifdef HAVE_W32_SYSTEM /*-- w32-reg.c --*/ char *read_w32_registry_string (const char *root, const char *dir, const char *name ); +char *read_w32_reg_string (const char *key); /* Other stuff. */ #ifdef HAVE_W32CE_SYSTEM /* Setmode is missing in cegcc but available since CE 5.0. */ int _setmode (int handle, int mode); # define setmode(a,b) _setmode ((a),(b)) static inline int umask (int a) { (void)a; return 0; } #endif /*HAVE_W32CE_SYSTEM*/ #endif /*HAVE_W32_SYSTEM*/ #endif /*GNUPG_COMMON_MISCHELP_H*/