1 /* $NetBSD: purge.c,v 1.2 2017/01/28 21:31:44 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2004 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "ktutil_locl.h" 37 38 __RCSID("$NetBSD: purge.c,v 1.2 2017/01/28 21:31:44 christos Exp $"); 39 40 /* 41 * keep track of the highest version for every principal. 42 */ 43 44 struct e { 45 krb5_principal principal; 46 int max_vno; 47 time_t timestamp; 48 struct e *next; 49 }; 50 51 static struct e * 52 get_entry (krb5_principal princ, struct e *head) 53 { 54 struct e *e; 55 56 for (e = head; e != NULL; e = e->next) 57 if (krb5_principal_compare (context, princ, e->principal)) 58 return e; 59 return NULL; 60 } 61 62 static void 63 add_entry (krb5_principal princ, int vno, time_t timestamp, struct e **head) 64 { 65 krb5_error_code ret; 66 struct e *e; 67 68 e = get_entry (princ, *head); 69 if (e != NULL) { 70 if(e->max_vno < vno) { 71 e->max_vno = vno; 72 e->timestamp = timestamp; 73 } 74 return; 75 } 76 e = malloc (sizeof (*e)); 77 if (e == NULL) 78 krb5_errx (context, 1, "malloc: out of memory"); 79 ret = krb5_copy_principal (context, princ, &e->principal); 80 if (ret) 81 krb5_err (context, 1, ret, "krb5_copy_principal"); 82 e->max_vno = vno; 83 e->timestamp = timestamp; 84 e->next = *head; 85 *head = e; 86 } 87 88 static void 89 delete_list (struct e *head) 90 { 91 while (head != NULL) { 92 struct e *next = head->next; 93 krb5_free_principal (context, head->principal); 94 free (head); 95 head = next; 96 } 97 } 98 99 /* 100 * Remove all entries that have newer versions and that are older 101 * than `age' 102 */ 103 104 int 105 kt_purge(struct purge_options *opt, int argc, char **argv) 106 { 107 krb5_error_code ret = 0; 108 krb5_kt_cursor cursor; 109 krb5_keytab keytab; 110 krb5_keytab_entry entry; 111 int age; 112 struct e *head = NULL; 113 time_t judgement_day; 114 115 age = parse_time(opt->age_string, "s"); 116 if(age < 0) { 117 krb5_warnx(context, "unparasable time `%s'", opt->age_string); 118 return 1; 119 } 120 121 if((keytab = ktutil_open_keytab()) == NULL) 122 return 1; 123 124 ret = krb5_kt_start_seq_get(context, keytab, &cursor); 125 if(ret){ 126 krb5_warn(context, ret, "%s", keytab_string); 127 goto out; 128 } 129 130 while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { 131 add_entry (entry.principal, entry.vno, entry.timestamp, &head); 132 krb5_kt_free_entry(context, &entry); 133 } 134 krb5_kt_end_seq_get(context, keytab, &cursor); 135 136 judgement_day = time (NULL); 137 138 ret = krb5_kt_start_seq_get(context, keytab, &cursor); 139 if(ret){ 140 krb5_warn(context, ret, "%s", keytab_string); 141 goto out; 142 } 143 144 while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) { 145 struct e *e = get_entry (entry.principal, head); 146 147 if (e == NULL) { 148 krb5_warnx (context, "ignoring extra entry"); 149 continue; 150 } 151 152 if (entry.vno < e->max_vno 153 && judgement_day - e->timestamp > age) { 154 if (verbose_flag) { 155 char *name_str; 156 157 krb5_unparse_name (context, entry.principal, &name_str); 158 printf ("removing %s vno %d\n", name_str, entry.vno); 159 free (name_str); 160 } 161 ret = krb5_kt_remove_entry (context, keytab, &entry); 162 if (ret) 163 krb5_warn (context, ret, "remove"); 164 } 165 krb5_kt_free_entry(context, &entry); 166 } 167 ret = krb5_kt_end_seq_get(context, keytab, &cursor); 168 169 delete_list (head); 170 171 out: 172 krb5_kt_close (context, keytab); 173 return ret != 0; 174 } 175