Exporting secret keys via gpg-agent is now basically supported.
[gnupg.git] / dirmngr / get-path.c
1 /* get-path.c - Utility functions for the W32 API
2    Copyright (C) 1999 Free Software Foundation, Inc
3    Copyright (C) 2001 Werner Koch (dd9jn)
4    Copyright (C) 2001, 2002, 2003, 2004, 2007 g10 Code GmbH
5
6    This file is part of DirMngr.
7   
8    DirMngr is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12   
13    DirMngr is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17   
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21    02111-1307, USA  */
22
23 #error Code has been replaced by common/homedir.c
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <errno.h>
33 #include <sys/time.h>
34 #include <sys/types.h>
35 #include <signal.h>
36 #include <fcntl.h>
37 #ifdef HAVE_W32_SYSTEM
38 #include <windows.h>
39 #include <shlobj.h>
40 #include <io.h>
41 #endif
42
43 #include "util.h"
44
45 #ifdef HAVE_W32_SYSTEM
46 #define GNUPG_DEFAULT_HOMEDIR "c:/gnupg"
47 #elif defined(__VMS)
48 #define GNUPG_DEFAULT_HOMEDIR "/SYS\$LOGIN/gnupg" 
49 #else
50 #define GNUPG_DEFAULT_HOMEDIR "~/.gnupg"
51 #endif 
52
53 #ifdef HAVE_DOSISH_SYSTEM
54 #define DIRSEP_C '\\'
55 #define DIRSEP_S "\\"
56 #else
57 #define DIRSEP_C '/'
58 #define DIRSEP_S "/"
59 #endif
60
61 \f
62 #ifdef HAVE_W32_SYSTEM
63 #define RTLD_LAZY 0
64
65 static __inline__ void *
66 dlopen (const char * name, int flag)
67 {
68   void * hd = LoadLibrary (name);
69   return hd;
70 }
71
72 static __inline__ void *
73 dlsym (void * hd, const char * sym)
74 {
75   if (hd && sym)
76     {
77       void * fnc = GetProcAddress (hd, sym);
78       if (!fnc)
79         return NULL;
80       return fnc;
81     }
82   return NULL;
83 }
84
85 static __inline__ int
86 dlclose (void * hd)
87 {
88   if (hd)
89     {
90       FreeLibrary (hd);
91       return 0;
92     }
93   return -1;
94 }  
95
96
97 /* Return a string from the W32 Registry or NULL in case of error.
98    Caller must release the return value.  A NULL for root is an alias
99    for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
100 static char *
101 read_w32_registry_string (const char *root, const char *dir, const char *name)
102 {
103   HKEY root_key, key_handle;
104   DWORD n1, nbytes, type;
105   char *result = NULL;
106         
107   if ( !root )
108     root_key = HKEY_CURRENT_USER;
109   else if ( !strcmp( root, "HKEY_CLASSES_ROOT" ) )
110     root_key = HKEY_CLASSES_ROOT;
111   else if ( !strcmp( root, "HKEY_CURRENT_USER" ) )
112     root_key = HKEY_CURRENT_USER;
113   else if ( !strcmp( root, "HKEY_LOCAL_MACHINE" ) )
114     root_key = HKEY_LOCAL_MACHINE;
115   else if ( !strcmp( root, "HKEY_USERS" ) )
116     root_key = HKEY_USERS;
117   else if ( !strcmp( root, "HKEY_PERFORMANCE_DATA" ) )
118     root_key = HKEY_PERFORMANCE_DATA;
119   else if ( !strcmp( root, "HKEY_CURRENT_CONFIG" ) )
120     root_key = HKEY_CURRENT_CONFIG;
121   else
122     return NULL;
123         
124   if ( RegOpenKeyEx ( root_key, dir, 0, KEY_READ, &key_handle ) )
125     {
126       if (root)
127         return NULL; /* no need for a RegClose, so return direct */
128       /* It seems to be common practise to fall back to HKLM. */
129       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
130         return NULL; /* still no need for a RegClose, so return direct */
131     }
132
133   nbytes = 1;
134   if ( RegQueryValueEx( key_handle, name, 0, NULL, NULL, &nbytes ) )
135     {
136       if (root)
137         goto leave;
138       /* Try to fallback to HKLM also vor a missing value.  */
139       RegCloseKey (key_handle);
140       if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle) )
141         return NULL; /* Nope.  */
142       if (RegQueryValueEx ( key_handle, name, 0, NULL, NULL, &nbytes))
143         goto leave;
144     }
145   result = malloc ( (n1=nbytes+1) );
146   if ( !result )
147     goto leave;
148   if ( RegQueryValueEx ( key_handle, name, 0, &type, result, &n1 ) )
149     {
150       free(result); result = NULL;
151       goto leave;
152     }
153   result[nbytes] = 0; /* Make sure it is really a string.  */
154   if (type == REG_EXPAND_SZ && strchr (result, '%')) 
155     {
156       char *tmp;
157         
158       n1 += 1000;
159       tmp = malloc (n1+1);
160       if (!tmp)
161         goto leave;
162       nbytes = ExpandEnvironmentStrings (result, tmp, n1);
163       if (nbytes && nbytes > n1)
164         {
165           free (tmp);
166           n1 = nbytes;
167           tmp = malloc (n1 + 1);
168           if (!tmp)
169             goto leave;
170           nbytes = ExpandEnvironmentStrings (result, tmp, n1);
171           if (nbytes && nbytes > n1) {
172             free (tmp); /* Oops - truncated, better don't expand at all. */
173             goto leave;
174           }
175           tmp[nbytes] = 0;
176           free (result);
177           result = tmp;
178         }
179       else if (nbytes)  /* Okay, reduce the length. */
180         {
181           tmp[nbytes] = 0;
182           free (result);
183           result = malloc (strlen (tmp)+1);
184           if (!result)
185             result = tmp;
186           else 
187             {
188               strcpy (result, tmp);
189               free (tmp);
190             }
191         }
192       else  /* Error - don't expand. */
193         {
194           free (tmp);
195         }
196     }
197
198  leave:
199   RegCloseKey( key_handle );
200   return result;
201 }
202
203
204 /* This is a helper function to load and run a Windows function from
205    either of one DLLs. */
206 static HRESULT
207 w32_shgetfolderpath (HWND a, int b, HANDLE c, DWORD d, LPSTR e)
208 {
209   static int initialized;
210   static HRESULT (WINAPI * func)(HWND,int,HANDLE,DWORD,LPSTR);
211
212   if (!initialized)
213     {
214       static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
215       void *handle;
216       int i;
217
218       initialized = 1;
219
220       for (i=0, handle = NULL; !handle && dllnames[i]; i++)
221         {
222           handle = dlopen (dllnames[i], RTLD_LAZY);
223           if (handle)
224             {
225               func = dlsym (handle, "SHGetFolderPathA");
226               if (!func)
227                 {
228                   dlclose (handle);
229                   handle = NULL;
230                 }
231             }
232         }
233     }
234
235   if (func)
236     return func (a,b,c,d,e);
237   else
238     return -1;
239 }
240
241
242 #if 0
243 static char *
244 find_program_in_inst_dir (const char *name)
245 {
246   char *result = NULL;
247   char *tmp;
248
249   tmp = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
250                                   "Software\\GNU\\GnuPG",
251                                   "Install Directory");
252   if (!tmp)
253     return NULL;
254
255   result = malloc (strlen (tmp) + 1 + strlen (name) + 1);
256   if (!result)
257     {
258       free (tmp);
259       return NULL;
260     }
261
262   strcpy (stpcpy (stpcpy (result, tmp), "\\"), name);
263   free (tmp);
264   if (access (result, F_OK))
265     {
266       free (result);
267       return NULL;
268     }
269
270   return result;
271 }
272
273
274 static char *
275 find_program_at_standard_place (const char *name)
276 {
277   char path[MAX_PATH];
278   char *result = NULL;
279       
280   if (w32_shgetfolderpath (NULL, CSIDL_PROGRAM_FILES, NULL, 0, path) >= 0) 
281     {
282       result = malloc (strlen (path) + 1 + strlen (name) + 1);
283       if (result)
284         {
285           strcpy (stpcpy (stpcpy (result, path), "\\"), name);
286           if (access (result, F_OK))
287             {
288               free (result);
289               result = NULL;
290             }
291         }
292     }
293   return result;
294 }
295 #endif
296 #endif
297
298
299 const char *
300 get_dirmngr_ldap_path (void)
301 {
302   static char *pgmname;
303
304 #ifdef HAVE_W32_SYSTEM
305   if (! pgmname)
306     {
307       const char *dir = dirmngr_libexecdir ();
308       const char *exe = "\\dirmngr_ldap.exe";
309       pgmname = malloc (strlen (dir) + strlen (exe) + 1);
310       if (pgmname)
311         strcpy (stpcpy (pgmname, dir), exe);
312     }
313 #endif
314   if (!pgmname)
315     pgmname = DIRMNGR_LIBEXECDIR "/dirmngr_ldap";
316   return pgmname;
317 }
318
319
320 \f
321 /* Home directory.  */
322
323 #ifdef HAVE_W32_SYSTEM
324 #ifndef CSIDL_APPDATA
325 #define CSIDL_APPDATA 0x001a
326 #endif
327 #ifndef CSIDL_LOCAL_APPDATA
328 #define CSIDL_LOCAL_APPDATA 0x001c
329 #endif
330 #ifndef CSIDL_COMMON_APPDATA
331 #define CSIDL_COMMON_APPDATA 0x0023
332 #endif
333 #ifndef CSIDL_FLAG_CREATE
334 #define CSIDL_FLAG_CREATE 0x8000
335 #endif
336 #endif /*HAVE_W32_SYSTEM*/
337
338 /* Get the standard home directory.  In general this function should
339    not be used as it does not consider a registry value (under W32) or
340    the GNUPGHOME environment variable.  It is better to use
341    default_homedir(). */
342 const char *
343 standard_homedir (void)
344 {
345 #ifdef HAVE_W32_SYSTEM
346   static const char *dir;
347
348   if (!dir)
349     {
350       char path[MAX_PATH];
351       
352       /* It might be better to use LOCAL_APPDATA because this is
353          defined as "non roaming" and thus more likely to be kept
354          locally.  For private keys this is desired.  However, given
355          that many users copy private keys anyway forth and back,
356          using a system roaming services might be better than to let
357          them do it manually.  A security conscious user will anyway
358          use the registry entry to have better control.  */
359       if (w32_shgetfolderpath (NULL, CSIDL_APPDATA|CSIDL_FLAG_CREATE, 
360                                NULL, 0, path) >= 0) 
361         {
362           char *tmp = xmalloc (strlen (path) + 6 +1);
363           strcpy (stpcpy (tmp, path), "\\gnupg");
364           dir = tmp;
365           
366           /* Try to create the directory if it does not yet exists.  */
367           if (access (dir, F_OK))
368             CreateDirectory (dir, NULL);
369         }
370       else
371         dir = GNUPG_DEFAULT_HOMEDIR;
372     }
373   return dir;
374 #else/*!HAVE_W32_SYSTEM*/
375   return GNUPG_DEFAULT_HOMEDIR;
376 #endif /*!HAVE_W32_SYSTEM*/
377 }
378
379 /* Set up the default home directory.  The usual --homedir option
380    should be parsed later. */
381 const char *
382 default_homedir (void)
383 {
384   const char *dir;
385
386   dir = getenv ("GNUPGHOME");
387 #ifdef HAVE_W32_SYSTEM
388   if (!dir || !*dir)
389     {
390       static const char *saved_dir;
391       
392       if (!saved_dir)
393         {
394           if (!dir || !*dir)
395             {
396               char *tmp;
397
398               tmp = read_w32_registry_string (NULL, "Software\\GNU\\GnuPG",
399                                               "HomeDir");
400               if (tmp && *tmp)
401                 {
402                   xfree (tmp);
403                   tmp = NULL;
404                 }
405                if (tmp)
406                 saved_dir = tmp;
407             }
408           
409           if (!saved_dir)
410             saved_dir = standard_homedir ();
411         }
412       dir = saved_dir;
413     }
414 #endif /*HAVE_W32_SYSTEM*/
415   if (!dir || !*dir)
416     dir = GNUPG_DEFAULT_HOMEDIR;
417
418   return dir;
419 }
420
421
422 #ifdef HAVE_W32_SYSTEM
423 static const char *
424 w32_rootdir (void)
425 {
426   static int got_dir;
427   static char dir[MAX_PATH+5];
428
429   if (!got_dir)
430     {
431       char *p;
432
433       if ( !GetModuleFileName ( NULL, dir, MAX_PATH) )
434         {
435           log_debug ("GetModuleFileName failed: %s\n", w32_strerror (0));
436           *dir = 0;
437         }
438       got_dir = 1;
439       p = strrchr (dir, DIRSEP_C);
440       if (p)
441         *p = 0;
442       else
443         {
444           log_debug ("bad filename `%s' returned for this process\n", dir);
445           *dir = 0; 
446         }
447     }
448
449   if (*dir)
450     return dir;
451   /* Fallback to the hardwired value. */
452   return DIRMNGR_LIBEXECDIR;
453 }
454
455 static const char *
456 w32_commondir (void)
457 {
458   static char *dir;
459
460   if (!dir)
461     {
462       char path[MAX_PATH];
463
464       if (w32_shgetfolderpath (NULL, CSIDL_COMMON_APPDATA, 
465                                NULL, 0, path) >= 0) 
466         {
467           char *tmp = xmalloc (strlen (path) + 4 +1);
468           strcpy (stpcpy (tmp, path), "\\GNU");
469           dir = tmp;
470           /* No auto create of the directory.  Either the installer or
471              the admin has to create these directories.  */
472         }
473       else
474         {
475           /* Ooops: Not defined - probably an old Windows version.
476              Use the installation directory instead.  */
477           dir = xstrdup (w32_rootdir ());
478         }
479     }
480   
481   return dir;
482 }
483 #endif /*HAVE_W32_SYSTEM*/
484
485
486
487
488 /* Return the name of the sysconfdir.  This is a static string.  This
489    function is required because under Windows we can't simply compile
490    it in.  */
491 const char *
492 dirmngr_sysconfdir (void)
493 {
494 #ifdef HAVE_W32_SYSTEM
495   static char *name;
496
497   if (!name)
498     {
499       const char *s1, *s2;
500       s1 = w32_commondir ();
501       s2 = DIRSEP_S "etc" DIRSEP_S "dirmngr";
502       name = xmalloc (strlen (s1) + strlen (s2) + 1);
503       strcpy (stpcpy (name, s1), s2);
504     }
505   return name;
506 #else /*!HAVE_W32_SYSTEM*/
507   return DIRMNGR_SYSCONFDIR;
508 #endif /*!HAVE_W32_SYSTEM*/
509 }
510
511
512 /* Return the name of the libexec directory.  The name is allocated in
513    a static area on the first use.  This function won't fail. */
514 const char *
515 dirmngr_libexecdir (void)
516 {
517 #ifdef HAVE_W32_SYSTEM
518   return w32_rootdir ();
519 #else /*!HAVE_W32_SYSTEM*/
520   return DIRMNGR_LIBEXECDIR;
521 #endif /*!HAVE_W32_SYSTEM*/
522 }
523
524
525 const char *
526 dirmngr_datadir (void)
527 {
528 #ifdef HAVE_W32_SYSTEM
529   static char *name;
530
531   if (!name)
532     {
533       const char *s1, *s2;
534       s1 = w32_commondir ();
535       s2 = DIRSEP_S "lib" DIRSEP_S "dirmngr";
536       name = xmalloc (strlen (s1) + strlen (s2) + 1);
537       strcpy (stpcpy (name, s1), s2);
538     }
539   return name;
540 #else /*!HAVE_W32_SYSTEM*/
541   return DIRMNGR_DATADIR;
542 #endif /*!HAVE_W32_SYSTEM*/
543 }
544
545
546 const char *
547 dirmngr_cachedir (void)
548 {
549 #ifdef HAVE_W32_SYSTEM
550   static const char *dir;
551
552   if (!dir)
553     {
554       char path[MAX_PATH];
555       const char *s1[] = { "GNU", "cache", "dirmngr", NULL };
556       int s1_len;
557       const char **comp;
558
559       s1_len = 0;
560       for (comp = s1; *comp; comp++)
561         {
562           /* Take account for the separator.  */
563           s1_len += 1 + strlen (*comp);
564         }
565
566       if (w32_shgetfolderpath (NULL, CSIDL_LOCAL_APPDATA|CSIDL_FLAG_CREATE, 
567                                NULL, 0, path) >= 0) 
568         {
569           char *tmp = xmalloc (strlen (path) + s1_len + 1);
570           char *p;
571
572           p = stpcpy (tmp, path);
573           for (comp = s1; *comp; comp++)
574             {
575               p = stpcpy (p, "\\");
576               p = stpcpy (p, *comp);
577
578               if (access (tmp, F_OK))
579                 CreateDirectory (tmp, NULL);
580             }
581
582           dir = tmp;
583         }
584       else
585         dir = "c:\\temp\\cache\\dirmngr";
586     }
587   return dir;
588 #else /*!HAVE_W32_SYSTEM*/
589   return DIRMNGR_CACHEDIR;
590 #endif /*!HAVE_W32_SYSTEM*/
591 }
592
593
594 const char *
595 default_socket_name (void)
596 {
597 #ifdef HAVE_W32_SYSTEM
598   static char *name;
599
600   if (!name)
601     {
602       char s1[MAX_PATH];
603       const char *s2;
604
605       /* We need something akin CSIDL_COMMON_PROGRAMS, but local
606          (non-roaming).  This is becuase the file needs to be on the
607          local machine and makes only sense on that machine.
608          CSIDL_WINDOWS seems to be the only location which guarantees
609          that. */
610       if (w32_shgetfolderpath (NULL, CSIDL_WINDOWS, NULL, 0, s1) < 0)
611         strcpy (s1, "C:\\WINDOWS");
612       s2 = DIRSEP_S "S.dirmngr";
613       name = xmalloc (strlen (s1) + strlen (s2) + 1);
614       strcpy (stpcpy (name, s1), s2);
615     }
616   return name;
617 #else /*!HAVE_W32_SYSTEM*/
618   return DIRMNGR_SOCKETDIR "/socket";
619 #endif /*!HAVE_W32_SYSTEM*/
620 }