1 /* 2 * kdc/replay.c 3 * 4 * Copyright 1991 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 * Replay lookaside cache for the KDC, to avoid extra work. 28 * 29 */ 30 31 32 33 #include "k5-int.h" 34 #include "kdc_util.h" 35 #include "extern.h" 36 37 #ifndef NOCACHE 38 39 typedef struct _krb5_kdc_replay_ent { 40 struct _krb5_kdc_replay_ent *next; 41 int num_hits; 42 krb5_int32 timein; 43 time_t db_age; 44 krb5_data *req_packet; 45 krb5_data *reply_packet; 46 } krb5_kdc_replay_ent; 47 48 static krb5_kdc_replay_ent root_ptr = {0}; 49 50 static int hits = 0; 51 static int calls = 0; 52 static int max_hits_per_entry = 0; 53 static int num_entries = 0; 54 55 #define STALE_TIME 2*60 /* two minutes */ 56 #define STALE(ptr) ((abs((ptr)->timein - timenow) >= STALE_TIME) || \ 57 ((ptr)->db_age != db_age)) 58 59 #define MATCH(ptr) (((ptr)->req_packet->length == inpkt->length) && \ 60 !memcmp((ptr)->req_packet->data, inpkt->data, \ 61 inpkt->length) && \ 62 ((ptr)->db_age == db_age)) 63 /* XXX 64 Todo: quench the size of the queue... 65 */ 66 67 /* return TRUE if outpkt is filled in with a packet to reply with, 68 FALSE if the caller should do the work */ 69 70 krb5_boolean 71 kdc_check_lookaside(krb5_data *inpkt, krb5_data **outpkt) 72 { 73 krb5_int32 timenow; 74 register krb5_kdc_replay_ent *eptr, *last, *hold; 75 time_t db_age; 76 77 if (krb5_timeofday(kdc_context, &timenow) || 78 krb5_db_get_age(kdc_context, 0, &db_age)) 79 return FALSE; 80 81 calls++; 82 83 /* search for a replay entry in the queue, possibly removing 84 stale entries while we're here */ 85 86 if (root_ptr.next) { 87 for (last = &root_ptr, eptr = root_ptr.next; 88 eptr; 89 eptr = eptr->next) { 90 if (MATCH(eptr)) { 91 eptr->num_hits++; 92 hits++; 93 94 if (krb5_copy_data(kdc_context, eptr->reply_packet, outpkt)) 95 return FALSE; 96 else 97 return TRUE; 98 /* return here, don't bother flushing even if it is stale. 99 if we just matched, we may get another retransmit... */ 100 } 101 if (STALE(eptr)) { 102 /* flush it and collect stats */ 103 max_hits_per_entry = max(max_hits_per_entry, eptr->num_hits); 104 krb5_free_data(kdc_context, eptr->req_packet); 105 krb5_free_data(kdc_context, eptr->reply_packet); 106 hold = eptr; 107 last->next = eptr->next; 108 eptr = last; 109 free(hold); 110 } else { 111 /* this isn't it, just move along */ 112 last = eptr; 113 } 114 } 115 } 116 return FALSE; 117 } 118 119 /* insert a request & reply into the lookaside queue. assumes it's not 120 already there, and can fail softly due to other weird errors. */ 121 122 void 123 kdc_insert_lookaside(krb5_data *inpkt, krb5_data *outpkt) 124 { 125 register krb5_kdc_replay_ent *eptr; 126 krb5_int32 timenow; 127 time_t db_age; 128 129 if (krb5_timeofday(kdc_context, &timenow) || 130 krb5_db_get_age(kdc_context, 0, &db_age)) 131 return; 132 133 /* this is a new entry */ 134 eptr = (krb5_kdc_replay_ent *)calloc(1, sizeof(*eptr)); 135 if (!eptr) 136 return; 137 eptr->timein = timenow; 138 eptr->db_age = db_age; 139 /* 140 * This is going to hurt a lot malloc()-wise due to the need to 141 * allocate memory for the krb5_data and krb5_address elements. 142 * ARGH! 143 */ 144 if (krb5_copy_data(kdc_context, inpkt, &eptr->req_packet)) { 145 free(eptr); 146 return; 147 } 148 if (krb5_copy_data(kdc_context, outpkt, &eptr->reply_packet)) { 149 krb5_free_data(kdc_context, eptr->req_packet); 150 free(eptr); 151 return; 152 } 153 eptr->next = root_ptr.next; 154 root_ptr.next = eptr; 155 num_entries++; 156 return; 157 } 158 159 /* frees memory associated with the lookaside queue for memory profiling */ 160 void 161 kdc_free_lookaside(krb5_context kcontext) 162 { 163 register krb5_kdc_replay_ent *eptr, *last, *hold; 164 if (root_ptr.next) { 165 for (last = &root_ptr, eptr = root_ptr.next; 166 eptr; eptr = eptr->next) { 167 krb5_free_data(kcontext, eptr->req_packet); 168 krb5_free_data(kcontext, eptr->reply_packet); 169 hold = eptr; 170 last->next = eptr->next; 171 eptr = last; 172 free(hold); 173 } 174 } 175 } 176 177 #endif /* NOCACHE */ 178