LINUX: afs_create infinite fetchStatus loop
[pkg-k5-afs_openafs.git] / src / WINNT / netidmgr_plugin / krb5common.c
blobfc4218d01366a91eda596c335d4f020f69434be1
1 /*
2 * Copyright (c) 2005 Massachusetts Institute of Technology
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use, copy,
8 * modify, merge, publish, distribute, sublicense, and/or sell copies
9 * of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
25 /* $Id$ */
27 #include <afsconfig.h>
28 #include <afs/param.h>
29 #include <roken.h>
31 #include<ws2tcpip.h>
32 #include<windows.h>
33 #include<netidmgr.h>
34 #include<dynimport.h>
35 #include<krb5common.h>
36 #ifdef DEBUG
37 #include<assert.h>
38 #endif
39 #include<strsafe.h>
41 /**************************************/
42 /* khm_krb5_error(): */
43 /**************************************/
44 int
45 khm_krb5_error(krb5_error_code rc, LPCSTR FailedFunctionName,
46 int FreeContextFlag, krb5_context * ctx,
47 krb5_ccache * cache)
49 #ifdef NO_KRB5
50 return 0;
51 #else
53 #ifdef SHOW_MESSAGE_IN_AN_ANNOYING_WAY
54 char message[256];
55 const char *errText;
56 int krb5Error = ((int)(rc & 255));
58 if (*ctx && krb5_get_error_message)
59 errText = krb5_get_error_message(*ctx, rc);
60 else
61 errText = perror_message(rc);
62 _snprintf(message, sizeof(message),
63 "%s\n(Kerberos error %ld)\n\n%s failed",
64 errText,
65 krb5Error,
66 FailedFunctionName);
67 if (*ctx && krb5_free_error_message)
68 krb5_free_error_message(*ctx, errText);
70 MessageBoxA(NULL, message, "Kerberos Five", MB_OK | MB_ICONERROR |
71 MB_TASKMODAL |
72 MB_SETFOREGROUND);
73 #endif
75 if (FreeContextFlag == 1)
77 if (*ctx != NULL)
79 if (*cache != NULL) {
80 krb5_cc_close(*ctx, *cache);
81 *cache = NULL;
84 krb5_free_context(*ctx);
85 *ctx = NULL;
89 return rc;
91 #endif //!NO_KRB5
94 int
95 khm_krb5_initialize(khm_handle ident,
96 krb5_context *ctx,
97 krb5_ccache *cache)
99 #ifdef NO_KRB5
100 return(0);
101 #else
103 LPCSTR functionName;
104 int freeContextFlag;
105 krb5_error_code rc = 0;
106 krb5_flags flags = KRB5_TC_OPENCLOSE;
108 if (krb5_init_context == NULL)
109 return 1;
111 if (*ctx == 0 && (rc = krb5_init_context(ctx))) {
112 functionName = "krb5_init_context()";
113 freeContextFlag = 0;
114 goto on_error;
117 if (krb5_enctype_valid(*ctx, ETYPE_DES_CBC_CRC))
118 krb5_enctype_enable(*ctx, ETYPE_DES_CBC_CRC);
120 if(*cache == 0) {
121 wchar_t wccname[MAX_PATH];
122 khm_size cbwccname;
124 if(ident != NULL) {
125 cbwccname = sizeof(wccname);
126 do {
127 char ccname[256];
129 if(KHM_FAILED(kcdb_identity_get_attrib(ident, L"Krb5CCName",
130 NULL, wccname,
131 &cbwccname))) {
132 cbwccname = sizeof(wccname);
133 if (KHM_FAILED
134 (khm_krb5_find_ccache_for_identity(ident,
135 ctx,
136 wccname,
137 &cbwccname))) {
138 #ifdef DEBUG_LIKE_A_MADMAN
139 assert(FALSE);
140 #endif
141 break;
145 if(UnicodeStrToAnsi(ccname, sizeof(ccname), wccname) == 0)
146 break;
148 if((rc = krb5_cc_resolve(*ctx, ccname, cache)) != 0) {
149 functionName = "krb5_cc_resolve()";
150 freeContextFlag = 1;
151 goto on_error;
153 } while(FALSE);
156 #ifndef FAILOVER_TO_DEFAULT_CCACHE
157 rc = 1;
158 #endif
159 if (*cache == 0
160 #ifdef FAILOVER_TO_DEFAULT_CCACHE
161 && (rc = krb5_cc_default(*ctx, cache))
162 #endif
164 functionName = "krb5_cc_default()";
165 freeContextFlag = 1;
166 goto on_error;
170 #ifdef KRB5_TC_NOTICKET
171 flags = KRB5_TC_NOTICKET;
172 #endif
174 if ((rc = krb5_cc_set_flags(*ctx, *cache, flags)))
176 if (rc != KRB5_FCC_NOFILE && rc != KRB5_CC_NOTFOUND)
177 khm_krb5_error(rc, "krb5_cc_set_flags()", 0, ctx, cache);
178 else if ((rc == KRB5_FCC_NOFILE || rc == KRB5_CC_NOTFOUND) && *ctx != NULL) {
179 if (*cache != NULL)
180 krb5_cc_close(*ctx, *cache);
182 return rc;
184 return 0;
186 on_error:
187 return khm_krb5_error(rc, functionName, freeContextFlag, ctx, cache);
188 #endif //!NO_KRB5
191 #define TIMET_TOLERANCE (60*5)
193 khm_int32 KHMAPI
194 khm_get_identity_expiration_time(krb5_context ctx, krb5_ccache cc,
195 khm_handle ident,
196 krb5_timestamp * pexpiration)
198 krb5_principal principal = 0;
199 char * princ_name = NULL;
200 krb5_creds creds;
201 krb5_error_code code;
202 krb5_error_code cc_code;
203 krb5_cc_cursor cur;
204 krb5_timestamp now, expiration = 0;
206 wchar_t w_ident_name[KCDB_IDENT_MAXCCH_NAME];
207 char ident_name[KCDB_IDENT_MAXCCH_NAME];
208 khm_size cb;
210 khm_int32 rv = KHM_ERROR_NOT_FOUND;
212 if (!ctx || !cc || !ident || !pexpiration)
213 return KHM_ERROR_GENERAL;
215 code = krb5_cc_get_principal(ctx, cc, &principal);
217 if ( code )
218 return KHM_ERROR_INVALID_PARAM;
220 cb = sizeof(w_ident_name);
221 kcdb_identity_get_name(ident, w_ident_name, &cb);
222 UnicodeStrToAnsi(ident_name, sizeof(ident_name), w_ident_name);
224 code = krb5_unparse_name(ctx, principal, &princ_name);
226 /* compare principal to ident. */
228 if ( code || !princ_name ||
229 strcmp(princ_name, ident_name) ) {
230 if (princ_name)
231 krb5_free_unparsed_name(ctx, princ_name);
232 krb5_free_principal(ctx, principal);
233 return KHM_ERROR_UNKNOWN;
236 krb5_free_unparsed_name(ctx, princ_name);
237 krb5_free_principal(ctx, principal);
239 code = krb5_timeofday(ctx, &now);
241 if (code)
242 return KHM_ERROR_UNKNOWN;
244 cc_code = krb5_cc_start_seq_get(ctx, cc, &cur);
246 while (!(cc_code = krb5_cc_next_cred(ctx, cc, &cur, &creds))) {
247 const char * c0 = krb5_principal_get_comp_string(ctx, creds.server, 0);
248 const char * c1 = krb5_principal_get_comp_string(ctx, creds.server, 1);
249 const char * r = krb5_principal_get_realm(ctx, creds.server);
251 if ( c0 && c1 && r && !strcmp(c1, r) &&
252 !strcmp("krbtgt",c0) ) {
254 /* we have a TGT, check for the expiration time.
255 * if it is valid and renewable, use the renew time
258 if (!creds.flags.b.invalid &&
259 creds.times.starttime < (now + TIMET_TOLERANCE) &&
260 (creds.times.endtime + TIMET_TOLERANCE) > now) {
261 expiration = creds.times.endtime;
263 if (creds.flags.b.renewable &&
264 (creds.times.renew_till > creds.times.endtime)) {
265 expiration = creds.times.renew_till;
271 if (cc_code == KRB5_CC_END) {
272 cc_code = krb5_cc_end_seq_get(ctx, cc, &cur);
273 rv = KHM_ERROR_SUCCESS;
274 *pexpiration = expiration;
277 return rv;
280 khm_int32 KHMAPI
281 khm_krb5_find_ccache_for_identity(khm_handle ident, krb5_context *pctx,
282 void * buffer, khm_size * pcbbuf)
284 krb5_context context = 0;
285 krb5_ccache cache = 0;
286 krb5_error_code code;
287 khm_int32 t;
288 wchar_t * ms = NULL;
289 khm_size cb;
290 krb5_timestamp expiration = 0;
291 krb5_timestamp best_match_expiration = 0;
292 char best_match_ccname[256] = "";
293 khm_handle csp_params = NULL;
294 khm_handle csp_plugins = NULL;
296 if (!buffer || !pcbbuf)
297 return KHM_ERROR_GENERAL;
299 context = *pctx;
301 do {
302 krb5_cccol_cursor cciter = 0;
304 code = krb5_cccol_cursor_new(context, &cciter);
305 if (code)
306 break;
308 while (krb5_cccol_cursor_next(context, cciter, &cache) == 0) {
310 /* need a function to check the cache for the identity and
311 * determine if it has valid tickets. If it has the right
312 * identity and valid tickets, store the expiration time
313 * and the cache name. If it has the right identity but
314 * no valid tickets, store the ccache name and an
315 * expiration time of zero. if it does not have the right
316 * identity don't save the name.
318 * Keep searching to find the best cache available.
321 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(context, cache,
322 ident,
323 &expiration))) {
324 if ( expiration > best_match_expiration ) {
325 best_match_expiration = expiration;
326 StringCbPrintfA(best_match_ccname, sizeof(best_match_ccname),
327 "%s:%s",
328 krb5_cc_get_type(context, cache),
329 krb5_cc_get_name(context, cache));
330 expiration = 0;
334 krb5_cc_close(context, cache);
335 cache = 0;
338 krb5_cccol_cursor_free(context, &cciter);
339 } while (FALSE);
341 if (KHM_SUCCEEDED(kmm_get_plugins_config(0, &csp_plugins))) {
342 khc_open_space(csp_plugins, L"Krb5Cred\\Parameters", 0, &csp_params);
343 khc_close_space(csp_plugins);
344 csp_plugins = NULL;
347 #ifdef DEBUG
348 if (csp_params == NULL) {
349 assert(FALSE);
351 #endif
353 if (csp_params &&
354 KHM_SUCCEEDED(khc_read_int32(csp_params, L"MsLsaList", &t)) && t) {
355 code = krb5_cc_resolve(context, "MSLSA:", &cache);
356 if (code == 0 && cache) {
357 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(context, cache,
358 ident,
359 &expiration))) {
360 if ( expiration > best_match_expiration ) {
361 best_match_expiration = expiration;
362 StringCbCopyA(best_match_ccname, sizeof(best_match_ccname),
363 "MSLSA:");
364 expiration = 0;
369 if (context != NULL && cache != NULL)
370 krb5_cc_close(context, cache);
372 cache = 0;
375 if (csp_params &&
376 khc_read_multi_string(csp_params, L"FileCCList", NULL, &cb)
377 == KHM_ERROR_TOO_LONG &&
378 cb > sizeof(wchar_t) * 2) {
380 wchar_t * t;
381 char ccname[MAX_PATH + 6];
383 ms = PMALLOC(cb);
385 #ifdef DEBUG
386 assert(ms);
387 #endif
389 khc_read_multi_string(csp_params, L"FileCCList", ms, &cb);
390 for(t = ms; t && *t; t = multi_string_next(t)) {
391 StringCchPrintfA(ccname, ARRAYLENGTH(ccname),
392 "FILE:%S", t);
394 code = krb5_cc_resolve(context, ccname, &cache);
395 if (code)
396 continue;
398 if (KHM_SUCCEEDED(khm_get_identity_expiration_time(context, cache,
399 ident,
400 &expiration))) {
401 if ( expiration > best_match_expiration ) {
402 best_match_expiration = expiration;
403 StringCbCopyA(best_match_ccname,
404 sizeof(best_match_ccname),
405 ccname);
406 expiration = 0;
410 if (context != NULL && cache != NULL)
411 krb5_cc_close(context, cache);
412 cache = 0;
415 PFREE(ms);
418 if (csp_params)
419 khc_close_space(csp_params);
421 if (best_match_ccname[0]) {
423 if (*pcbbuf = AnsiStrToUnicode((wchar_t *)buffer,
424 *pcbbuf,
425 best_match_ccname)) {
427 *pcbbuf = (*pcbbuf + 1) * sizeof(wchar_t);
429 return KHM_ERROR_SUCCESS;
434 return KHM_ERROR_GENERAL;