155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2004 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "ktutil_locl.h"
3555682Smarkm
36233294SstasRCSID("$Id$");
3755682Smarkm
3855682Smarkm/*
3955682Smarkm * keep track of the highest version for every principal.
4055682Smarkm */
4155682Smarkm
4255682Smarkmstruct e {
4355682Smarkm    krb5_principal principal;
4455682Smarkm    int max_vno;
45178825Sdfr    time_t timestamp;
4655682Smarkm    struct e *next;
4755682Smarkm};
4855682Smarkm
4955682Smarkmstatic struct e *
5055682Smarkmget_entry (krb5_principal princ, struct e *head)
5155682Smarkm{
5255682Smarkm    struct e *e;
5355682Smarkm
5455682Smarkm    for (e = head; e != NULL; e = e->next)
5555682Smarkm	if (krb5_principal_compare (context, princ, e->principal))
5655682Smarkm	    return e;
5755682Smarkm    return NULL;
5855682Smarkm}
5955682Smarkm
6055682Smarkmstatic void
61178825Sdfradd_entry (krb5_principal princ, int vno, time_t timestamp, struct e **head)
6255682Smarkm{
6355682Smarkm    krb5_error_code ret;
6455682Smarkm    struct e *e;
6555682Smarkm
6655682Smarkm    e = get_entry (princ, *head);
6755682Smarkm    if (e != NULL) {
68178825Sdfr	if(e->max_vno < vno) {
69178825Sdfr	    e->max_vno = vno;
70178825Sdfr	    e->timestamp = timestamp;
71178825Sdfr	}
7255682Smarkm	return;
7355682Smarkm    }
7455682Smarkm    e = malloc (sizeof (*e));
7555682Smarkm    if (e == NULL)
7655682Smarkm	krb5_errx (context, 1, "malloc: out of memory");
7755682Smarkm    ret = krb5_copy_principal (context, princ, &e->principal);
7855682Smarkm    if (ret)
7955682Smarkm	krb5_err (context, 1, ret, "krb5_copy_principal");
8055682Smarkm    e->max_vno = vno;
81178825Sdfr    e->timestamp = timestamp;
8255682Smarkm    e->next    = *head;
8355682Smarkm    *head      = e;
8455682Smarkm}
8555682Smarkm
8655682Smarkmstatic void
8755682Smarkmdelete_list (struct e *head)
8855682Smarkm{
8955682Smarkm    while (head != NULL) {
9055682Smarkm	struct e *next = head->next;
9155682Smarkm	krb5_free_principal (context, head->principal);
9255682Smarkm	free (head);
9355682Smarkm	head = next;
9455682Smarkm    }
9555682Smarkm}
9655682Smarkm
9755682Smarkm/*
9855682Smarkm * Remove all entries that have newer versions and that are older
9955682Smarkm * than `age'
10055682Smarkm */
10155682Smarkm
10255682Smarkmint
103178825Sdfrkt_purge(struct purge_options *opt, int argc, char **argv)
10455682Smarkm{
10578527Sassar    krb5_error_code ret = 0;
10655682Smarkm    krb5_kt_cursor cursor;
10778527Sassar    krb5_keytab keytab;
10855682Smarkm    krb5_keytab_entry entry;
10972445Sassar    int age;
11055682Smarkm    struct e *head = NULL;
11155682Smarkm    time_t judgement_day;
11255682Smarkm
113178825Sdfr    age = parse_time(opt->age_string, "s");
11472445Sassar    if(age < 0) {
115178825Sdfr	krb5_warnx(context, "unparasable time `%s'", opt->age_string);
11678527Sassar	return 1;
11772445Sassar    }
11872445Sassar
11990926Snectar    if((keytab = ktutil_open_keytab()) == NULL)
12078527Sassar	return 1;
12178527Sassar
12255682Smarkm    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
12355682Smarkm    if(ret){
124178825Sdfr	krb5_warn(context, ret, "%s", keytab_string);
12578527Sassar	goto out;
12655682Smarkm    }
12755682Smarkm
128233294Sstas    while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) {
129178825Sdfr	add_entry (entry.principal, entry.vno, entry.timestamp, &head);
13055682Smarkm	krb5_kt_free_entry(context, &entry);
13155682Smarkm    }
132233294Sstas    krb5_kt_end_seq_get(context, keytab, &cursor);
13355682Smarkm
13455682Smarkm    judgement_day = time (NULL);
13555682Smarkm
13655682Smarkm    ret = krb5_kt_start_seq_get(context, keytab, &cursor);
13755682Smarkm    if(ret){
138178825Sdfr	krb5_warn(context, ret, "%s", keytab_string);
13978527Sassar	goto out;
14055682Smarkm    }
14155682Smarkm
142233294Sstas    while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0) {
14355682Smarkm	struct e *e = get_entry (entry.principal, head);
14455682Smarkm
14555682Smarkm	if (e == NULL) {
14655682Smarkm	    krb5_warnx (context, "ignoring extra entry");
14755682Smarkm	    continue;
14855682Smarkm	}
14955682Smarkm
15055682Smarkm	if (entry.vno < e->max_vno
151178825Sdfr	    && judgement_day - e->timestamp > age) {
15255682Smarkm	    if (verbose_flag) {
15355682Smarkm		char *name_str;
15455682Smarkm
15555682Smarkm		krb5_unparse_name (context, entry.principal, &name_str);
15655682Smarkm		printf ("removing %s vno %d\n", name_str, entry.vno);
15755682Smarkm		free (name_str);
15855682Smarkm	    }
15955682Smarkm	    ret = krb5_kt_remove_entry (context, keytab, &entry);
16055682Smarkm	    if (ret)
16155682Smarkm		krb5_warn (context, ret, "remove");
16255682Smarkm	}
16355682Smarkm	krb5_kt_free_entry(context, &entry);
16455682Smarkm    }
16555682Smarkm    ret = krb5_kt_end_seq_get(context, keytab, &cursor);
16655682Smarkm
16755682Smarkm    delete_list (head);
16855682Smarkm
16978527Sassar out:
17078527Sassar    krb5_kt_close (context, keytab);
17178527Sassar    return ret != 0;
17255682Smarkm}
173