155682Smarkm/*
272445Sassar * Copyright (c) 1997-2001 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
3572445Sassar#include <vis.h>
3655682Smarkm
37178825SdfrRCSID("$Id: replay.c 17047 2006-04-10 17:13:49Z lha $");
3872445Sassar
3955682Smarkmstruct krb5_rcache_data {
4055682Smarkm    char *name;
4155682Smarkm};
4255682Smarkm
43178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
4455682Smarkmkrb5_rc_resolve(krb5_context context,
4555682Smarkm		krb5_rcache id,
4655682Smarkm		const char *name)
4755682Smarkm{
4855682Smarkm    id->name = strdup(name);
4978527Sassar    if(id->name == NULL) {
5078527Sassar	krb5_set_error_string (context, "malloc: out of memory");
5155682Smarkm	return KRB5_RC_MALLOC;
5278527Sassar    }
5355682Smarkm    return 0;
5455682Smarkm}
5555682Smarkm
56178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
5755682Smarkmkrb5_rc_resolve_type(krb5_context context,
5855682Smarkm		     krb5_rcache *id,
5955682Smarkm		     const char *type)
6055682Smarkm{
61178825Sdfr    *id = NULL;
6278527Sassar    if(strcmp(type, "FILE")) {
6378527Sassar	krb5_set_error_string (context, "replay cache type %s not supported",
6478527Sassar			       type);
6555682Smarkm	return KRB5_RC_TYPE_NOTFOUND;
6678527Sassar    }
6755682Smarkm    *id = calloc(1, sizeof(**id));
6878527Sassar    if(*id == NULL) {
6978527Sassar	krb5_set_error_string (context, "malloc: out of memory");
7055682Smarkm	return KRB5_RC_MALLOC;
7178527Sassar    }
7255682Smarkm    return 0;
7355682Smarkm}
7455682Smarkm
75178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
7655682Smarkmkrb5_rc_resolve_full(krb5_context context,
7755682Smarkm		     krb5_rcache *id,
7855682Smarkm		     const char *string_name)
7955682Smarkm{
8055682Smarkm    krb5_error_code ret;
81178825Sdfr
82178825Sdfr    *id = NULL;
83178825Sdfr
8478527Sassar    if(strncmp(string_name, "FILE:", 5)) {
8578527Sassar	krb5_set_error_string (context, "replay cache type %s not supported",
8678527Sassar			       string_name);
8755682Smarkm	return KRB5_RC_TYPE_NOTFOUND;
8878527Sassar    }
8955682Smarkm    ret = krb5_rc_resolve_type(context, id, "FILE");
9055682Smarkm    if(ret)
9155682Smarkm	return ret;
9255682Smarkm    ret = krb5_rc_resolve(context, *id, string_name + 5);
93178825Sdfr    if (ret) {
94178825Sdfr	krb5_rc_close(context, *id);
95178825Sdfr	*id = NULL;
96178825Sdfr    }
9755682Smarkm    return ret;
9855682Smarkm}
9955682Smarkm
100178825Sdfrconst char* KRB5_LIB_FUNCTION
10155682Smarkmkrb5_rc_default_name(krb5_context context)
10255682Smarkm{
10355682Smarkm    return "FILE:/var/run/default_rcache";
10455682Smarkm}
10555682Smarkm
106178825Sdfrconst char* KRB5_LIB_FUNCTION
10772445Sassarkrb5_rc_default_type(krb5_context context)
10872445Sassar{
10972445Sassar    return "FILE";
11072445Sassar}
11172445Sassar
112178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
11355682Smarkmkrb5_rc_default(krb5_context context,
11455682Smarkm		krb5_rcache *id)
11555682Smarkm{
11655682Smarkm    return krb5_rc_resolve_full(context, id, krb5_rc_default_name(context));
11755682Smarkm}
11855682Smarkm
11955682Smarkmstruct rc_entry{
12055682Smarkm    time_t stamp;
12155682Smarkm    unsigned char data[16];
12255682Smarkm};
12355682Smarkm
124178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
12555682Smarkmkrb5_rc_initialize(krb5_context context,
12655682Smarkm		   krb5_rcache id,
12755682Smarkm		   krb5_deltat auth_lifespan)
12855682Smarkm{
12955682Smarkm    FILE *f = fopen(id->name, "w");
13055682Smarkm    struct rc_entry tmp;
13178527Sassar    int ret;
13278527Sassar
13378527Sassar    if(f == NULL) {
13478527Sassar	ret = errno;
13578527Sassar	krb5_set_error_string (context, "open(%s): %s", id->name,
13678527Sassar			       strerror(ret));
13778527Sassar	return ret;
13878527Sassar    }
13955682Smarkm    tmp.stamp = auth_lifespan;
14055682Smarkm    fwrite(&tmp, 1, sizeof(tmp), f);
14155682Smarkm    fclose(f);
14255682Smarkm    return 0;
14355682Smarkm}
14455682Smarkm
145178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
14655682Smarkmkrb5_rc_recover(krb5_context context,
14755682Smarkm		krb5_rcache id)
14855682Smarkm{
14955682Smarkm    return 0;
15055682Smarkm}
15155682Smarkm
152178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
15355682Smarkmkrb5_rc_destroy(krb5_context context,
15455682Smarkm		krb5_rcache id)
15555682Smarkm{
15678527Sassar    int ret;
15778527Sassar
15878527Sassar    if(remove(id->name) < 0) {
15978527Sassar	ret = errno;
16078527Sassar	krb5_set_error_string (context, "remove(%s): %s", id->name,
16178527Sassar			       strerror(ret));
16278527Sassar	return ret;
16378527Sassar    }
16455682Smarkm    return krb5_rc_close(context, id);
16555682Smarkm}
16655682Smarkm
167178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
16855682Smarkmkrb5_rc_close(krb5_context context,
16955682Smarkm	      krb5_rcache id)
17055682Smarkm{
17155682Smarkm    free(id->name);
17255682Smarkm    free(id);
17355682Smarkm    return 0;
17455682Smarkm}
17555682Smarkm
17655682Smarkmstatic void
17755682Smarkmchecksum_authenticator(Authenticator *auth, void *data)
17855682Smarkm{
17957416Smarkm    MD5_CTX md5;
18055682Smarkm    int i;
18157416Smarkm
18272445Sassar    MD5_Init (&md5);
18372445Sassar    MD5_Update (&md5, auth->crealm, strlen(auth->crealm));
18455682Smarkm    for(i = 0; i < auth->cname.name_string.len; i++)
18572445Sassar	MD5_Update(&md5, auth->cname.name_string.val[i],
18672445Sassar		   strlen(auth->cname.name_string.val[i]));
18772445Sassar    MD5_Update (&md5, &auth->ctime, sizeof(auth->ctime));
18872445Sassar    MD5_Update (&md5, &auth->cusec, sizeof(auth->cusec));
18972445Sassar    MD5_Final (data, &md5);
19055682Smarkm}
19155682Smarkm
192178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
19355682Smarkmkrb5_rc_store(krb5_context context,
19455682Smarkm	      krb5_rcache id,
19572445Sassar	      krb5_donot_replay *rep)
19655682Smarkm{
19755682Smarkm    struct rc_entry ent, tmp;
19855682Smarkm    time_t t;
19955682Smarkm    FILE *f;
20078527Sassar    int ret;
20178527Sassar
20255682Smarkm    ent.stamp = time(NULL);
20355682Smarkm    checksum_authenticator(rep, ent.data);
20455682Smarkm    f = fopen(id->name, "r");
20578527Sassar    if(f == NULL) {
20678527Sassar	ret = errno;
20778527Sassar	krb5_set_error_string (context, "open(%s): %s", id->name,
20878527Sassar			       strerror(ret));
20978527Sassar	return ret;
21078527Sassar    }
21155682Smarkm    fread(&tmp, sizeof(ent), 1, f);
21255682Smarkm    t = ent.stamp - tmp.stamp;
21355682Smarkm    while(fread(&tmp, sizeof(ent), 1, f)){
21455682Smarkm	if(tmp.stamp < t)
21555682Smarkm	    continue;
21655682Smarkm	if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){
21755682Smarkm	    fclose(f);
21878527Sassar	    krb5_clear_error_string (context);
21955682Smarkm	    return KRB5_RC_REPLAY;
22055682Smarkm	}
22155682Smarkm    }
22255682Smarkm    if(ferror(f)){
22378527Sassar	ret = errno;
22455682Smarkm	fclose(f);
22578527Sassar	krb5_set_error_string (context, "%s: %s", id->name, strerror(ret));
22678527Sassar	return ret;
22755682Smarkm    }
22855682Smarkm    fclose(f);
22955682Smarkm    f = fopen(id->name, "a");
23078527Sassar    if(f == NULL) {
23178527Sassar	krb5_set_error_string (context, "open(%s): %s", id->name,
23278527Sassar			       strerror(errno));
23355682Smarkm	return KRB5_RC_IO_UNKNOWN;
23478527Sassar    }
23555682Smarkm    fwrite(&ent, 1, sizeof(ent), f);
23655682Smarkm    fclose(f);
23755682Smarkm    return 0;
23855682Smarkm}
23955682Smarkm
240178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
24155682Smarkmkrb5_rc_expunge(krb5_context context,
24255682Smarkm		krb5_rcache id)
24355682Smarkm{
24455682Smarkm    return 0;
24555682Smarkm}
24655682Smarkm
247178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
24855682Smarkmkrb5_rc_get_lifespan(krb5_context context,
24955682Smarkm		     krb5_rcache id,
25055682Smarkm		     krb5_deltat *auth_lifespan)
25155682Smarkm{
25255682Smarkm    FILE *f = fopen(id->name, "r");
25355682Smarkm    int r;
25455682Smarkm    struct rc_entry ent;
25555682Smarkm    r = fread(&ent, sizeof(ent), 1, f);
25655682Smarkm    fclose(f);
25755682Smarkm    if(r){
25855682Smarkm	*auth_lifespan = ent.stamp;
25955682Smarkm	return 0;
26055682Smarkm    }
26178527Sassar    krb5_clear_error_string (context);
26255682Smarkm    return KRB5_RC_IO_UNKNOWN;
26355682Smarkm}
26472445Sassar
265178825Sdfrconst char* KRB5_LIB_FUNCTION
26655682Smarkmkrb5_rc_get_name(krb5_context context,
26755682Smarkm		 krb5_rcache id)
26855682Smarkm{
26955682Smarkm    return id->name;
27055682Smarkm}
27155682Smarkm
272178825Sdfrconst char* KRB5_LIB_FUNCTION
27355682Smarkmkrb5_rc_get_type(krb5_context context,
27455682Smarkm		 krb5_rcache id)
27555682Smarkm{
27655682Smarkm    return "FILE";
27755682Smarkm}
27855682Smarkm
279178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
28072445Sassarkrb5_get_server_rcache(krb5_context context,
28172445Sassar		       const krb5_data *piece,
28272445Sassar		       krb5_rcache *id)
28372445Sassar{
28472445Sassar    krb5_rcache rcache;
28572445Sassar    krb5_error_code ret;
28672445Sassar
28772445Sassar    char *tmp = malloc(4 * piece->length + 1);
28872445Sassar    char *name;
28978527Sassar
29078527Sassar    if(tmp == NULL) {
29178527Sassar	krb5_set_error_string (context, "malloc: out of memory");
29272445Sassar	return ENOMEM;
29378527Sassar    }
29472445Sassar    strvisx(tmp, piece->data, piece->length, VIS_WHITE | VIS_OCTAL);
29572445Sassar#ifdef HAVE_GETEUID
29690926Snectar    asprintf(&name, "FILE:rc_%s_%u", tmp, (unsigned)geteuid());
29772445Sassar#else
29872445Sassar    asprintf(&name, "FILE:rc_%s", tmp);
29972445Sassar#endif
30072445Sassar    free(tmp);
30178527Sassar    if(name == NULL) {
30278527Sassar	krb5_set_error_string (context, "malloc: out of memory");
30372445Sassar	return ENOMEM;
30478527Sassar    }
30572445Sassar
30672445Sassar    ret = krb5_rc_resolve_full(context, &rcache, name);
30772445Sassar    free(name);
30872445Sassar    if(ret)
30972445Sassar	return ret;
31072445Sassar    *id = rcache;
31172445Sassar    return ret;
31272445Sassar}
313