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)
get_from_registry_indirect(char * name_buf,int name_size)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
set_to_registry(HKEY hBaseKey,const char * name_buf)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
get_from_registry(HKEY hBaseKey,char * name_buf,int name_size)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
try_dir(char * dir,char * buffer,int buf_len)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
get_from_os_buffer(char * name_buf,unsigned int name_size)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
get_from_os(krb5_context context)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
get_from_os(krb5_context context)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
set_for_os(const char * name)238 set_for_os(const char *name)
239 {
240 set_to_registry(HKEY_CURRENT_USER, name);
241 }
242 #else
243 static void
set_for_os(const char * name)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
krb5int_cc_user_set_default_name(krb5_context context,const char * name)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
krb5_cc_set_default_name(krb5_context context,const char * name)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
krb5_cc_default_name(krb5_context context)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