Merged Dirmngr with GnuPG.
[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.
5  *
6  * JNLIB is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 3 of
9  * the License, or (at your option) any later version.
10  *
11  * JNLIB is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #ifdef HAVE_W32_SYSTEM
22  /* This module is only used in this environment */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <stdarg.h>
28 #include <windows.h>
29
30 #include "libjnlib-config.h"
31 #include "utf8conv.h"
32 #include "w32help.h"
33
34
35 static HKEY
36 get_root_key(const char *root)
37 {
38   HKEY root_key;
39   
40   if (!root)
41     root_key = HKEY_CURRENT_USER;
42   else if (!strcmp( root, "HKEY_CLASSES_ROOT" ) )
43     root_key = HKEY_CLASSES_ROOT;
44   else if (!strcmp( root, "HKEY_CURRENT_USER" ) )
45     root_key = HKEY_CURRENT_USER;
46   else if (!strcmp( root, "HKEY_LOCAL_MACHINE" ) )
47     root_key = HKEY_LOCAL_MACHINE;
48   else if (!strcmp( root, "HKEY_USERS" ) )
49     root_key = HKEY_USERS;
50   else if (!strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
51     root_key = HKEY_PERFORMANCE_DATA;
52   else if (!strcmp( root, "HKEY_CURRENT_CONFIG" ) )
53     root_key = HKEY_CURRENT_CONFIG;
54   else
55     return NULL;
56   
57   return root_key;
58 }
59
60
61 /* Return a string from the Win32 Registry or NULL in case of error.
62    Caller must release the return value.  A NULL for root is an alias
63    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn.  */
64 char *
65 read_w32_registry_string (const char *root, const char *dir, const char *name)
66 {
67 #ifdef HAVE_W32CE_SYSTEM
68   HKEY root_key, key_handle;
69   DWORD n1, nbytes, type;
70   char *result = NULL;
71   wchar_t *wdir, *wname;
72   
73   if ( !(root_key = get_root_key(root) ) )
74     return NULL;
75   
76   wdir = utf8_to_wchar (dir);
77   if (!wdir)
78     return NULL;
79
80   if (RegOpenKeyEx (root_key, wdir, 0, KEY_READ, &key_handle) )
81     {
82       if (root)
83         {
84           jnlib_free (wdir);
85           return NULL; /* No need for a RegClose, so return immediately. */
86         }
87       /* It seems to be common practise to fall back to HKLM. */
88       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, wdir, 0, KEY_READ, &key_handle) )
89         {
90           jnlib_free (wdir);
91           return NULL; /* Still no need for a RegClose. */
92         }
93     }
94   jnlib_free (wdir);
95
96   if (name)
97     {
98       wname = utf8_to_wchar (name);
99       if (!wname)
100         goto leave;
101     }
102   else
103     wname = NULL;
104
105   nbytes = 2;
106   if (RegQueryValueEx (key_handle, wname, 0, NULL, NULL, &nbytes))
107     goto leave;
108   result = jnlib_malloc ((n1=nbytes+2));
109   if (!result)
110     goto leave;
111   if (RegQueryValueEx (key_handle, wname, 0, &type, result, &n1))
112     {
113       jnlib_free (result);
114       result = NULL;
115       goto leave;
116     }
117   result[nbytes] = 0;   /* Make sure it is a string.  */
118   result[nbytes+1] = 0; 
119   if (type == REG_SZ || type == REG_EXPAND_SZ)
120     {
121       wchar_t *tmp = (void*)result;
122       result = wchar_to_utf8 (tmp);
123       jnlib_free (tmp);
124     }
125
126  leave:
127   jnlib_free (wname);
128   RegCloseKey (key_handle);
129   return result;
130 #else /*!HAVE_W32CE_SYSTEM*/
131   HKEY root_key, key_handle;
132   DWORD n1, nbytes, type;
133   char *result = NULL;
134   
135   if ( !(root_key = get_root_key(root) ) )
136     return NULL;
137   
138   if (RegOpenKeyEx (root_key, dir, 0, KEY_READ, &key_handle) )
139     {
140       if (root)
141         return NULL; /* No need for a RegClose, so return immediately. */
142       /* It seems to be common practise to fall back to HKLM. */
143       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
144         return NULL; /* Still no need for a RegClose. */
145     }
146
147   nbytes = 1;
148   if (RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
149     goto leave;
150   result = jnlib_malloc ((n1=nbytes+1));
151   if (!result)
152     goto leave;
153   if (RegQueryValueEx( key_handle, name, 0, &type, result, &n1 ))
154     {
155       jnlib_free (result);
156       result = NULL;
157       goto leave;
158     }
159   result[nbytes] = 0; /* Make sure it is a string.  */
160   if (type == REG_EXPAND_SZ && strchr (result, '%'))
161     {
162       char *tmp;
163       
164       n1 += 1000;
165       tmp = jnlib_malloc (n1+1);
166       if (!tmp)
167         goto leave;
168       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
169       if (nbytes && nbytes > n1)
170         {
171           jnlib_free (tmp);
172           n1 = nbytes;
173           tmp = jnlib_malloc (n1 + 1);
174           if (!tmp)
175             goto leave;
176           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
177           if (nbytes && nbytes > n1)
178             {
179               /* Oops - truncated, better don't expand at all.  */
180               jnlib_free (tmp); 
181               goto leave;
182             }
183           tmp[nbytes] = 0;
184           jnlib_free (result);
185           result = tmp;
186         }
187       else if (nbytes)
188         {
189           /* Okay, reduce the length.  */
190           tmp[nbytes] = 0;
191           jnlib_free (result);
192           result = jnlib_malloc (strlen (tmp)+1);
193           if (!result)
194             result = tmp;
195             else 
196               {
197                 strcpy (result, tmp);
198                 jnlib_free (tmp);
199               }
200         }
201       else 
202         {  
203           /* Error - don't expand.  */
204           jnlib_free (tmp);
205         }
206     }
207
208  leave:
209   RegCloseKey (key_handle);
210   return result;
211 #endif /*!HAVE_W32CE_SYSTEM*/
212 }
213
214
215 /* Note: This code is not well tested.  However, it is not used in
216    GnuPG.  */
217 int
218 write_w32_registry_string (const char *root, const char *dir, 
219                            const char *name, const char *value)
220 {
221   HKEY root_key, reg_key;
222 #ifdef HAVE_W32CE_SYSTEM
223   wchar_t *wdir, *wname, *wvalue;
224   DWORD disp;
225
226   if ( !(root_key = get_root_key(root) ) )
227     return -1;
228
229   wdir = utf8_to_wchar (dir);
230   if (!wdir)
231     return -1;
232
233   if (RegOpenKeyEx (root_key, wdir, 0, 0, &reg_key))
234     {
235       jnlib_free (wdir);
236       return -1;
237     }
238   jnlib_free (wdir);
239   
240   if (name)
241     {
242       wname = utf8_to_wchar (name);
243       if (!wname)
244         return -1;
245     }
246   else
247     wname = NULL;
248
249   wvalue = utf8_to_wchar (value);
250   if (wvalue)
251     {
252       jnlib_free (wname);
253       return -1;
254     }
255
256   if (RegSetValueEx (reg_key, wname, 0, REG_SZ, 
257                      (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS )
258     {
259
260       if (RegCreateKeyEx (root_key, wname, 0, NULL, 0, 0, NULL,
261                           &reg_key, &disp) != ERROR_SUCCESS) 
262         {
263           RegCloseKey(reg_key);
264           jnlib_free (wname);
265           jnlib_free (wvalue);
266           return -1;
267         }
268       if (RegSetValueEx (reg_key, wname, 0, REG_SZ,
269                          (BYTE *)wvalue, wcslen (wvalue)) != ERROR_SUCCESS )
270         {
271           RegCloseKey(reg_key);
272           jnlib_free (wname);
273           jnlib_free (wvalue);
274           return -1;
275         }
276     }
277   
278   jnlib_free (wname);
279   jnlib_free (wvalue);
280   RegCloseKey (reg_key);
281   return 0;
282 #else /*!HAVE_W32CE_SYSTEM*/
283
284   if ( !(root_key = get_root_key(root) ) )
285     return -1;
286   
287   if ( RegOpenKeyEx( root_key, dir, 0, KEY_WRITE, &reg_key ) 
288        != ERROR_SUCCESS )
289     return -1;
290   
291   if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value, 
292                       strlen( value ) ) != ERROR_SUCCESS )
293     {
294       if ( RegCreateKey( root_key, name, &reg_key ) != ERROR_SUCCESS ) 
295         {
296           RegCloseKey(reg_key);
297           return -1;
298         }
299       if ( RegSetValueEx (reg_key, name, 0, REG_SZ, (BYTE *)value,
300                           strlen( value ) ) != ERROR_SUCCESS )
301         {
302           RegCloseKey(reg_key);
303           return -1;
304         }
305     }
306   
307   RegCloseKey (reg_key);
308   return 0;
309 #endif /*!HAVE_W32CE_SYSTEM*/
310 }
311
312 #endif /*HAVE_W32_SYSTEM*/