155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2001 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 "krb5_locl.h"
3572445Sassar#include <vis.h>
3655682Smarkm
3755682Smarkmstruct krb5_rcache_data {
3855682Smarkm    char *name;
3955682Smarkm};
4055682Smarkm
41233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
4255682Smarkmkrb5_rc_resolve(krb5_context context,
4355682Smarkm		krb5_rcache id,
4455682Smarkm		const char *name)
4555682Smarkm{
4655682Smarkm    id->name = strdup(name);
4778527Sassar    if(id->name == NULL) {
48233294Sstas	krb5_set_error_message(context, KRB5_RC_MALLOC,
49233294Sstas			       N_("malloc: out of memory", ""));
5055682Smarkm	return KRB5_RC_MALLOC;
5178527Sassar    }
5255682Smarkm    return 0;
5355682Smarkm}
5455682Smarkm
55233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
5655682Smarkmkrb5_rc_resolve_type(krb5_context context,
5755682Smarkm		     krb5_rcache *id,
5855682Smarkm		     const char *type)
5955682Smarkm{
60178825Sdfr    *id = NULL;
6178527Sassar    if(strcmp(type, "FILE")) {
62233294Sstas	krb5_set_error_message (context, KRB5_RC_TYPE_NOTFOUND,
63233294Sstas				N_("replay cache type %s not supported", ""),
64233294Sstas				type);
6555682Smarkm	return KRB5_RC_TYPE_NOTFOUND;
6678527Sassar    }
6755682Smarkm    *id = calloc(1, sizeof(**id));
6878527Sassar    if(*id == NULL) {
69233294Sstas	krb5_set_error_message(context, KRB5_RC_MALLOC,
70233294Sstas			       N_("malloc: out of memory", ""));
7155682Smarkm	return KRB5_RC_MALLOC;
7278527Sassar    }
7355682Smarkm    return 0;
7455682Smarkm}
7555682Smarkm
76233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
7755682Smarkmkrb5_rc_resolve_full(krb5_context context,
7855682Smarkm		     krb5_rcache *id,
7955682Smarkm		     const char *string_name)
8055682Smarkm{
8155682Smarkm    krb5_error_code ret;
82178825Sdfr
83178825Sdfr    *id = NULL;
84178825Sdfr
8578527Sassar    if(strncmp(string_name, "FILE:", 5)) {
86233294Sstas	krb5_set_error_message(context, KRB5_RC_TYPE_NOTFOUND,
87233294Sstas			       N_("replay cache type %s not supported", ""),
8878527Sassar			       string_name);
8955682Smarkm	return KRB5_RC_TYPE_NOTFOUND;
9078527Sassar    }
9155682Smarkm    ret = krb5_rc_resolve_type(context, id, "FILE");
9255682Smarkm    if(ret)
9355682Smarkm	return ret;
9455682Smarkm    ret = krb5_rc_resolve(context, *id, string_name + 5);
95178825Sdfr    if (ret) {
96178825Sdfr	krb5_rc_close(context, *id);
97178825Sdfr	*id = NULL;
98178825Sdfr    }
9955682Smarkm    return ret;
10055682Smarkm}
10155682Smarkm
102233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
10355682Smarkmkrb5_rc_default_name(krb5_context context)
10455682Smarkm{
10555682Smarkm    return "FILE:/var/run/default_rcache";
10655682Smarkm}
10755682Smarkm
108233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
10972445Sassarkrb5_rc_default_type(krb5_context context)
11072445Sassar{
11172445Sassar    return "FILE";
11272445Sassar}
11372445Sassar
114233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
11555682Smarkmkrb5_rc_default(krb5_context context,
11655682Smarkm		krb5_rcache *id)
11755682Smarkm{
11855682Smarkm    return krb5_rc_resolve_full(context, id, krb5_rc_default_name(context));
11955682Smarkm}
12055682Smarkm
12155682Smarkmstruct rc_entry{
12255682Smarkm    time_t stamp;
12355682Smarkm    unsigned char data[16];
12455682Smarkm};
12555682Smarkm
126233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
12755682Smarkmkrb5_rc_initialize(krb5_context context,
12855682Smarkm		   krb5_rcache id,
12955682Smarkm		   krb5_deltat auth_lifespan)
13055682Smarkm{
13155682Smarkm    FILE *f = fopen(id->name, "w");
13255682Smarkm    struct rc_entry tmp;
13378527Sassar    int ret;
13478527Sassar
13578527Sassar    if(f == NULL) {
136233294Sstas	char buf[128];
13778527Sassar	ret = errno;
138233294Sstas	rk_strerror_r(ret, buf, sizeof(buf));
139233294Sstas	krb5_set_error_message(context, ret, "open(%s): %s", id->name, buf);
14078527Sassar	return ret;
14178527Sassar    }
14255682Smarkm    tmp.stamp = auth_lifespan;
14355682Smarkm    fwrite(&tmp, 1, sizeof(tmp), f);
14455682Smarkm    fclose(f);
14555682Smarkm    return 0;
14655682Smarkm}
14755682Smarkm
148233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
14955682Smarkmkrb5_rc_recover(krb5_context context,
15055682Smarkm		krb5_rcache id)
15155682Smarkm{
15255682Smarkm    return 0;
15355682Smarkm}
15455682Smarkm
155233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
15655682Smarkmkrb5_rc_destroy(krb5_context context,
15755682Smarkm		krb5_rcache id)
15855682Smarkm{
15978527Sassar    int ret;
16078527Sassar
16178527Sassar    if(remove(id->name) < 0) {
162233294Sstas	char buf[128];
16378527Sassar	ret = errno;
164233294Sstas	rk_strerror_r(ret, buf, sizeof(buf));
165233294Sstas	krb5_set_error_message(context, ret, "remove(%s): %s", id->name, buf);
16678527Sassar	return ret;
16778527Sassar    }
16855682Smarkm    return krb5_rc_close(context, id);
16955682Smarkm}
17055682Smarkm
171233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
17255682Smarkmkrb5_rc_close(krb5_context context,
17355682Smarkm	      krb5_rcache id)
17455682Smarkm{
17555682Smarkm    free(id->name);
17655682Smarkm    free(id);
17755682Smarkm    return 0;
17855682Smarkm}
17955682Smarkm
18055682Smarkmstatic void
18155682Smarkmchecksum_authenticator(Authenticator *auth, void *data)
18255682Smarkm{
183233294Sstas    EVP_MD_CTX *m = EVP_MD_CTX_create();
184233294Sstas    unsigned i;
18557416Smarkm
186233294Sstas    EVP_DigestInit_ex(m, EVP_md5(), NULL);
187233294Sstas
188233294Sstas    EVP_DigestUpdate(m, auth->crealm, strlen(auth->crealm));
18955682Smarkm    for(i = 0; i < auth->cname.name_string.len; i++)
190233294Sstas	EVP_DigestUpdate(m, auth->cname.name_string.val[i],
19172445Sassar		   strlen(auth->cname.name_string.val[i]));
192233294Sstas    EVP_DigestUpdate(m, &auth->ctime, sizeof(auth->ctime));
193233294Sstas    EVP_DigestUpdate(m, &auth->cusec, sizeof(auth->cusec));
194233294Sstas
195233294Sstas    EVP_DigestFinal_ex(m, data, NULL);
196233294Sstas    EVP_MD_CTX_destroy(m);
19755682Smarkm}
19855682Smarkm
199233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
20055682Smarkmkrb5_rc_store(krb5_context context,
20155682Smarkm	      krb5_rcache id,
20272445Sassar	      krb5_donot_replay *rep)
20355682Smarkm{
20455682Smarkm    struct rc_entry ent, tmp;
20555682Smarkm    time_t t;
20655682Smarkm    FILE *f;
20778527Sassar    int ret;
20878527Sassar
20955682Smarkm    ent.stamp = time(NULL);
21055682Smarkm    checksum_authenticator(rep, ent.data);
21155682Smarkm    f = fopen(id->name, "r");
21278527Sassar    if(f == NULL) {
213233294Sstas	char buf[128];
21478527Sassar	ret = errno;
215233294Sstas	rk_strerror_r(ret, buf, sizeof(buf));
216233294Sstas	krb5_set_error_message(context, ret, "open(%s): %s", id->name, buf);
21778527Sassar	return ret;
21878527Sassar    }
219233294Sstas    rk_cloexec_file(f);
22055682Smarkm    fread(&tmp, sizeof(ent), 1, f);
22155682Smarkm    t = ent.stamp - tmp.stamp;
22255682Smarkm    while(fread(&tmp, sizeof(ent), 1, f)){
22355682Smarkm	if(tmp.stamp < t)
22455682Smarkm	    continue;
22555682Smarkm	if(memcmp(tmp.data, ent.data, sizeof(ent.data)) == 0){
22655682Smarkm	    fclose(f);
227233294Sstas	    krb5_clear_error_message (context);
22855682Smarkm	    return KRB5_RC_REPLAY;
22955682Smarkm	}
23055682Smarkm    }
23155682Smarkm    if(ferror(f)){
232233294Sstas	char buf[128];
23378527Sassar	ret = errno;
23455682Smarkm	fclose(f);
235233294Sstas	rk_strerror_r(ret, buf, sizeof(buf));
236233294Sstas	krb5_set_error_message(context, ret, "%s: %s",
237233294Sstas			       id->name, buf);
23878527Sassar	return ret;
23955682Smarkm    }
24055682Smarkm    fclose(f);
24155682Smarkm    f = fopen(id->name, "a");
24278527Sassar    if(f == NULL) {
243233294Sstas	char buf[128];
244233294Sstas	rk_strerror_r(errno, buf, sizeof(buf));
245233294Sstas	krb5_set_error_message(context, KRB5_RC_IO_UNKNOWN,
246233294Sstas			       "open(%s): %s", id->name, buf);
24755682Smarkm	return KRB5_RC_IO_UNKNOWN;
24878527Sassar    }
24955682Smarkm    fwrite(&ent, 1, sizeof(ent), f);
25055682Smarkm    fclose(f);
25155682Smarkm    return 0;
25255682Smarkm}
25355682Smarkm
254233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
25555682Smarkmkrb5_rc_expunge(krb5_context context,
25655682Smarkm		krb5_rcache id)
25755682Smarkm{
25855682Smarkm    return 0;
25955682Smarkm}
26055682Smarkm
261233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
26255682Smarkmkrb5_rc_get_lifespan(krb5_context context,
26355682Smarkm		     krb5_rcache id,
26455682Smarkm		     krb5_deltat *auth_lifespan)
26555682Smarkm{
26655682Smarkm    FILE *f = fopen(id->name, "r");
26755682Smarkm    int r;
26855682Smarkm    struct rc_entry ent;
26955682Smarkm    r = fread(&ent, sizeof(ent), 1, f);
27055682Smarkm    fclose(f);
27155682Smarkm    if(r){
27255682Smarkm	*auth_lifespan = ent.stamp;
27355682Smarkm	return 0;
27455682Smarkm    }
275233294Sstas    krb5_clear_error_message (context);
27655682Smarkm    return KRB5_RC_IO_UNKNOWN;
27755682Smarkm}
27872445Sassar
279233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
28055682Smarkmkrb5_rc_get_name(krb5_context context,
28155682Smarkm		 krb5_rcache id)
28255682Smarkm{
28355682Smarkm    return id->name;
28455682Smarkm}
285233294Sstas
286233294SstasKRB5_LIB_FUNCTION const char* KRB5_LIB_CALL
28755682Smarkmkrb5_rc_get_type(krb5_context context,
28855682Smarkm		 krb5_rcache id)
28955682Smarkm{
29055682Smarkm    return "FILE";
29155682Smarkm}
292233294Sstas
293233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
294233294Sstaskrb5_get_server_rcache(krb5_context context,
295233294Sstas		       const krb5_data *piece,
29672445Sassar		       krb5_rcache *id)
29772445Sassar{
29872445Sassar    krb5_rcache rcache;
29972445Sassar    krb5_error_code ret;
30072445Sassar
30172445Sassar    char *tmp = malloc(4 * piece->length + 1);
30272445Sassar    char *name;
30378527Sassar
30478527Sassar    if(tmp == NULL) {
305233294Sstas	krb5_set_error_message(context, ENOMEM,
306233294Sstas			       N_("malloc: out of memory", ""));
30772445Sassar	return ENOMEM;
30878527Sassar    }
30972445Sassar    strvisx(tmp, piece->data, piece->length, VIS_WHITE | VIS_OCTAL);
31072445Sassar#ifdef HAVE_GETEUID
311233294Sstas    ret = asprintf(&name, "FILE:rc_%s_%u", tmp, (unsigned)geteuid());
31272445Sassar#else
313233294Sstas    ret = asprintf(&name, "FILE:rc_%s", tmp);
31472445Sassar#endif
31572445Sassar    free(tmp);
316233294Sstas    if(ret < 0 || name == NULL) {
317233294Sstas	krb5_set_error_message(context, ENOMEM,
318233294Sstas			       N_("malloc: out of memory", ""));
31972445Sassar	return ENOMEM;
32078527Sassar    }
32172445Sassar
32272445Sassar    ret = krb5_rc_resolve_full(context, &rcache, name);
32372445Sassar    free(name);
32472445Sassar    if(ret)
32572445Sassar	return ret;
32672445Sassar    *id = rcache;
32772445Sassar    return ret;
32872445Sassar}
329