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