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 "ktutil_locl.h" 35 36 RCSID("$Id$"); 37 38 /* 39 * keep track of the highest version for every principal. 40 */ 41 42 struct e { 43 krb5_principal principal; 44 int max_vno; 45 time_t timestamp; 46 struct e *next; 47 }; 48 49 static struct e * 50 get_entry (krb5_principal princ, struct e *head) 51 { 52 struct e *e; 53 54 for (e = head; e != NULL; e = e->next) 55 if (krb5_principal_compare (context, princ, e->principal)) 56 return e; 57 return NULL; 58 } 59 60 static void 61 add_entry (krb5_principal princ, int vno, time_t timestamp, struct e **head) 62 { 63 krb5_error_code ret; 64 struct e *e; 65 66 e = get_entry (princ, *head); 67 if (e != NULL) { 68 if(e->max_vno < vno) { 69 e->max_vno = vno; 70 e->timestamp = timestamp; 71 } 72 return; 73 } 74 e = malloc (sizeof (*e)); 75 if (e == NULL) 76 krb5_errx (context, 1, "malloc: out of memory"); 77 ret = krb5_copy_principal (context, princ, &e->principal); 78 if (ret) 79 krb5_err (context, 1, ret, "krb5_copy_principal"); 80 e->max_vno = vno; 81 e->timestamp = timestamp; 82 e->next = *head; 83 *head = e; 84 } 85 86 static void 87 delete_list (struct e *head) 88 { 89 while (head != NULL) { 90 struct e *next = head->next; 91 krb5_free_principal (context, head->principal); 92 free (head); 93 head = next; 94 } 95 } 96 97 /* 98 * Remove all entries that have newer versions and that are older 99 * than `age' 100 */ 101 102 int 103 kt_purge(struct purge_options *opt, int argc, char **argv) 104 { 105 krb5_error_code ret = 0; 106 krb5_kt_cursor cursor; 107 krb5_keytab keytab; 108 krb5_keytab_entry entry; 109 int age; 110 struct e *head = NULL; 111 time_t judgement_day; 112 113 age = parse_time(opt->age_string, "s"); 114 if(age < 0) { 115 krb5_warnx(context, "unparasable time `%s'", opt->age_string); 116 return 1; 117 } 118 119 if((keytab = ktutil_open_keytab()) == NULL) 120 return 1; 121 122 ret = krb5_kt_start_seq_get(context, keytab, &cursor); 123 if(ret){ 124 krb5_warn(context, ret, "%s", keytab_string); 125 goto out; 126 } 127 128 while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { 129 add_entry (entry.principal, entry.vno, entry.timestamp, &head); 130 krb5_kt_free_entry(context, &entry); 131 } 132 krb5_kt_end_seq_get(context, keytab, &cursor); 133 134 judgement_day = time (NULL); 135 136 ret = krb5_kt_start_seq_get(context, keytab, &cursor); 137 if(ret){ 138 krb5_warn(context, ret, "%s", keytab_string); 139 goto out; 140 } 141 142 while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { 143 struct e *e = get_entry (entry.principal, head); 144 145 if (e == NULL) { 146 krb5_warnx (context, "ignoring extra entry"); 147 continue; 148 } 149 150 if (entry.vno < e->max_vno 151 && judgement_day - e->timestamp > age) { 152 if (verbose_flag) { 153 char *name_str; 154 155 krb5_unparse_name (context, entry.principal, &name_str); 156 printf ("removing %s vno %d\n", name_str, entry.vno); 157 free (name_str); 158 } 159 ret = krb5_kt_remove_entry (context, keytab, &entry); 160 if (ret) 161 krb5_warn (context, ret, "remove"); 162 } 163 krb5_kt_free_entry(context, &entry); 164 } 165 ret = krb5_kt_end_seq_get(context, keytab, &cursor); 166 167 delete_list (head); 168 169 out: 170 krb5_kt_close (context, keytab); 171 return ret != 0; 172 } 173