1/*
2 * $Header$
3 *
4 * Copyright 2006 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#include <Security/Authorization.h>
28#include <CoreFoundation/CoreFoundation.h>
29
30#include <string.h>
31#include <syslog.h>
32#include <stdlib.h>
33#include <errno.h>
34#include <time.h>
35#include <pthread.h>
36#include <stdio.h>
37
38#include <dispatch/dispatch.h>
39
40#include "heim.h"
41#include "mit-KerberosLogin.h"
42#include "mit-CredentialsCache.h"
43
44struct KLLoginOptions {
45    krb5_get_init_creds_opt *opt;
46    char *service;
47};
48
49/*
50 * Deprecated Error codes
51 */
52enum {
53    /* Carbon Dialog errors */
54    klDialogDoesNotExistErr             = 19676,
55    klDialogAlreadyExistsErr,
56    klNotInForegroundErr,
57    klNoAppearanceErr,
58    klFatalDialogErr,
59    klCarbonUnavailableErr
60};
61
62krb5_get_init_creds_opt *__KLLoginOptionsGetKerberos5Options (KLLoginOptions ioOptions);
63KLTime __KLLoginOptionsGetStartTime (KLLoginOptions ioOptions);
64char *__KLLoginOptionsGetServiceName (KLLoginOptions ioOptions);
65
66#define CHECK_VERSION(_vers) ((_vers) != kerberosVersion_V5 && (_vers) != kerberosVersion_All)
67
68
69KLStatus
70KLAcquireTickets (KLPrincipal   inPrincipal,
71		  KLPrincipal  *outPrincipal,
72		  char        **outCredCacheName)
73{
74    LOG_ENTRY();
75    return KLAcquireInitialTickets (inPrincipal,
76				    NULL,
77				    outPrincipal,
78				    outCredCacheName);
79}
80
81
82KLStatus
83KLAcquireNewTickets (KLPrincipal  inPrincipal,
84		     KLPrincipal  *outPrincipal,
85		     char        **outCredCacheName)
86{
87    LOG_ENTRY();
88    return KLAcquireNewInitialTickets (inPrincipal,
89				       NULL,
90				       outPrincipal,
91				       outCredCacheName);
92}
93
94
95KLStatus
96KLAcquireTicketsWithPassword (KLPrincipal      inPrincipal,
97			      KLLoginOptions   inLoginOptions,
98			      const char      *inPassword,
99			      char           **outCredCacheName)
100{
101    LOG_ENTRY();
102    return KLAcquireInitialTicketsWithPassword (inPrincipal,
103						inLoginOptions,
104						inPassword,
105						outCredCacheName);
106}
107
108
109KLStatus
110KLAcquireNewTicketsWithPassword (KLPrincipal      inPrincipal,
111				 KLLoginOptions   inLoginOptions,
112				 const char      *inPassword,
113				 char           **outCredCacheName)
114{
115    LOG_ENTRY();
116    return KLAcquireNewInitialTicketsWithPassword (inPrincipal,
117						   inLoginOptions,
118						   inPassword,
119						   outCredCacheName);
120}
121
122
123KLStatus
124KLSetApplicationOptions (const void *inAppOptions)
125{
126    return klNoErr;
127}
128
129
130KLStatus
131KLGetApplicationOptions (void *outAppOptions)
132{
133    return klDialogDoesNotExistErr;
134}
135
136#define kCoreAuthPanelKerberosRight "com.apple.KerberosAgent"
137#define kCoreAuthPanelKerberosPrincipal "principal"
138#define kCoreAuthPanelKerberosOptions "kerberosOptions"
139
140static OSStatus
141acquireticket_ui(KLPrincipal inPrincipal,
142		 KLLoginOptions inLoginOptions,
143		 KLPrincipal *outPrincipal,
144		 char **outCredCacheName)
145{
146    AuthorizationRef auth;
147    OSStatus ret;
148    char *princ = NULL;
149    CFDataRef d = NULL;
150
151    LOG_ENTRY();
152
153    if (outPrincipal)
154	*outPrincipal = NULL;
155    if (outCredCacheName)
156	*outCredCacheName = NULL;
157
158    if (inPrincipal) {
159	ret = heim_krb5_unparse_name(milcontext, inPrincipal, &princ);
160	if (ret)
161	    return ret;
162    }
163
164
165    ret = AuthorizationCreate(NULL, NULL, kAuthorizationFlagDefaults, &auth);
166    if (ret) {
167	free(princ);
168	return ret;
169    }
170
171    AuthorizationItem rightItems[1] = { kCoreAuthPanelKerberosRight, 0, NULL, 0 };
172    AuthorizationRights rights = { sizeof(rightItems[0])/sizeof(rightItems) , rightItems };
173    AuthorizationItem envItems[3];
174    AuthorizationEnvironment env = { 0 , envItems };
175    AuthorizationFlags authFlags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagExtendRights;
176
177    if (princ) {
178	envItems[env.count].name = kCoreAuthPanelKerberosPrincipal;
179	envItems[env.count].valueLength = strlen(princ);
180	envItems[env.count].value = princ;
181	envItems[env.count].flags = 0;
182	env.count++;
183    }
184
185    if (inLoginOptions && inLoginOptions->opt) {
186	CFMutableDictionaryRef dict;
187
188	dict = CFDictionaryCreateMutable(NULL, 1,
189					 &kCFTypeDictionaryKeyCallBacks,
190					 &kCFTypeDictionaryValueCallBacks);
191	if (dict == NULL)
192	    goto out;
193
194	if (inLoginOptions->opt->renew_life) {
195	    CFStringRef t;
196	    t = CFStringCreateWithFormat(NULL, 0, CFSTR("%ld"),(long)inLoginOptions->opt->renew_life);
197	    CFDictionarySetValue(dict, CFSTR("renewTime"), t);
198	    CFRelease(t);
199	}
200
201	d = CFPropertyListCreateData(NULL, dict, kCFPropertyListBinaryFormat_v1_0,
202				     0, NULL);
203	CFRelease(dict);
204
205	envItems[env.count].name = kCoreAuthPanelKerberosOptions;
206	envItems[env.count].valueLength = CFDataGetLength(d);
207	envItems[env.count].value = (void *)CFDataGetBytePtr(d);
208	envItems[env.count].flags = 0;
209	env.count++;
210    }
211
212    ret = AuthorizationCopyRights(auth, &rights, &env, authFlags, NULL);
213
214    if (ret == 0 && outPrincipal) {
215	AuthorizationItemSet *info;
216	UInt32 i;
217	ret = AuthorizationCopyInfo(auth, NULL, &info);
218	if (ret)
219	    goto out;
220	for(i = 0; i < info->count; i++) {
221	    if (strcmp(info->items[i].name, "out-principal") == 0) {
222		char *str;
223		asprintf(&str, "%.*s", (int)info->items[i].valueLength, (char *)info->items[i].value);
224		heim_krb5_parse_name(milcontext, str, outPrincipal);
225	    } else if (strcmp(info->items[i].name, "out-cache-name") == 0) {
226		asprintf(outCredCacheName, "%.*s", (int)info->items[i].valueLength, (char *)info->items[i].value);
227	    }
228	}
229	AuthorizationFreeItemSet(info);
230	if (*outPrincipal == NULL)
231	    ret = EINVAL;
232    }
233out:
234    if (d)
235	CFRelease(d);
236    AuthorizationFree(auth, kAuthorizationFlagDestroyRights);
237    free(princ);
238    return ret;
239}
240
241KLStatus
242KLAcquireInitialTickets(KLPrincipal      inPrincipal,
243			KLLoginOptions   inLoginOptions,
244			KLPrincipal     *outPrincipal,
245			char           **outCredCacheName)
246{
247    KLBoolean ValidTickets;
248    KLStatus ret;
249
250    LOG_ENTRY();
251
252    ret = KLCacheHasValidTickets(inPrincipal,
253				 kerberosVersion_V5,
254				 &ValidTickets,
255				 outPrincipal,
256				 outCredCacheName);
257    if (ret || !ValidTickets)
258	ret = acquireticket_ui(inPrincipal, inLoginOptions, outPrincipal, outCredCacheName);
259
260    return ret;
261}
262
263
264KLStatus
265KLAcquireNewInitialTickets (KLPrincipal      inPrincipal,
266			    KLLoginOptions   inLoginOptions,
267			    KLPrincipal     *outPrincipal,
268			    char           **outCredCacheName)
269{
270    LOG_ENTRY();
271
272    return acquireticket_ui(inPrincipal, inLoginOptions, outPrincipal, outCredCacheName);
273}
274
275
276KLStatus
277KLDestroyTickets(KLPrincipal inPrincipal)
278{
279    krb5_context context = mshim_ctx();
280    krb5_error_code ret;
281    krb5_ccache id;
282
283    ret = heim_krb5_cc_cache_match(context, inPrincipal, &id);
284    if (ret)
285	return ret;
286
287    return krb5_cc_destroy((mit_krb5_context)context, (mit_krb5_ccache)id);
288}
289
290
291KLStatus KLChangePassword (KLPrincipal inPrincipal)
292{
293    LOG_UNIMPLEMENTED();
294    return EINVAL;
295}
296
297
298KLStatus
299KLAcquireInitialTicketsWithPassword(KLPrincipal      inPrincipal,
300				    KLLoginOptions   inLoginOptions,
301				    const char      *inPassword,
302				    char           **outCredCacheName)
303{
304    KLStatus ret;
305    KLBoolean ValidTickets;
306
307    ret = KLCacheHasValidTickets(inPrincipal,
308				 kerberosVersion_V5,
309				 &ValidTickets,
310				 NULL,
311				 outCredCacheName);
312    if (ret == 0) {
313	if (ValidTickets)
314	    return klNoErr; /* done */
315	/* get credential */
316	if (outCredCacheName)
317	    free(*outCredCacheName);
318    }
319    return KLAcquireNewInitialTicketsWithPassword(inPrincipal,
320						  inLoginOptions,
321						  inPassword,
322						  outCredCacheName);
323}
324
325KLStatus
326KLAcquireNewInitialTicketsWithPassword(KLPrincipal      inPrincipal,
327				       KLLoginOptions   inLoginOptions,
328				       const char      *inPassword,
329				       char           **outCredCacheName)
330{
331    krb5_context context = mshim_ctx();
332    krb5_error_code ret;
333    krb5_ccache cache;
334    krb5_creds creds;
335    char *service = NULL;
336    krb5_get_init_creds_opt *opt = NULL;
337
338    LOG_ENTRY();
339
340    if (inLoginOptions) {
341	service = inLoginOptions->service;
342	opt = inLoginOptions->opt;
343    }
344
345    ret = heim_krb5_get_init_creds_password(context, &creds,
346					    inPrincipal, inPassword,
347					    NULL, NULL, 0,
348					    service,
349					    opt);
350    if (ret)
351	return ret;
352
353    ret = heim_krb5_cc_cache_match(context, inPrincipal, &cache);
354    if (ret)
355	ret = heim_krb5_cc_new_unique(context, NULL, NULL, &cache);
356    if (ret)
357	goto out;
358
359    ret = heim_krb5_cc_initialize(context, cache, creds.client);
360    if(ret)
361	goto out;
362
363    ret = heim_krb5_cc_store_cred(context, cache, &creds);
364    if (ret)
365	goto out;
366
367    if (outCredCacheName)
368	*outCredCacheName = strdup(heim_krb5_cc_get_name(context, cache));
369
370 out:
371    if (cache) {
372	if (ret)
373	    krb5_cc_destroy((mit_krb5_context)context, (mit_krb5_ccache)cache);
374	else
375	    heim_krb5_cc_close(context, cache);
376    }
377    heim_krb5_free_cred_contents(context, &creds);
378
379    return ret;
380}
381
382
383KLStatus KLAcquireNewInitialTicketCredentialsWithPassword (KLPrincipal      inPrincipal,
384                                                           KLLoginOptions   inLoginOptions,
385                                                           const char      *inPassword,
386                                                           void            *inV5Context,
387                                                           KLBoolean       *outGotV4Credentials,
388                                                           KLBoolean       *outGotV5Credentials,
389                                                           void            *outV4Credentials,
390                                                           void            *outV5Credentials)
391{
392    LOG_UNIMPLEMENTED();
393    return EINVAL;
394}
395
396
397KLStatus KLStoreNewInitialTicketCredentials (KLPrincipal     inPrincipal,
398                                             void           *inV5Context,
399                                             void           *inV4Credentials,
400                                             void           *inV5Credentials,
401                                             char          **outCredCacheName)
402{
403    LOG_UNIMPLEMENTED();
404    return EINVAL;
405}
406
407
408KLStatus KLVerifyInitialTickets (KLPrincipal   inPrincipal,
409                                 KLBoolean     inFailIfNoHostKey,
410                                 char        **outCredCacheName)
411{
412    LOG_UNIMPLEMENTED();
413    return klNoErr;
414}
415
416
417KLStatus KLVerifyInitialTicketCredentials (void        *inV4Credentials,
418                                           void        *inV5Credentials,
419                                           KLBoolean    inFailIfNoHostKey)
420{
421    LOG_UNIMPLEMENTED();
422    return klNoErr;
423}
424
425
426KLStatus KLAcquireNewInitialTicketsWithKeytab (KLPrincipal      inPrincipal,
427                                               KLLoginOptions   inLoginOptions,
428                                               const char      *inKeytabName,
429                                               char           **outCredCacheName)
430{
431    LOG_UNIMPLEMENTED();
432    return EINVAL;
433}
434
435
436KLStatus
437KLRenewInitialTickets(KLPrincipal      inPrincipal,
438		      KLLoginOptions   inLoginOptions,
439		      KLPrincipal     *outPrincipal,
440		      char           **outCredCacheName)
441{
442    krb5_context context = mshim_ctx();
443    krb5_error_code ret;
444    krb5_creds in, *cred = NULL;
445    krb5_ccache id;
446    krb5_kdc_flags flags;
447    krb5_const_realm realm;
448    krb5_principal principal = NULL;
449
450    memset(&in, 0, sizeof(in));
451
452    LOG_ENTRY();
453
454    if (outPrincipal)
455	*outPrincipal = NULL;
456    if (outCredCacheName)
457	*outCredCacheName = NULL;
458
459    if (inPrincipal) {
460	principal = inPrincipal;
461    } else {
462	ret = heim_krb5_get_default_principal(context, &principal);
463	if (ret)
464	    return ret;
465    }
466
467    ret = heim_krb5_cc_cache_match(context, principal, &id);
468    if (ret) {
469	if (inPrincipal == NULL)
470	    heim_krb5_free_principal(context, principal);
471	return ret;
472    }
473
474    in.client = principal;
475
476    realm = heim_krb5_principal_get_realm(context, in.client);
477
478    if (inLoginOptions && inLoginOptions->service)
479	ret = heim_krb5_make_principal(context, &in.server, realm, inLoginOptions->service, NULL);
480    else
481	ret = heim_krb5_make_principal(context, &in.server, realm, KRB5_TGS_NAME, realm, NULL);
482    if (ret) {
483	if (inPrincipal == NULL)
484	    heim_krb5_free_principal(context, principal);
485	heim_krb5_cc_close(context, id);
486	return ret;
487    }
488
489    flags.i = 0;
490    if (inLoginOptions)
491	flags.i = inLoginOptions->opt->flags;
492
493    /* Pull out renewable from previous ticket */
494    ret = heim_krb5_get_credentials(context, KRB5_GC_CACHED, id, &in, &cred);
495    if (inPrincipal == NULL)
496	heim_krb5_free_principal(context, principal);
497    if (ret == 0 && cred) {
498	flags.b.renewable = cred->flags.b.renewable;
499	heim_krb5_free_creds (context, cred);
500	cred = NULL;
501    }
502
503    flags.b.renew = 1;
504
505    ret = heim_krb5_get_kdc_cred(context, id, flags, NULL, NULL, &in, &cred);
506    heim_krb5_free_principal(context, in.server);
507    if (ret)
508	goto out;
509    ret = heim_krb5_cc_initialize(context, id, in.client);
510    if (ret)
511	goto out;
512    ret = heim_krb5_cc_store_cred(context, id, cred);
513
514 out:
515    if (cred)
516	heim_krb5_free_creds (context, cred);
517    heim_krb5_cc_close(context, id);
518
519    return ret;
520}
521
522
523KLStatus KLValidateInitialTickets (KLPrincipal      inPrincipal,
524                                   KLLoginOptions   inLoginOptions,
525                                   char           **outCredCacheName)
526{
527    LOG_UNIMPLEMENTED();
528    return klNoErr;
529}
530
531static krb5_timestamp g_cc_change_time = 0;
532static KLTime g_kl_change_time = 0;
533static pthread_mutex_t g_change_time_mutex = PTHREAD_MUTEX_INITIALIZER;
534
535
536KLStatus
537KLLastChangedTime(KLTime *outLastChangedTime)
538{
539    krb5_timestamp ccChangeTime;
540    KLStatus ret;
541
542    LOG_ENTRY();
543
544    if (outLastChangedTime == NULL)
545	return klParameterErr;
546
547    ret = heim_krb5_cccol_last_change_time(milcontext, "API", &ccChangeTime);
548    if (ret)
549	return ret;
550
551    pthread_mutex_lock(&g_change_time_mutex);
552
553    if (g_kl_change_time == 0)
554	g_kl_change_time = ccChangeTime;
555
556    if (ccChangeTime > g_cc_change_time) {
557
558	if (ccChangeTime > g_kl_change_time)
559	    g_kl_change_time = ccChangeTime;
560	else
561	    g_kl_change_time++;
562
563	g_cc_change_time = ccChangeTime;
564    }
565
566    *outLastChangedTime = g_kl_change_time;
567
568    pthread_mutex_unlock (&g_change_time_mutex);
569
570    return klNoErr;
571}
572
573
574static krb5_error_code
575fetch_creds(KLPrincipal inPrincipal, krb5_creds **ocreds,
576	    char **outCredCacheName)
577{
578    krb5_context context = mshim_ctx();
579    krb5_principal princ = NULL;
580    krb5_creds in_creds;
581    krb5_const_realm realm;
582    krb5_error_code ret;
583    krb5_ccache id = NULL;
584
585    LOG_ENTRY();
586
587    memset(&in_creds, 0, sizeof(in_creds));
588
589    if (inPrincipal) {
590	ret = heim_krb5_cc_cache_match(context, inPrincipal, &id);
591    } else {
592	ret = heim_krb5_cc_default(context, &id);
593	if (ret == 0)
594	    ret = heim_krb5_cc_get_principal(context, id, &princ);
595	inPrincipal = princ;
596    }
597    if (ret)
598	goto out;
599
600    realm = heim_krb5_principal_get_realm(context, inPrincipal);
601    ret = heim_krb5_make_principal(context, &in_creds.server, realm, KRB5_TGS_NAME, realm, NULL);
602    if (ret)
603	goto out;
604
605    in_creds.client = inPrincipal;
606
607    ret = heim_krb5_get_credentials(context, KRB5_GC_CACHED, id,
608				    &in_creds, ocreds);
609    heim_krb5_free_principal(context, in_creds.server);
610
611    if (outCredCacheName)
612	*outCredCacheName = strdup(heim_krb5_cc_get_name(context, id));
613
614 out:
615    if (id)
616	heim_krb5_cc_close(context, id);
617    if (princ)
618	heim_krb5_free_principal(context, princ);
619
620    return LOG_FAILURE(ret, "fetch_creds");
621}
622
623
624KLStatus KLCacheHasValidTickets (KLPrincipal         inPrincipal,
625                                 KLKerberosVersion   inKerberosVersion,
626                                 KLBoolean          *outFoundValidTickets,
627                                 KLPrincipal        *outPrincipal,
628                                 char              **outCredCacheName)
629{
630    krb5_error_code ret;
631    krb5_creds *ocreds = NULL;
632
633    LOG_ENTRY();
634
635    if (outPrincipal)
636	*outPrincipal = NULL;
637
638    if (CHECK_VERSION(inKerberosVersion))
639	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
640
641    ret = fetch_creds(inPrincipal, &ocreds, outCredCacheName);
642
643    if (ret == 0) {
644	time_t t = time(NULL);
645	/* consinder tickets that are slightly too young as valid
646	 * since might just have fetched them */
647	*outFoundValidTickets =
648	       (ocreds->times.starttime - 10 < t)
649	    && (t < ocreds->times.endtime);
650
651	if (outPrincipal)
652	    (void)heim_krb5_copy_principal(milcontext, ocreds->client, outPrincipal);
653	heim_krb5_free_creds(milcontext, ocreds);
654    } else {
655	LOG_FAILURE(ret, "fetch tickets failed");
656	ret = 0;
657	*outFoundValidTickets = 0;
658    }
659
660
661    return LOG_FAILURE(ret, "KLCacheHasValidTickets");
662}
663
664
665KLStatus KLTicketStartTime (KLPrincipal        inPrincipal,
666                            KLKerberosVersion  inKerberosVersion,
667                            KLTime            *outStartTime)
668{
669    krb5_creds *creds;
670    krb5_error_code ret;
671
672    LOG_ENTRY();
673
674    if (CHECK_VERSION(inKerberosVersion))
675	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
676
677    ret = fetch_creds(inPrincipal, &creds, NULL);
678    if (ret)
679	return LOG_FAILURE(ret, "fetch tickets failed");
680
681    *outStartTime = creds->times.starttime;
682
683    heim_krb5_free_creds(milcontext, creds);
684    return klNoErr;
685}
686
687
688KLStatus KLTicketExpirationTime (KLPrincipal        inPrincipal,
689                                 KLKerberosVersion  inKerberosVersion,
690                                 KLTime            *outExpirationTime)
691{
692    krb5_error_code ret;
693    krb5_creds *creds;
694
695    LOG_ENTRY();
696
697    if (CHECK_VERSION(inKerberosVersion))
698	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
699
700    ret = fetch_creds(inPrincipal, &creds, NULL);
701    if (ret)
702	return LOG_FAILURE(ret, "fetch tickets failed");
703
704    *outExpirationTime = creds->times.endtime;
705
706    heim_krb5_free_creds(milcontext, creds);
707    return klNoErr;
708}
709
710
711KLStatus
712KLSetSystemDefaultCache (KLPrincipal inPrincipal)
713{
714    krb5_context context = mshim_ctx();
715    krb5_error_code ret;
716    krb5_ccache id;
717
718    LOG_ENTRY();
719
720    ret = heim_krb5_cc_cache_match(context, inPrincipal, &id);
721    if (ret)
722	return LOG_FAILURE(ret, "ccache match");
723    ret = heim_krb5_cc_switch(context, id);
724    heim_krb5_cc_close(context, id);
725    if (ret)
726	return LOG_FAILURE(ret, "cc switch");
727    return klNoErr;
728}
729
730
731KLStatus KLHandleError (KLStatus           inError,
732                        KLDialogIdentifier inDialogIdentifier,
733                        KLBoolean          inShowAlert)
734{
735    LOG_UNIMPLEMENTED();
736    return klNoErr;
737}
738
739
740KLStatus KLGetErrorString (KLStatus   inError,
741                           char     **outErrorString)
742{
743    const char *msg;
744    LOG_ENTRY();
745
746    msg = heim_krb5_get_error_message(milcontext, (krb5_error_code)inError);
747    if (msg) {
748	*outErrorString = strdup(msg);
749	krb5_free_error_message((mit_krb5_context)milcontext, msg);
750    } else
751	asprintf(outErrorString, "unknown error: %d\n", (int)inError);
752    if (*outErrorString == NULL)
753	return klMemFullErr;
754    return klNoErr;
755}
756
757
758KLStatus KLCancelAllDialogs (void)
759{
760    return klNoErr;
761}
762
763
764/* Kerberos change password dialog low level functions */
765
766KLStatus KLChangePasswordWithPasswords (KLPrincipal   inPrincipal,
767                                        const char   *inOldPassword,
768                                        const char   *inNewPassword,
769                                        KLBoolean    *outRejected,
770                                        char        **outRejectionError,
771                                        char        **outRejectionDescription)
772{
773    LOG_UNIMPLEMENTED();
774    return EINVAL;
775}
776
777
778/* Application Configuration functions */
779
780KLStatus KLSetIdleCallback (const KLIdleCallback inCallback,
781                            const KLRefCon inRefCon)
782{
783    return klNoErr;
784}
785
786
787KLStatus KLGetIdleCallback (KLIdleCallback* inCallback,
788                            KLRefCon* inRefCon)
789{
790    return klNoErr;
791}
792
793
794/* Library configuration functions */
795/* Deprecated options which we now ignore */
796enum {
797    loginOption_ShowOptions                = 'sopt',
798    loginOption_RememberShowOptions        = 'ropt',
799    loginOption_LongTicketLifetimeDisplay  = 'hms ',
800    loginOption_RememberPassword           = 'pass'
801};
802
803
804
805KLStatus KLGetDefaultLoginOption (const KLDefaultLoginOption  inOption,
806                                  void                       *ioBuffer,
807                                  KLSize                     *ioBufferSize)
808{
809    LOG_UNIMPLEMENTED();
810    return EINVAL;
811}
812
813
814KLStatus KLSetDefaultLoginOption (const KLDefaultLoginOption  inOption,
815                                  const void                 *inBuffer,
816                                  const KLSize                inBufferSize)
817{
818    LOG_UNIMPLEMENTED();
819    return EINVAL;
820}
821
822
823/* Realm configuration functions */
824
825KLStatus KLFindKerberosRealmByName (const char *inRealmName,
826                                    KLIndex    *outIndex)
827{
828    KLStatus ret;
829    char *realm = NULL;
830
831    ret = KLGetKerberosDefaultRealmByName (&realm);
832    if (ret == klNoErr) {
833        if (!strcmp (inRealmName, realm)) {
834            *outIndex = 0;
835        } else {
836            ret = klRealmDoesNotExistErr;
837        }
838	free(realm);
839    }
840
841
842    return ret;
843}
844
845
846KLStatus KLGetKerberosRealm (KLIndex   inIndex,
847                             char    **outRealmName)
848{
849    return KLGetKerberosDefaultRealmByName (outRealmName);
850}
851
852
853KLStatus KLSetKerberosRealm (KLIndex     inIndex,
854                             const char *inRealmName)
855{
856    return klNoErr;
857}
858
859
860KLStatus KLRemoveKerberosRealm (KLIndex inIndex)
861{
862    return klNoErr;
863}
864
865
866KLStatus KLInsertKerberosRealm (KLIndex     inInsertBeforeIndex,
867                                const char *inRealmName)
868{
869    return klNoErr;
870}
871
872
873KLStatus KLRemoveAllKerberosRealms (void)
874{
875    return klNoErr;
876}
877
878
879KLSize KLCountKerberosRealms (void)
880{
881    return 1;
882}
883
884
885KLStatus KLGetKerberosDefaultRealm(KLIndex *outIndex)
886{
887    if(outIndex)
888	*outIndex = 0;
889
890    return klNoErr;
891}
892
893
894KLStatus KLGetKerberosDefaultRealmByName (char **outRealmName)
895{
896    LOG_ENTRY();
897
898    return krb5_get_default_realm((mit_krb5_context)milcontext, outRealmName);
899}
900
901
902KLStatus KLSetKerberosDefaultRealm (KLIndex inIndex)
903{
904    return klNoErr;
905}
906
907
908KLStatus KLSetKerberosDefaultRealmByName (const char *inRealm)
909{
910    return klNoErr;
911}
912
913
914/* KLPrincipal functions */
915
916KLStatus
917KLCreatePrincipalFromTriplet (const char  *inName,
918			      const char  *inInstance,
919			      const char  *inRealm,
920			      KLPrincipal *outPrincipal)
921{
922    return heim_krb5_make_principal(milcontext, outPrincipal, inRealm, inName, inInstance, NULL);
923}
924
925
926KLStatus
927KLCreatePrincipalFromString (const char        *inFullPrincipal,
928			     KLKerberosVersion  inKerberosVersion,
929			     KLPrincipal       *outPrincipal)
930{
931    LOG_ENTRY();
932
933    if (CHECK_VERSION(inKerberosVersion))
934	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
935
936    if (inFullPrincipal == NULL)
937	return klParameterErr;
938    return heim_krb5_parse_name(milcontext, inFullPrincipal, outPrincipal);
939}
940
941
942KLStatus KLCreatePrincipalFromKerberos5Principal (void           *inKerberos5Principal,
943                                                  KLPrincipal    *outPrincipal)
944{
945    if (inKerberos5Principal == NULL)
946	return klParameterErr;
947    return heim_krb5_copy_principal(milcontext, inKerberos5Principal, outPrincipal);
948}
949
950
951KLStatus KLCreatePrincipalFromPrincipal (KLPrincipal inPrincipal,
952                                         KLPrincipal *outPrincipal)
953{
954    if (inPrincipal == NULL)
955	return klParameterErr;
956    return heim_krb5_copy_principal(milcontext, inPrincipal, outPrincipal);
957}
958
959
960KLStatus
961KLGetTripletFromPrincipal(KLPrincipal inPrincipal,
962			  char **outName,
963			  char **outInstance,
964			  char **outRealm)
965{
966    LOG_ENTRY();
967
968    if (outName)
969	*outName = NULL;
970    if (outInstance)
971	*outInstance = NULL;
972    if (outRealm)
973	*outRealm = NULL;
974
975    if (inPrincipal == NULL)
976	return klParameterErr;
977
978    switch (inPrincipal->name.name_string.len) {
979    case 2:
980	if (outInstance)
981	    *outInstance = strdup(inPrincipal->name.name_string.val[1]);
982    case 1:
983	if (outName)
984	    *outName = strdup(inPrincipal->name.name_string.val[0]);
985	break;
986    default:
987	return klInvalidOptionErr;
988    }
989    if (outRealm)
990	*outRealm = strdup(inPrincipal->realm);
991
992    return klNoErr;
993}
994
995KLStatus
996KLGetStringFromPrincipal (KLPrincipal         inPrincipal,
997			  KLKerberosVersion   inKerberosVersion,
998			  char              **outFullPrincipal)
999{
1000    LOG_ENTRY();
1001    if (inPrincipal == NULL)
1002	return klParameterErr;
1003    if (CHECK_VERSION(inKerberosVersion))
1004	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
1005    return heim_krb5_unparse_name(milcontext, inPrincipal, outFullPrincipal);
1006}
1007
1008
1009KLStatus
1010KLGetDisplayStringFromPrincipal (KLPrincipal         inPrincipal,
1011				 KLKerberosVersion   inKerberosVersion,
1012				 char              **outFullPrincipal)
1013{
1014    LOG_ENTRY();
1015    if (inPrincipal == NULL)
1016	return klParameterErr;
1017    if (CHECK_VERSION(inKerberosVersion))
1018	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
1019    return heim_krb5_unparse_name(milcontext, inPrincipal, outFullPrincipal);
1020}
1021
1022
1023KLStatus
1024KLComparePrincipal (KLPrincipal  inFirstPrincipal,
1025		    KLPrincipal  inSecondPrincipal,
1026		    KLBoolean   *outAreEquivalent)
1027{
1028    LOG_ENTRY();
1029    if (inFirstPrincipal == NULL || inSecondPrincipal == NULL)
1030	return klParameterErr;
1031    *outAreEquivalent = heim_krb5_principal_compare(milcontext, inFirstPrincipal, inSecondPrincipal);
1032    return klNoErr;
1033}
1034
1035
1036KLStatus
1037KLDisposePrincipal (KLPrincipal inPrincipal)
1038{
1039    LOG_ENTRY();
1040    if (inPrincipal == NULL)
1041	return klNoErr;
1042    heim_krb5_free_principal(milcontext, inPrincipal);
1043    return klNoErr;
1044}
1045
1046
1047/* KLLoginOptions functions */
1048
1049KLStatus
1050KLCreateLoginOptions (KLLoginOptions *outOptions)
1051{
1052    struct KLLoginOptions *opt;
1053    krb5_error_code ret;
1054
1055    *outOptions = NULL;
1056
1057    LOG_ENTRY();
1058
1059    opt = calloc(1, sizeof(*opt));
1060
1061    ret = heim_krb5_get_init_creds_opt_alloc(milcontext, &opt->opt);
1062    if (ret) {
1063	free(opt);
1064	return ret; /* XXX */
1065    }
1066    *outOptions = opt;
1067    return klNoErr;
1068}
1069
1070
1071KLStatus KLLoginOptionsSetTicketLifetime (KLLoginOptions ioOptions,
1072                                          KLLifetime     inTicketLifetime)
1073{
1074    LOG_ENTRY();
1075    heim_krb5_get_init_creds_opt_set_tkt_life(ioOptions->opt, inTicketLifetime);
1076    return klNoErr;
1077}
1078
1079
1080KLStatus KLLoginOptionsSetForwardable (KLLoginOptions ioOptions,
1081                                       KLBoolean      inForwardable)
1082{
1083    LOG_ENTRY();
1084    heim_krb5_get_init_creds_opt_set_forwardable(ioOptions->opt, inForwardable);
1085    return klNoErr;
1086}
1087
1088
1089KLStatus KLLoginOptionsSetProxiable (KLLoginOptions ioOptions,
1090                                     KLBoolean      inProxiable)
1091{
1092    LOG_ENTRY();
1093    heim_krb5_get_init_creds_opt_set_proxiable(ioOptions->opt, inProxiable);
1094    return klNoErr;
1095}
1096
1097
1098KLStatus KLLoginOptionsSetRenewableLifetime (KLLoginOptions ioOptions,
1099                                             KLLifetime     inRenewableLifetime)
1100{
1101    LOG_ENTRY();
1102    heim_krb5_get_init_creds_opt_set_renew_life(ioOptions->opt, inRenewableLifetime);
1103    return klNoErr;
1104}
1105
1106
1107KLStatus
1108KLLoginOptionsSetAddressless (KLLoginOptions ioOptions,
1109			      KLBoolean      inAddressless)
1110{
1111    LOG_ENTRY();
1112    return klNoErr;
1113}
1114
1115
1116KLStatus
1117KLLoginOptionsSetTicketStartTime (KLLoginOptions ioOptions,
1118				  KLTime         inStartTime)
1119{
1120    LOG_ENTRY();
1121    return klNoErr;
1122}
1123
1124
1125KLStatus
1126KLLoginOptionsSetServiceName(KLLoginOptions  ioOptions,
1127			     const char     *inServiceName)
1128{
1129    LOG_ENTRY();
1130    if (ioOptions->service)
1131	free(ioOptions->service);
1132    ioOptions->service = strdup(inServiceName);
1133    return klNoErr;
1134}
1135
1136
1137KLStatus KLDisposeLoginOptions(KLLoginOptions ioOptions)
1138{
1139    LOG_ENTRY();
1140    heim_krb5_get_init_creds_opt_free(milcontext, ioOptions->opt);
1141    if (ioOptions->service)
1142	free(ioOptions->service);
1143    free(ioOptions);
1144    return klNoErr;
1145}
1146
1147
1148KLStatus KLDisposeString (char *inStringToDispose)
1149{
1150    free(inStringToDispose);
1151    return klNoErr;
1152}
1153
1154KLStatus __KLSetApplicationPrompter(int inPrompter)
1155{
1156    /* Deprecated */
1157    return klNoErr;
1158}
1159
1160KLStatus __KLSetHomeDirectoryAccess (KLBoolean inAllowHomeDirectoryAccess)
1161{
1162    return heim_krb5_set_home_dir_access(NULL, inAllowHomeDirectoryAccess);
1163}
1164
1165
1166KLBoolean __KLAllowHomeDirectoryAccess (void)
1167{
1168    return 1;
1169}
1170
1171
1172KLStatus __KLSetAutomaticPrompting (KLBoolean inAllowAutomaticPrompting)
1173{
1174    return klNoErr;
1175}
1176
1177
1178KLBoolean __KLAllowAutomaticPrompting (void)
1179{
1180    return 0;
1181}
1182
1183
1184KLStatus __KLSetPromptMechanism (int inPromptMechanism)
1185{
1186    return klNoErr;
1187}
1188
1189
1190int __KLPromptMechanism (void)
1191{
1192    return klPromptMechanism_None;
1193}
1194
1195
1196KLBoolean __KLAllowRememberPassword (void)
1197{
1198    return klNoErr;
1199}
1200
1201
1202KLStatus __KLCreatePrincipalFromTriplet (const char  *inName,
1203                                         const char  *inInstance,
1204                                         const char  *inRealm,
1205                                         KLKerberosVersion  inKerberosVersion,
1206                                         KLPrincipal *outPrincipal)
1207{
1208    LOG_UNIMPLEMENTED();
1209    if (CHECK_VERSION(inKerberosVersion))
1210	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
1211    return EINVAL;
1212}
1213
1214
1215KLStatus __KLGetTripletFromPrincipal (KLPrincipal         inPrincipal,
1216                                      KLKerberosVersion   inKerberosVersion,
1217                                      char              **outName,
1218                                      char              **outInstance,
1219                                      char              **outRealm)
1220{
1221    LOG_UNIMPLEMENTED();
1222    if (CHECK_VERSION(inKerberosVersion))
1223	return LOG_FAILURE(klInvalidVersionErr, "wrong version");
1224    return EINVAL;
1225}
1226
1227
1228KLStatus __KLCreatePrincipalFromKerberos5Principal (krb5_principal inPrincipal,
1229                                                    KLPrincipal *outPrincipal)
1230{
1231    return KLCreatePrincipalFromKerberos5Principal (inPrincipal, outPrincipal);
1232}
1233
1234
1235KLStatus __KLGetKerberos5PrincipalFromPrincipal (KLPrincipal     inPrincipal,
1236                                                 krb5_context    inContext,
1237                                                 krb5_principal *outKrb5Principal)
1238{
1239    LOG_UNIMPLEMENTED();
1240    return EINVAL;
1241}
1242
1243
1244KLBoolean __KLPrincipalIsTicketGrantingService (KLPrincipal inPrincipal)
1245{
1246    LOG_UNIMPLEMENTED();
1247    return klNoErr;
1248}
1249
1250
1251KLStatus __KLGetKeychainPasswordForPrincipal (KLPrincipal   inPrincipal,
1252                                              char        **outPassword)
1253{
1254    LOG_UNIMPLEMENTED();
1255    return EINVAL;
1256}
1257
1258
1259
1260KLStatus __KLPrincipalSetKeychainPassword (KLPrincipal  inPrincipal,
1261                                           const char  *inPassword)
1262{
1263    return klNoErr;
1264}
1265
1266
1267KLStatus __KLRemoveKeychainPasswordForPrincipal (KLPrincipal inPrincipal)
1268{
1269    return klNoErr;
1270}
1271
1272krb5_get_init_creds_opt *
1273__KLLoginOptionsGetKerberos5Options (KLLoginOptions ioOptions)
1274{
1275    return NULL;
1276}
1277
1278KLTime __KLLoginOptionsGetStartTime (KLLoginOptions ioOptions)
1279{
1280    return klNoErr;
1281}
1282
1283char *__KLLoginOptionsGetServiceName (KLLoginOptions ioOptions)
1284{
1285    return NULL;
1286}
1287