common: Add new function gnupg_gmtime.
[gnupg.git] / common / w32-reg.c
1 /* w32-reg.c -  MS-Windows Registry access
2  * Copyright (C) 1999, 2002, 2007 Free Software Foundation, Inc.
3  *
4  * This file is part of JNLIB, which is a subsystem of GnuPG.
5  *
6  * JNLIB is free software; you can redistribute it and/or modify it
7  * under the terms of either
8  *
9  *   - the GNU Lesser General Public License as published by the Free
10  *     Software Foundation; either version 3 of the License, or (at
11  *     your option) any later version.
12  *
13  * or
14  *
15  *   - the GNU General Public License as published by the Free
16  *     Software Foundation; either version 2 of the License, or (at
17  *     your option) any later version.
18  *
19  * or both in parallel, as here.
20  *
21  * JNLIB is distributed in the hope that it will be useful, but
22  * WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24  * General Public License for more details.
25  *
26  * You should have received a copies of the GNU General Public License
27  * and the GNU Lesser General Public License along with this program;
28  * if not, see <http://www.gnu.org/licenses/>.
29  */
30
31 #include <config.h>
32 #ifdef HAVE_W32_SYSTEM
33  /* This module is only used in this environment */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdarg.h>
39 #ifdef HAVE_WINSOCK2_H
40 # include <winsock2.h>
41 #endif
42 #include <windows.h>
43
44 #include "libjnlib-config.h"
45 #include "utf8conv.h"
46 #include "w32help.h"
47
48
49 static HKEY
50 get_root_key(const char *root)
51 {
52   HKEY root_key;
53
54   if (!root)
55     root_key = HKEY_CURRENT_USER;
56   else if (!strcmp( root, "HKEY_CLASSES_ROOT" ) )
57     root_key = HKEY_CLASSES_ROOT;
58   else if (!strcmp( root, "HKEY_CURRENT_USER" ) )
59     root_key = HKEY_CURRENT_USER;
60   else if (!strcmp( root, "HKEY_LOCAL_MACHINE" ) )
61     root_key = HKEY_LOCAL_MACHINE;
62   else if (!strcmp( root, "HKEY_USERS" ) )
63     root_key = HKEY_USERS;
64   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
65     root_key = HKEY_PERFORMANCE_DATA;
66   else if (!strcmp( root, "HKEY_CURRENT_CONFIG" ) )
67     root_key = HKEY_CURRENT_CONFIG;
68   else
69     return NULL;
70
71   return root_key;
72 }
73
74
75 /* Return a string from the Win32 Registry or NULL in case of error.
76    Caller must release the return value.  A NULL for root is an alias
77    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  */
78 char *
79 read_w32_registry_string (const char *root, const char *dir, const char *name)
80 {
81 #ifdef HAVE_W32CE_SYSTEM
82   HKEY root_key, key_handle;
83   DWORD n1, nbytes, type;
84   char *result = NULL;
85   wchar_t *wdir, *wname;
86
87   if ( !(root_key = get_root_key(root) ) )
88     return NULL;
89
90   wdir = utf8_to_wchar (dir);
91   if (!wdir)
92     return NULL;
93
94   if (RegOpenKeyEx (root_key, wdir, 0, KEY_READ, &key_handle) )
95     {
96       if (root)
97         {
98           jnlib_free (wdir);
99           return NULL; /* No need for a RegClose, so return immediately. */
100         }
101       /* It seems to be common practise to fall back to HKLM. */
102       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, wdir, 0, KEY_READ, &key_handle) )
103         {
104           jnlib_free (wdir);
105           return NULL; /* Still no need for a RegClose. */
106         }
107     }
108   jnlib_free (wdir);
109
110   if (name)
111     {
112       wname = utf8_to_wchar (name);
113       if (!wname)
114         goto leave;
115     }
116   else
117     wname = NULL;
118
119   nbytes = 2;
120   if (RegQueryValueEx (key_handle, wname, 0, NULL, NULL, &nbytes))
121     goto leave;
122   result = jnlib_malloc ((n1=nbytes+2));
123   if (!result)
124     goto leave;
125   if (RegQueryValueEx (key_handle, wname, 0, &type, result, &n1))
126     {
127       jnlib_free (result);
128       result = NULL;
129       goto leave;
130     }
131   result[nbytes] = 0;   /* Make sure it is a string.  */
132   result[nbytes+1] = 0;
133   if (type == REG_SZ || type == REG_EXPAND_SZ)
134     {
135       wchar_t *tmp = (void*)result;
136       result = wchar_to_utf8 (tmp);
137       jnlib_free (tmp);
138     }
139
140  leave:
141   jnlib_free (wname);
142   RegCloseKey (key_handle);
143   return result;
144 #else /*!HAVE_W32CE_SYSTEM*/
145   HKEY root_key, key_handle;
146   DWORD n1, nbytes, type;
147   char *result = NULL;
148
149   if ( !(root_key = get_root_key(root) ) )
150     return NULL;
151
152   if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle) )
153     {
154       if (root)
155         return NULL; /* No need for a RegClose, so return immediately. */
156       /* It seems to be common practise to fall back to HKLM. */
157       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
158         return NULL; /* Still no need for a RegClose. */
159     }
160
161   nbytes = 1;
162   if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
163     goto leave;
164   result = jnlib_malloc ((n1=nbytes+1));
165   if (!result)
166     goto leave;
167   if (RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ))
168     {
169       jnlib_free (result);
170       result = NULL;
171       goto leave;
172     }
173   result[nbytes] = 0; /* Make sure it is a string.  */
174   if (type == REG_EXPAND_SZ && strchr (result, '%'))
175     {
176       char *tmp;
177
178       n1 += 1000;
179       tmp = jnlib_malloc (n1+1);
180       if (!tmp)
181         goto leave;
182       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
183       if (nbytes && nbytes > n1)
184         {
185           jnlib_free (tmp);
186           n1 = nbytes;
187           tmp = jnlib_malloc (n1 + 1);
188           if (!tmp)
189             goto leave;
190           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
191           if (nbytes && nbytes > n1)
192             {
193               /* Oops - truncated, better don't expand at all.  */
194               jnlib_free (tmp);
195               goto leave;
196             }
197           tmp[nbytes] = 0;
198           jnlib_free (result);
199           result = tmp;
200         }
201       else if (nbytes)
202         {
203           /* Okay, reduce the length.  */
204           tmp[nbytes] = 0;
205           jnlib_free (result);
206           result = jnlib_malloc (strlen (tmp)+1);
207           if (!result)
208             result = tmp;
209             else
210               {
211                 strcpy (result, tmp);
212                 jnlib_free (tmp);
213               }
214         }
215       else
216         {
217           /* Error - don't expand.  */
218           jnlib_free (tmp);
219         }
220     }
221
222  leave:
223   RegCloseKey (key_handle);
224   return result;
225 #endif /*!HAVE_W32CE_SYSTEM*/
226 }
227
228
229 #endif /*HAVE_W32_SYSTEM*/