#include "k5-int.h"
#include <errno.h>
krb5_error_code KRB5_CALLCONV krb5_mcc_close
(krb5_context, krb5_ccache id );
krb5_error_code KRB5_CALLCONV krb5_mcc_destroy
(krb5_context, krb5_ccache id );
krb5_error_code KRB5_CALLCONV krb5_mcc_end_seq_get
(krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
krb5_error_code KRB5_CALLCONV krb5_mcc_generate_new
(krb5_context, krb5_ccache *id );
const char * KRB5_CALLCONV krb5_mcc_get_name
(krb5_context, krb5_ccache id );
krb5_error_code KRB5_CALLCONV krb5_mcc_get_principal
(krb5_context, krb5_ccache id , krb5_principal *princ );
krb5_error_code KRB5_CALLCONV krb5_mcc_initialize
(krb5_context, krb5_ccache id , krb5_principal princ );
krb5_error_code KRB5_CALLCONV krb5_mcc_next_cred
(krb5_context,
krb5_ccache id ,
krb5_cc_cursor *cursor ,
krb5_creds *creds );
krb5_error_code KRB5_CALLCONV krb5_mcc_resolve
(krb5_context, krb5_ccache *id , const char *residual );
krb5_error_code KRB5_CALLCONV krb5_mcc_retrieve
(krb5_context,
krb5_ccache id ,
krb5_flags whichfields ,
krb5_creds *mcreds ,
krb5_creds *creds );
krb5_error_code KRB5_CALLCONV krb5_mcc_start_seq_get
(krb5_context, krb5_ccache id , krb5_cc_cursor *cursor );
krb5_error_code KRB5_CALLCONV krb5_mcc_store
(krb5_context, krb5_ccache id , krb5_creds *creds );
krb5_error_code KRB5_CALLCONV krb5_mcc_set_flags
(krb5_context, krb5_ccache id , krb5_flags flags );
extern const krb5_cc_ops krb5_mcc_ops;
krb5_error_code krb5_change_cache (void);
#define KRB5_OK 0
typedef struct _krb5_mcc_link {
struct _krb5_mcc_link *next;
krb5_creds *creds;
} krb5_mcc_link, *krb5_mcc_cursor;
typedef struct _krb5_mcc_data {
struct _krb5_mcc_data *next;
char *name;
krb5_principal prin;
krb5_mcc_cursor link;
} krb5_mcc_data;
static krb5_mcc_data *mcc_head = 0;
void krb5_mcc_free (krb5_context context, krb5_ccache id);
krb5_error_code KRB5_CALLCONV
krb5_mcc_initialize(krb5_context context, krb5_ccache id, krb5_principal princ)
{
krb5_error_code ret;
krb5_mcc_free(context, id);
ret = krb5_copy_principal(context, princ,
&((krb5_mcc_data *)id->data)->prin);
if (ret == KRB5_OK)
krb5_change_cache();
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_close(krb5_context context, krb5_ccache id)
{
krb5_xfree(id);
return KRB5_OK;
}
void
krb5_mcc_free(krb5_context context, krb5_ccache id)
{
krb5_mcc_cursor curr,next;
for (curr = ((krb5_mcc_data *)id->data)->link; curr;)
{
krb5_free_creds(context, curr->creds);
next = curr->next;
krb5_xfree(curr);
curr = next;
}
((krb5_mcc_data *)id->data)->link = NULL;
krb5_free_principal(context, ((krb5_mcc_data *)id->data)->prin);
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_destroy(krb5_context context, krb5_ccache id)
{
krb5_mcc_data *curr;
if (mcc_head && ((krb5_mcc_data *)id->data) == mcc_head)
mcc_head = mcc_head->next;
else {
for (curr=mcc_head; curr; curr=curr->next)
if (curr->next == ((krb5_mcc_data *)id->data)) {
curr->next = curr->next->next;
break;
}
}
krb5_mcc_free(context, id);
krb5_xfree(((krb5_mcc_data *)id->data)->name);
krb5_xfree(id->data);
krb5_xfree(id);
#if 0
--krb5_cache_sessions;
#endif
krb5_change_cache ();
return KRB5_OK;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_resolve (krb5_context context, krb5_ccache *id, const char *residual)
{
krb5_ccache lid;
krb5_mcc_data *ptr;
lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
if (lid == NULL)
return KRB5_CC_NOMEM;
lid->ops = &krb5_mcc_ops;
for (ptr = mcc_head; ptr; ptr=ptr->next)
if (!strcmp(ptr->name, residual))
break;
if (ptr) {
lid->data = ptr;
} else {
lid->data = (krb5_pointer) malloc(sizeof(krb5_mcc_data));
if (lid->data == NULL) {
krb5_xfree(lid);
return KRB5_CC_NOMEM;
}
((krb5_mcc_data *) lid->data)->name = (char *)
malloc(strlen(residual) + 1);
if (((krb5_mcc_data *)lid->data)->name == NULL) {
krb5_xfree(((krb5_mcc_data *)lid->data));
krb5_xfree(lid);
return KRB5_CC_NOMEM;
}
strcpy(((krb5_mcc_data *)lid->data)->name, residual);
((krb5_mcc_data *)lid->data)->link = 0L;
((krb5_mcc_data *)lid->data)->prin = 0L;
((krb5_mcc_data *)lid->data)->next = mcc_head;
mcc_head = (krb5_mcc_data *)lid->data;
#if 0
++krb5_cache_sessions;
#endif
}
*id = lid;
return KRB5_OK;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_start_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
{
krb5_mcc_cursor mcursor;
mcursor = ((krb5_mcc_data *)id->data)->link;
*cursor = (krb5_cc_cursor) mcursor;
return KRB5_OK;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_next_cred(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor, krb5_creds *creds)
{
krb5_mcc_cursor mcursor;
krb5_error_code retval;
krb5_data *scratch;
mcursor = (krb5_mcc_cursor) *cursor;
if (mcursor == NULL)
return KRB5_CC_END;
memset(creds, 0, sizeof(krb5_creds));
if (mcursor->creds) {
*creds = *mcursor->creds;
retval = krb5_copy_principal(context, mcursor->creds->client, &creds->client);
if (retval)
return retval;
retval = krb5_copy_principal(context, mcursor->creds->server,
&creds->server);
if (retval)
goto cleanclient;
retval = krb5_copy_keyblock_contents(context, &mcursor->creds->keyblock,
&creds->keyblock);
if (retval)
goto cleanserver;
retval = krb5_copy_addresses(context, mcursor->creds->addresses,
&creds->addresses);
if (retval)
goto cleanblock;
retval = krb5_copy_data(context, &mcursor->creds->ticket, &scratch);
if (retval)
goto cleanaddrs;
creds->ticket = *scratch;
krb5_xfree(scratch);
retval = krb5_copy_data(context, &mcursor->creds->second_ticket, &scratch);
if (retval)
goto cleanticket;
creds->second_ticket = *scratch;
krb5_xfree(scratch);
retval = krb5_copy_authdata(context, mcursor->creds->authdata,
&creds->authdata);
if (retval)
goto clearticket;
}
*cursor = (krb5_cc_cursor)mcursor->next;
return KRB5_OK;
clearticket:
memset(creds->ticket.data,0, (unsigned) creds->ticket.length);
cleanticket:
krb5_xfree(creds->ticket.data);
cleanaddrs:
krb5_free_addresses(context, creds->addresses);
cleanblock:
krb5_xfree(creds->keyblock.contents);
cleanserver:
krb5_free_principal(context, creds->server);
cleanclient:
krb5_free_principal(context, creds->client);
return retval;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_end_seq_get(krb5_context context, krb5_ccache id, krb5_cc_cursor *cursor)
{
*cursor = 0L;
return KRB5_OK;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_generate_new (krb5_context context, krb5_ccache *id)
{
krb5_ccache lid;
char scratch[6+1];
lid = (krb5_ccache) malloc(sizeof(struct _krb5_ccache));
if (lid == NULL)
return KRB5_CC_NOMEM;
lid->ops = &krb5_mcc_ops;
(void) strcpy(scratch, "XXXXXX");
mktemp(scratch);
lid->data = (krb5_pointer) malloc(sizeof(krb5_mcc_data));
if (lid->data == NULL) {
krb5_xfree(lid);
return KRB5_CC_NOMEM;
}
((krb5_mcc_data *) lid->data)->name = (char *)
malloc(strlen(scratch) + 1);
if (((krb5_mcc_data *) lid->data)->name == NULL) {
krb5_xfree(((krb5_mcc_data *) lid->data));
krb5_xfree(lid);
return KRB5_CC_NOMEM;
}
((krb5_mcc_data *) lid->data)->link = NULL;
((krb5_mcc_data *) lid->data)->prin = NULL;
strcpy(((krb5_mcc_data *) lid->data)->name, scratch);
*id = lid;
#if 0
++krb5_cache_sessions;
#endif
((krb5_mcc_data *)lid->data)->next = mcc_head;
mcc_head = (krb5_mcc_data *)lid->data;
krb5_change_cache ();
return KRB5_OK;
}
const char * KRB5_CALLCONV
krb5_mcc_get_name (krb5_context context, krb5_ccache id)
{
return (char *) ((krb5_mcc_data *) id->data)->name;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_get_principal(krb5_context context, krb5_ccache id, krb5_principal *princ)
{
krb5_mcc_data *ptr = (krb5_mcc_data *)id->data;
if (!ptr->prin)
{
*princ = 0L;
return KRB5_FCC_NOFILE;
}
return krb5_copy_principal(context, ptr->prin, princ);
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_retrieve(krb5_context context, krb5_ccache id, krb5_flags whichfields, krb5_creds *mcreds, krb5_creds *creds)
{
return krb5_cc_retrieve_cred_default (context, id, whichfields,
mcreds, creds);
}
#define CHECK(ret) if (ret != KRB5_OK) return ret;
krb5_error_code KRB5_CALLCONV
krb5_mcc_store(krb5_context context, krb5_ccache id, krb5_creds *creds)
{
krb5_error_code ret;
krb5_mcc_cursor mcursor;
mcursor = (krb5_mcc_cursor)malloc(sizeof(krb5_mcc_link));
if (mcursor == NULL)
return KRB5_CC_NOMEM;
ret = krb5_copy_creds(context, creds, &mcursor->creds);
if (ret == KRB5_OK) {
mcursor->next = ((krb5_mcc_data *)id->data)->link;
((krb5_mcc_data *)id->data)->link = mcursor;
krb5_change_cache();
}
return ret;
}
krb5_error_code KRB5_CALLCONV
krb5_mcc_set_flags(krb5_context context, krb5_ccache id, krb5_flags flags)
{
return KRB5_OK;
}
#define NEED_WINDOWS
const krb5_cc_ops krb5_mcc_ops = {
0,
"MEMORY",
krb5_mcc_get_name,
krb5_mcc_resolve,
krb5_mcc_generate_new,
krb5_mcc_initialize,
krb5_mcc_destroy,
krb5_mcc_close,
krb5_mcc_store,
krb5_mcc_retrieve,
krb5_mcc_get_principal,
krb5_mcc_start_seq_get,
krb5_mcc_next_cred,
krb5_mcc_end_seq_get,
NULL,
krb5_mcc_set_flags,
};