1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * kdc/replay.c 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * Copyright 1991 by the Massachusetts Institute of Technology. 5*7c478bd9Sstevel@tonic-gate * All Rights Reserved. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 8*7c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 9*7c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 10*7c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 13*7c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 14*7c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 15*7c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 16*7c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 17*7c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 18*7c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 19*7c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 20*7c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 21*7c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 22*7c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 23*7c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 24*7c478bd9Sstevel@tonic-gate * or implied warranty. 25*7c478bd9Sstevel@tonic-gate * 26*7c478bd9Sstevel@tonic-gate * 27*7c478bd9Sstevel@tonic-gate * Replay lookaside cache for the KDC, to avoid extra work. 28*7c478bd9Sstevel@tonic-gate * 29*7c478bd9Sstevel@tonic-gate */ 30*7c478bd9Sstevel@tonic-gate 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include "k5-int.h" 35*7c478bd9Sstevel@tonic-gate #include "kdc_util.h" 36*7c478bd9Sstevel@tonic-gate #include "extern.h" 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate #ifndef NOCACHE 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate typedef struct _krb5_kdc_replay_ent { 41*7c478bd9Sstevel@tonic-gate struct _krb5_kdc_replay_ent *next; 42*7c478bd9Sstevel@tonic-gate int num_hits; 43*7c478bd9Sstevel@tonic-gate krb5_int32 timein; 44*7c478bd9Sstevel@tonic-gate time_t db_age; 45*7c478bd9Sstevel@tonic-gate krb5_data *req_packet; 46*7c478bd9Sstevel@tonic-gate krb5_data *reply_packet; 47*7c478bd9Sstevel@tonic-gate krb5_address *addr; /* XXX should these not be pointers? */ 48*7c478bd9Sstevel@tonic-gate } krb5_kdc_replay_ent; 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate static krb5_kdc_replay_ent root_ptr = {0}; 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate static int hits = 0; 53*7c478bd9Sstevel@tonic-gate static int calls = 0; 54*7c478bd9Sstevel@tonic-gate static int max_hits_per_entry = 0; 55*7c478bd9Sstevel@tonic-gate static int num_entries = 0; 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define STALE_TIME 2*60 /* two minutes */ 58*7c478bd9Sstevel@tonic-gate #define STALE(ptr) ((abs((ptr)->timein - timenow) >= STALE_TIME) || \ 59*7c478bd9Sstevel@tonic-gate ((ptr)->db_age != db_age)) 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #define MATCH(ptr) (((ptr)->req_packet->length == inpkt->length) && \ 62*7c478bd9Sstevel@tonic-gate !memcmp((ptr)->req_packet->data, inpkt->data, \ 63*7c478bd9Sstevel@tonic-gate inpkt->length) && \ 64*7c478bd9Sstevel@tonic-gate ((ptr)->addr->length == from->address->length) && \ 65*7c478bd9Sstevel@tonic-gate !memcmp((ptr)->addr->contents, \ 66*7c478bd9Sstevel@tonic-gate from->address->contents, \ 67*7c478bd9Sstevel@tonic-gate from->address->length)&& \ 68*7c478bd9Sstevel@tonic-gate ((ptr)->db_age == db_age)) 69*7c478bd9Sstevel@tonic-gate /* XXX 70*7c478bd9Sstevel@tonic-gate Todo: quench the size of the queue... 71*7c478bd9Sstevel@tonic-gate */ 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* return TRUE if outpkt is filled in with a packet to reply with, 74*7c478bd9Sstevel@tonic-gate FALSE if the caller should do the work */ 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate krb5_boolean 77*7c478bd9Sstevel@tonic-gate kdc_check_lookaside(inpkt, from, outpkt) 78*7c478bd9Sstevel@tonic-gate register krb5_data *inpkt; 79*7c478bd9Sstevel@tonic-gate register const krb5_fulladdr *from; 80*7c478bd9Sstevel@tonic-gate register krb5_data **outpkt; 81*7c478bd9Sstevel@tonic-gate { 82*7c478bd9Sstevel@tonic-gate krb5_int32 timenow; 83*7c478bd9Sstevel@tonic-gate register krb5_kdc_replay_ent *eptr, *last, *hold; 84*7c478bd9Sstevel@tonic-gate time_t db_age; 85*7c478bd9Sstevel@tonic-gate 86*7c478bd9Sstevel@tonic-gate if (krb5_timeofday(kdc_context, &timenow) || 87*7c478bd9Sstevel@tonic-gate krb5_db_get_age(kdc_context, 0, &db_age)) 88*7c478bd9Sstevel@tonic-gate return FALSE; 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate calls++; 91*7c478bd9Sstevel@tonic-gate 92*7c478bd9Sstevel@tonic-gate /* search for a replay entry in the queue, possibly removing 93*7c478bd9Sstevel@tonic-gate stale entries while we're here */ 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate if (root_ptr.next) { 96*7c478bd9Sstevel@tonic-gate for (last = &root_ptr, eptr = root_ptr.next; 97*7c478bd9Sstevel@tonic-gate eptr; 98*7c478bd9Sstevel@tonic-gate eptr = eptr->next) { 99*7c478bd9Sstevel@tonic-gate if (MATCH(eptr)) { 100*7c478bd9Sstevel@tonic-gate eptr->num_hits++; 101*7c478bd9Sstevel@tonic-gate hits++; 102*7c478bd9Sstevel@tonic-gate 103*7c478bd9Sstevel@tonic-gate if (krb5_copy_data(kdc_context, eptr->reply_packet, outpkt)) 104*7c478bd9Sstevel@tonic-gate return FALSE; 105*7c478bd9Sstevel@tonic-gate else 106*7c478bd9Sstevel@tonic-gate return TRUE; 107*7c478bd9Sstevel@tonic-gate /* return here, don't bother flushing even if it is stale. 108*7c478bd9Sstevel@tonic-gate if we just matched, we may get another retransmit... */ 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate if (STALE(eptr)) { 111*7c478bd9Sstevel@tonic-gate /* flush it and collect stats */ 112*7c478bd9Sstevel@tonic-gate max_hits_per_entry = max(max_hits_per_entry, eptr->num_hits); 113*7c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, eptr->req_packet); 114*7c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, eptr->reply_packet); 115*7c478bd9Sstevel@tonic-gate krb5_free_address(kdc_context, eptr->addr); 116*7c478bd9Sstevel@tonic-gate hold = eptr; 117*7c478bd9Sstevel@tonic-gate last->next = eptr->next; 118*7c478bd9Sstevel@tonic-gate eptr = last; 119*7c478bd9Sstevel@tonic-gate free(hold); 120*7c478bd9Sstevel@tonic-gate } else { 121*7c478bd9Sstevel@tonic-gate /* this isn't it, just move along */ 122*7c478bd9Sstevel@tonic-gate last = eptr; 123*7c478bd9Sstevel@tonic-gate } 124*7c478bd9Sstevel@tonic-gate } 125*7c478bd9Sstevel@tonic-gate } 126*7c478bd9Sstevel@tonic-gate return FALSE; 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* insert a request & reply into the lookaside queue. assumes it's not 130*7c478bd9Sstevel@tonic-gate already there, and can fail softly due to other weird errors. */ 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate void 133*7c478bd9Sstevel@tonic-gate kdc_insert_lookaside(inpkt, from, outpkt) 134*7c478bd9Sstevel@tonic-gate register krb5_data *inpkt; 135*7c478bd9Sstevel@tonic-gate register const krb5_fulladdr *from; 136*7c478bd9Sstevel@tonic-gate register krb5_data *outpkt; 137*7c478bd9Sstevel@tonic-gate { 138*7c478bd9Sstevel@tonic-gate register krb5_kdc_replay_ent *eptr; 139*7c478bd9Sstevel@tonic-gate krb5_int32 timenow; 140*7c478bd9Sstevel@tonic-gate time_t db_age; 141*7c478bd9Sstevel@tonic-gate 142*7c478bd9Sstevel@tonic-gate if (krb5_timeofday(kdc_context, &timenow) || 143*7c478bd9Sstevel@tonic-gate krb5_db_get_age(kdc_context, 0, &db_age)) 144*7c478bd9Sstevel@tonic-gate return; 145*7c478bd9Sstevel@tonic-gate 146*7c478bd9Sstevel@tonic-gate /* this is a new entry */ 147*7c478bd9Sstevel@tonic-gate eptr = (krb5_kdc_replay_ent *)calloc(1, sizeof(*eptr)); 148*7c478bd9Sstevel@tonic-gate if (!eptr) 149*7c478bd9Sstevel@tonic-gate return; 150*7c478bd9Sstevel@tonic-gate eptr->timein = timenow; 151*7c478bd9Sstevel@tonic-gate eptr->db_age = db_age; 152*7c478bd9Sstevel@tonic-gate /* 153*7c478bd9Sstevel@tonic-gate * This is going to hurt a lot malloc()-wise due to the need to 154*7c478bd9Sstevel@tonic-gate * allocate memory for the krb5_data and krb5_address elements. 155*7c478bd9Sstevel@tonic-gate * ARGH! 156*7c478bd9Sstevel@tonic-gate */ 157*7c478bd9Sstevel@tonic-gate if (krb5_copy_data(kdc_context, inpkt, &eptr->req_packet)) { 158*7c478bd9Sstevel@tonic-gate free(eptr); 159*7c478bd9Sstevel@tonic-gate return; 160*7c478bd9Sstevel@tonic-gate } 161*7c478bd9Sstevel@tonic-gate if (krb5_copy_data(kdc_context, outpkt, &eptr->reply_packet)) { 162*7c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, eptr->req_packet); 163*7c478bd9Sstevel@tonic-gate free(eptr); 164*7c478bd9Sstevel@tonic-gate return; 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate if (krb5_copy_addr(kdc_context, from->address, &eptr->addr)) { 167*7c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, eptr->req_packet); 168*7c478bd9Sstevel@tonic-gate krb5_free_data(kdc_context, eptr->reply_packet); 169*7c478bd9Sstevel@tonic-gate free(eptr); 170*7c478bd9Sstevel@tonic-gate return; 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate eptr->next = root_ptr.next; 173*7c478bd9Sstevel@tonic-gate root_ptr.next = eptr; 174*7c478bd9Sstevel@tonic-gate num_entries++; 175*7c478bd9Sstevel@tonic-gate return; 176*7c478bd9Sstevel@tonic-gate } 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate #endif /* NOCACHE */ 179