root/source4/heimdal/lib/krb5/mcache.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mcc_get_name
  2. mcc_alloc
  3. mcc_resolve
  4. mcc_gen_new
  5. mcc_initialize
  6. mcc_close_internal
  7. mcc_close
  8. mcc_destroy
  9. mcc_store_cred
  10. mcc_get_principal
  11. mcc_get_first
  12. mcc_get_next
  13. mcc_end_get
  14. mcc_remove_cred
  15. mcc_set_flags
  16. mcc_get_cache_first
  17. mcc_get_cache_next
  18. mcc_end_cache_get
  19. mcc_move
  20. mcc_default_name
  21. mcc_lastchange

   1 /*
   2  * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan
   3  * (Royal Institute of Technology, Stockholm, Sweden).
   4  * All rights reserved.
   5  *
   6  * Redistribution and use in source and binary forms, with or without
   7  * modification, are permitted provided that the following conditions
   8  * are met:
   9  *
  10  * 1. Redistributions of source code must retain the above copyright
  11  *    notice, this list of conditions and the following disclaimer.
  12  *
  13  * 2. Redistributions in binary form must reproduce the above copyright
  14  *    notice, this list of conditions and the following disclaimer in the
  15  *    documentation and/or other materials provided with the distribution.
  16  *
  17  * 3. Neither the name of the Institute nor the names of its contributors
  18  *    may be used to endorse or promote products derived from this software
  19  *    without specific prior written permission.
  20  *
  21  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
  22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
  25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31  * SUCH DAMAGE.
  32  */
  33 
  34 #include "krb5_locl.h"
  35 
  36 RCSID("$Id$");
  37 
  38 typedef struct krb5_mcache {
  39     char *name;
  40     unsigned int refcnt;
  41     int dead;
  42     krb5_principal primary_principal;
  43     struct link {
  44         krb5_creds cred;
  45         struct link *next;
  46     } *creds;
  47     struct krb5_mcache *next;
  48     time_t mtime;
  49 } krb5_mcache;
  50 
  51 static HEIMDAL_MUTEX mcc_mutex = HEIMDAL_MUTEX_INITIALIZER;
  52 static struct krb5_mcache *mcc_head;
  53 
  54 #define MCACHE(X)       ((krb5_mcache *)(X)->data.data)
  55 
  56 #define MISDEAD(X)      ((X)->dead)
  57 
  58 static const char*
  59 mcc_get_name(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
  60              krb5_ccache id)
  61 {
  62     return MCACHE(id)->name;
  63 }
  64 
  65 static krb5_mcache *
  66 mcc_alloc(const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  67 {
  68     krb5_mcache *m, *m_c;
  69 
  70     ALLOC(m, 1);
  71     if(m == NULL)
  72         return NULL;
  73     if(name == NULL)
  74         asprintf(&m->name, "%p", m);
  75     else
  76         m->name = strdup(name);
  77     if(m->name == NULL) {
  78         free(m);
  79         return NULL;
  80     }
  81     /* check for dups first */
  82     HEIMDAL_MUTEX_lock(&mcc_mutex);
  83     for (m_c = mcc_head; m_c != NULL; m_c = m_c->next)
  84         if (strcmp(m->name, m_c->name) == 0)
  85             break;
  86     if (m_c) {
  87         free(m->name);
  88         free(m);
  89         HEIMDAL_MUTEX_unlock(&mcc_mutex);
  90         return NULL;
  91     }
  92 
  93     m->dead = 0;
  94     m->refcnt = 1;
  95     m->primary_principal = NULL;
  96     m->creds = NULL;
  97     m->mtime = time(NULL);
  98     m->next = mcc_head;
  99     mcc_head = m;
 100     HEIMDAL_MUTEX_unlock(&mcc_mutex);
 101     return m;
 102 }
 103 
 104 static krb5_error_code
 105 mcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
     /* [<][>][^][v][top][bottom][index][help] */
 106 {
 107     krb5_mcache *m;
 108 
 109     HEIMDAL_MUTEX_lock(&mcc_mutex);
 110     for (m = mcc_head; m != NULL; m = m->next)
 111         if (strcmp(m->name, res) == 0)
 112             break;
 113     HEIMDAL_MUTEX_unlock(&mcc_mutex);
 114 
 115     if (m != NULL) {
 116         m->refcnt++;
 117         (*id)->data.data = m;
 118         (*id)->data.length = sizeof(*m);
 119         return 0;
 120     }
 121 
 122     m = mcc_alloc(res);
 123     if (m == NULL) {
 124         krb5_set_error_message(context, KRB5_CC_NOMEM,
 125                                N_("malloc: out of memory", ""));
 126         return KRB5_CC_NOMEM;
 127     }
 128 
 129     (*id)->data.data = m;
 130     (*id)->data.length = sizeof(*m);
 131 
 132     return 0;
 133 }
 134 
 135 
 136 static krb5_error_code
 137 mcc_gen_new(krb5_context context, krb5_ccache *id)
     /* [<][>][^][v][top][bottom][index][help] */
 138 {
 139     krb5_mcache *m;
 140 
 141     m = mcc_alloc(NULL);
 142 
 143     if (m == NULL) {
 144         krb5_set_error_message(context, KRB5_CC_NOMEM,
 145                                N_("malloc: out of memory", ""));
 146         return KRB5_CC_NOMEM;
 147     }
 148 
 149     (*id)->data.data = m;
 150     (*id)->data.length = sizeof(*m);
 151 
 152     return 0;
 153 }
 154 
 155 static krb5_error_code
 156 mcc_initialize(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 157                krb5_ccache id,
 158                krb5_principal primary_principal)
 159 {
 160     krb5_mcache *m = MCACHE(id);
 161     m->dead = 0;
 162     m->mtime = time(NULL);
 163     return krb5_copy_principal (context,
 164                                 primary_principal,
 165                                 &m->primary_principal);
 166 }
 167 
 168 static int
 169 mcc_close_internal(krb5_mcache *m)
     /* [<][>][^][v][top][bottom][index][help] */
 170 {
 171     if (--m->refcnt != 0)
 172         return 0;
 173 
 174     if (MISDEAD(m)) {
 175         free (m->name);
 176         return 1;
 177     }
 178     return 0;
 179 }
 180 
 181 static krb5_error_code
 182 mcc_close(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 183           krb5_ccache id)
 184 {
 185     if (mcc_close_internal(MCACHE(id)))
 186         krb5_data_free(&id->data);
 187     return 0;
 188 }
 189 
 190 static krb5_error_code
 191 mcc_destroy(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 192             krb5_ccache id)
 193 {
 194     krb5_mcache **n, *m = MCACHE(id);
 195     struct link *l;
 196 
 197     if (m->refcnt == 0)
 198         krb5_abortx(context, "mcc_destroy: refcnt already 0");
 199 
 200     if (!MISDEAD(m)) {
 201         /* if this is an active mcache, remove it from the linked
 202            list, and free all data */
 203         HEIMDAL_MUTEX_lock(&mcc_mutex);
 204         for(n = &mcc_head; n && *n; n = &(*n)->next) {
 205             if(m == *n) {
 206                 *n = m->next;
 207                 break;
 208             }
 209         }
 210         HEIMDAL_MUTEX_unlock(&mcc_mutex);
 211         if (m->primary_principal != NULL) {
 212             krb5_free_principal (context, m->primary_principal);
 213             m->primary_principal = NULL;
 214         }
 215         m->dead = 1;
 216 
 217         l = m->creds;
 218         while (l != NULL) {
 219             struct link *old;
 220         
 221             krb5_free_cred_contents (context, &l->cred);
 222             old = l;
 223             l = l->next;
 224             free (old);
 225         }
 226         m->creds = NULL;
 227     }
 228     return 0;
 229 }
 230 
 231 static krb5_error_code
 232 mcc_store_cred(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 233                krb5_ccache id,
 234                krb5_creds *creds)
 235 {
 236     krb5_mcache *m = MCACHE(id);
 237     krb5_error_code ret;
 238     struct link *l;
 239 
 240     if (MISDEAD(m))
 241         return ENOENT;
 242 
 243     l = malloc (sizeof(*l));
 244     if (l == NULL) {
 245         krb5_set_error_message(context, KRB5_CC_NOMEM,
 246                                N_("malloc: out of memory", ""));
 247         return KRB5_CC_NOMEM;
 248     }
 249     l->next = m->creds;
 250     m->creds = l;
 251     memset (&l->cred, 0, sizeof(l->cred));
 252     ret = krb5_copy_creds_contents (context, creds, &l->cred);
 253     if (ret) {
 254         m->creds = l->next;
 255         free (l);
 256         return ret;
 257     }
 258     m->mtime = time(NULL);
 259     return 0;
 260 }
 261 
 262 static krb5_error_code
 263 mcc_get_principal(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 264                   krb5_ccache id,
 265                   krb5_principal *principal)
 266 {
 267     krb5_mcache *m = MCACHE(id);
 268 
 269     if (MISDEAD(m) || m->primary_principal == NULL)
 270         return ENOENT;
 271     return krb5_copy_principal (context,
 272                                 m->primary_principal,
 273                                 principal);
 274 }
 275 
 276 static krb5_error_code
 277 mcc_get_first (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 278                krb5_ccache id,
 279                krb5_cc_cursor *cursor)
 280 {
 281     krb5_mcache *m = MCACHE(id);
 282 
 283     if (MISDEAD(m))
 284         return ENOENT;
 285 
 286     *cursor = m->creds;
 287     return 0;
 288 }
 289 
 290 static krb5_error_code
 291 mcc_get_next (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 292               krb5_ccache id,
 293               krb5_cc_cursor *cursor,
 294               krb5_creds *creds)
 295 {
 296     krb5_mcache *m = MCACHE(id);
 297     struct link *l;
 298 
 299     if (MISDEAD(m))
 300         return ENOENT;
 301 
 302     l = *cursor;
 303     if (l != NULL) {
 304         *cursor = l->next;
 305         return krb5_copy_creds_contents (context,
 306                                          &l->cred,
 307                                          creds);
 308     } else
 309         return KRB5_CC_END;
 310 }
 311 
 312 static krb5_error_code
 313 mcc_end_get (krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 314              krb5_ccache id,
 315              krb5_cc_cursor *cursor)
 316 {
 317     return 0;
 318 }
 319 
 320 static krb5_error_code
 321 mcc_remove_cred(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 322                  krb5_ccache id,
 323                  krb5_flags which,
 324                  krb5_creds *mcreds)
 325 {
 326     krb5_mcache *m = MCACHE(id);
 327     struct link **q, *p;
 328     for(q = &m->creds, p = *q; p; p = *q) {
 329         if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
 330             *q = p->next;
 331             krb5_free_cred_contents(context, &p->cred);
 332             free(p);
 333             m->mtime = time(NULL);
 334         } else
 335             q = &p->next;
 336     }
 337     return 0;
 338 }
 339 
 340 static krb5_error_code
 341 mcc_set_flags(krb5_context context,
     /* [<][>][^][v][top][bottom][index][help] */
 342               krb5_ccache id,
 343               krb5_flags flags)
 344 {
 345     return 0; /* XXX */
 346 }
 347                 
 348 struct mcache_iter {
 349     krb5_mcache *cache;
 350 };
 351 
 352 static krb5_error_code
 353 mcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
     /* [<][>][^][v][top][bottom][index][help] */
 354 {
 355     struct mcache_iter *iter;
 356 
 357     iter = calloc(1, sizeof(*iter));
 358     if (iter == NULL) {
 359         krb5_set_error_message(context, ENOMEM,
 360                                N_("malloc: out of memory", ""));
 361         return ENOMEM;
 362     }
 363 
 364     HEIMDAL_MUTEX_lock(&mcc_mutex);
 365     iter->cache = mcc_head;
 366     if (iter->cache)
 367         iter->cache->refcnt++;
 368     HEIMDAL_MUTEX_unlock(&mcc_mutex);
 369 
 370     *cursor = iter;
 371     return 0;
 372 }
 373 
 374 static krb5_error_code
 375 mcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
     /* [<][>][^][v][top][bottom][index][help] */
 376 {
 377     struct mcache_iter *iter = cursor;
 378     krb5_error_code ret;
 379     krb5_mcache *m;
 380 
 381     if (iter->cache == NULL)
 382         return KRB5_CC_END;
 383 
 384     HEIMDAL_MUTEX_lock(&mcc_mutex);
 385     m = iter->cache;
 386     if (m->next)
 387         m->next->refcnt++;
 388     iter->cache = m->next;
 389     HEIMDAL_MUTEX_unlock(&mcc_mutex);
 390 
 391     ret = _krb5_cc_allocate(context, &krb5_mcc_ops, id);
 392     if (ret)
 393         return ret;
 394 
 395     (*id)->data.data = m;
 396     (*id)->data.length = sizeof(*m);
 397 
 398     return 0;
 399 }
 400 
 401 static krb5_error_code
 402 mcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
     /* [<][>][^][v][top][bottom][index][help] */
 403 {
 404     struct mcache_iter *iter = cursor;
 405 
 406     if (iter->cache)
 407         mcc_close_internal(iter->cache);
 408     iter->cache = NULL;
 409     free(iter);
 410     return 0;
 411 }
 412 
 413 static krb5_error_code
 414 mcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
     /* [<][>][^][v][top][bottom][index][help] */
 415 {
 416     krb5_mcache *mfrom = MCACHE(from), *mto = MCACHE(to);
 417     struct link *creds;
 418     krb5_principal principal;
 419     krb5_mcache **n;
 420 
 421     HEIMDAL_MUTEX_lock(&mcc_mutex);
 422 
 423     /* drop the from cache from the linked list to avoid lookups */
 424     for(n = &mcc_head; n && *n; n = &(*n)->next) {
 425         if(mfrom == *n) {
 426             *n = mfrom->next;
 427             break;
 428         }
 429     }
 430 
 431     /* swap creds */
 432     creds = mto->creds;
 433     mto->creds = mfrom->creds;
 434     mfrom->creds = creds;
 435     /* swap principal */
 436     principal = mto->primary_principal;
 437     mto->primary_principal = mfrom->primary_principal;
 438     mfrom->primary_principal = principal;
 439 
 440     mto->mtime = mfrom->mtime = time(NULL);
 441 
 442     HEIMDAL_MUTEX_unlock(&mcc_mutex);
 443     mcc_destroy(context, from);
 444 
 445     return 0;
 446 }
 447 
 448 static krb5_error_code
 449 mcc_default_name(krb5_context context, char **str)
     /* [<][>][^][v][top][bottom][index][help] */
 450 {
 451     *str = strdup("MEMORY:");
 452     if (*str == NULL) {
 453         krb5_set_error_message(context, ENOMEM,
 454                                N_("malloc: out of memory", ""));
 455         return ENOMEM;
 456     }
 457     return 0;
 458 }
 459 
 460 static krb5_error_code
 461 mcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
     /* [<][>][^][v][top][bottom][index][help] */
 462 {
 463     *mtime = MCACHE(id)->mtime;
 464     return 0;
 465 }
 466 
 467 
 468 /**
 469  * Variable containing the MEMORY based credential cache implemention.
 470  *
 471  * @ingroup krb5_ccache
 472  */
 473 
 474 KRB5_LIB_VARIABLE const krb5_cc_ops krb5_mcc_ops = {
 475     KRB5_CC_OPS_VERSION,
 476     "MEMORY",
 477     mcc_get_name,
 478     mcc_resolve,
 479     mcc_gen_new,
 480     mcc_initialize,
 481     mcc_destroy,
 482     mcc_close,
 483     mcc_store_cred,
 484     NULL, /* mcc_retrieve */
 485     mcc_get_principal,
 486     mcc_get_first,
 487     mcc_get_next,
 488     mcc_end_get,
 489     mcc_remove_cred,
 490     mcc_set_flags,
 491     NULL,
 492     mcc_get_cache_first,
 493     mcc_get_cache_next,
 494     mcc_end_cache_get,
 495     mcc_move,
 496     mcc_default_name,
 497     NULL,
 498     mcc_lastchange
 499 };

/* [<][>][^][v][top][bottom][index][help] */