xref: /freebsd/crypto/krb5/src/lib/krb5/os/ccdefname.c (revision b670c9bafc0e31c7609969bf374b2e80bdc00211)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/os/ccdefname.c - Return default credential cache name */
3 /*
4  * Copyright 1990, 2007 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 
27 #define NEED_WINDOWS
28 #include "k5-int.h"
29 #include "../ccache/cc-int.h"
30 #include "os-proto.h"
31 #include <stdio.h>
32 
33 #if defined(_WIN32)
34 static int get_from_registry_indirect(char *name_buf, int name_size)
35 {
36     /* If the RegKRB5CCNAME variable is set, it will point to
37      * the registry key that has the name of the cache to use.
38      * The Gradient PC-DCE sets the registry key
39      * [HKEY_CURRENT_USER\Software\Gradient\DCE\Default\KRB5CCNAME]
40      * to point at the cache file name (including the FILE: prefix).
41      * By indirecting with the RegKRB5CCNAME entry in kerberos.ini,
42      * we can accommodate other versions that might set a registry
43      * variable.
44      */
45     char newkey[256];
46 
47     LONG name_buf_size;
48     HKEY hkey;
49     int found = 0;
50     char *cp;
51 
52     newkey[0] = 0;
53     GetPrivateProfileString(INI_FILES, "RegKRB5CCNAME", "",
54                             newkey, sizeof(newkey), KERBEROS_INI);
55     if (!newkey[0])
56         return 0;
57 
58     newkey[sizeof(newkey)-1] = 0;
59     cp = strrchr(newkey,'\\');
60     if (cp) {
61         *cp = '\0'; /* split the string */
62         cp++;
63     } else
64         cp = "";
65 
66     if (RegOpenKeyEx(HKEY_CURRENT_USER, newkey, 0,
67                      KEY_QUERY_VALUE, &hkey) != ERROR_SUCCESS)
68         return 0;
69 
70     name_buf_size = name_size;
71     if (RegQueryValueEx(hkey, cp, 0, 0,
72                         name_buf, &name_buf_size) != ERROR_SUCCESS)
73     {
74         RegCloseKey(hkey);
75         return 0;
76     }
77 
78     RegCloseKey(hkey);
79     return 1;
80 }
81 
82 static const char *key_path = "Software\\MIT\\Kerberos5";
83 static const char *value_name = "ccname";
84 static int
85 set_to_registry(
86     HKEY hBaseKey,
87     const char *name_buf
88 )
89 {
90     HRESULT result;
91     HKEY hKey;
92 
93     if ((result = RegCreateKeyEx(hBaseKey, key_path, 0, NULL,
94                                  REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL,
95                                  &hKey, NULL)) != ERROR_SUCCESS) {
96         return 0;
97     }
98     if (RegSetValueEx(hKey, value_name, 0, REG_SZ, name_buf,
99                       strlen(name_buf)+1) != ERROR_SUCCESS) {
100         RegCloseKey(hKey);
101         return 0;
102     }
103     RegCloseKey(hKey);
104     return 1;
105 }
106 
107 
108 /*
109  * get_from_registry
110  *
111  * This will find the ccname in the registry.  Returns 0 on error, non-zero
112  * on success.
113  */
114 
115 static int
116 get_from_registry(
117     HKEY hBaseKey,
118     char *name_buf,
119     int name_size
120 )
121 {
122     HKEY hKey;
123     DWORD name_buf_size = (DWORD)name_size;
124 
125     if (RegOpenKeyEx(hBaseKey, key_path, 0, KEY_QUERY_VALUE,
126                      &hKey) != ERROR_SUCCESS)
127         return 0;
128     if (RegQueryValueEx(hKey, value_name, 0, 0,
129                         name_buf, &name_buf_size) != ERROR_SUCCESS)
130     {
131         RegCloseKey(hKey);
132         return 0;
133     }
134     RegCloseKey(hKey);
135     return 1;
136 }
137 
138 #define APPEND_KRB5CC "\\krb5cc"
139 
140 static int
141 try_dir(
142     char* dir,
143     char* buffer,
144     int buf_len
145 )
146 {
147     struct _stat s;
148     if (!dir)
149         return 0;
150     if (_stat(dir, &s))
151         return 0;
152     if (!(s.st_mode & _S_IFDIR))
153         return 0;
154     if (buffer != dir) {
155         strncpy(buffer, dir, buf_len);
156         buffer[buf_len-1]='\0';
157     }
158     strncat(buffer, APPEND_KRB5CC, buf_len-strlen(buffer));
159     buffer[buf_len-1] = '\0';
160     return 1;
161 }
162 
163 static krb5_error_code
164 get_from_os_buffer(char *name_buf, unsigned int name_size)
165 {
166     char *prefix = krb5_cc_dfl_ops->prefix;
167     unsigned int size;
168     char *p;
169     DWORD gle;
170 
171     SetLastError(0);
172     GetEnvironmentVariable(KRB5_ENV_CCNAME, name_buf, name_size);
173     gle = GetLastError();
174     if (gle == 0)
175         return 0;
176     else if (gle != ERROR_ENVVAR_NOT_FOUND)
177         return ENOMEM;
178 
179     if (get_from_registry(HKEY_CURRENT_USER,
180                           name_buf, name_size) != 0)
181         return 0;
182 
183     if (get_from_registry(HKEY_LOCAL_MACHINE,
184                           name_buf, name_size) != 0)
185         return 0;
186 
187     if (get_from_registry_indirect(name_buf, name_size) != 0)
188         return 0;
189 
190     strncpy(name_buf, prefix, name_size - 1);
191     name_buf[name_size - 1] = 0;
192     size = name_size - strlen(prefix);
193     if (size > 0)
194         strcat(name_buf, ":");
195     size--;
196     p = name_buf + name_size - size;
197     if (!strcmp(prefix, "API")) {
198         strncpy(p, "krb5cc", size);
199     } else if (!strcmp(prefix, "FILE") || !strcmp(prefix, "STDIO")) {
200         if (!try_dir(getenv("TEMP"), p, size) &&
201             !try_dir(getenv("TMP"), p, size))
202         {
203             unsigned int len = GetWindowsDirectory(p, size);
204             name_buf[name_size - 1] = 0;
205             if (len < size - sizeof(APPEND_KRB5CC))
206                 strcat(p, APPEND_KRB5CC);
207         }
208     } else {
209         strncpy(p, "default_cache_name", size);
210     }
211     name_buf[name_size - 1] = 0;
212     return 0;
213 }
214 
215 static void
216 get_from_os(krb5_context context)
217 {
218     krb5_error_code err;
219     char buf[1024];
220 
221     if (get_from_os_buffer(buf, sizeof(buf)) == 0)
222         context->os_context.default_ccname = strdup(buf);
223 }
224 
225 #else /* not _WIN32 */
226 
227 static void
228 get_from_os(krb5_context context)
229 {
230     (void)k5_expand_path_tokens(context, DEFCCNAME,
231                                 &context->os_context.default_ccname);
232 }
233 
234 #endif /* not _WIN32 */
235 
236 #if defined(_WIN32)
237 static void
238 set_for_os(const char *name)
239 {
240     set_to_registry(HKEY_CURRENT_USER, name);
241 }
242 #else
243 static void
244 set_for_os(const char *name)
245 {
246     /* No implementation at present. */
247 }
248 #endif
249 
250 /*
251  * Set the default ccache name for all processes for the current user
252  * (and the current context)
253  */
254 krb5_error_code KRB5_CALLCONV
255 krb5int_cc_user_set_default_name(krb5_context context, const char *name)
256 {
257     krb5_error_code err;
258 
259     err = krb5_cc_set_default_name(context, name);
260     if (err)
261         return err;
262     set_for_os(name);
263     return 0;
264 }
265 
266 krb5_error_code KRB5_CALLCONV
267 krb5_cc_set_default_name(krb5_context context, const char *name)
268 {
269     krb5_os_context os_ctx;
270     char *new_ccname = NULL;
271 
272     if (!context || context->magic != KV5M_CONTEXT)
273         return KV5M_CONTEXT;
274 
275     if (name != NULL) {
276         new_ccname = strdup(name);
277         if (new_ccname == NULL)
278             return ENOMEM;
279     }
280 
281     /* Free the old ccname and store the new one. */
282     os_ctx = &context->os_context;
283     free(os_ctx->default_ccname);
284     os_ctx->default_ccname = new_ccname;
285     return 0;
286 }
287 
288 
289 const char * KRB5_CALLCONV
290 krb5_cc_default_name(krb5_context context)
291 {
292     krb5_os_context os_ctx;
293     char *profstr, *envstr;
294 
295     if (!context || context->magic != KV5M_CONTEXT)
296         return NULL;
297 
298     os_ctx = &context->os_context;
299     if (os_ctx->default_ccname != NULL)
300         return os_ctx->default_ccname;
301 
302     /* Try the environment variable first. */
303     envstr = secure_getenv(KRB5_ENV_CCNAME);
304     if (envstr != NULL) {
305         os_ctx->default_ccname = strdup(envstr);
306         return os_ctx->default_ccname;
307     }
308 
309     if (profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
310                            KRB5_CONF_DEFAULT_CCACHE_NAME, NULL, NULL,
311                            &profstr) == 0 && profstr != NULL) {
312         (void)k5_expand_path_tokens(context, profstr, &os_ctx->default_ccname);
313         profile_release_string(profstr);
314         return os_ctx->default_ccname;
315     }
316 
317     /* Fall back on the default ccache name for the OS. */
318     get_from_os(context);
319     return os_ctx->default_ccname;
320 }
321