1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/rcache/rc_base.c */
3 /*
4 * This file of the Kerberos V5 software is derived from public-domain code
5 * contributed by Daniel J. Bernstein, <brnstnd@acf10.nyu.edu>.
6 *
7 */
8
9 /*
10 * Base "glue" functions for the replay cache.
11 */
12
13 #include "k5-int.h"
14 #include "rc-int.h"
15 #include "k5-thread.h"
16 #include "../os/os-proto.h"
17
18 struct typelist {
19 const krb5_rc_ops *ops;
20 struct typelist *next;
21 };
22 static struct typelist none = { &k5_rc_none_ops, 0 };
23 static struct typelist file2 = { &k5_rc_file2_ops, &none };
24 static struct typelist dfl = { &k5_rc_dfl_ops, &file2 };
25 static struct typelist *typehead = &dfl;
26
27 krb5_error_code
k5_rc_default(krb5_context context,krb5_rcache * rc_out)28 k5_rc_default(krb5_context context, krb5_rcache *rc_out)
29 {
30 krb5_error_code ret;
31 const char *val;
32 char *profstr, *rcname;
33
34 *rc_out = NULL;
35
36 /* If KRB5RCACHENAME is set in the environment, resolve it. */
37 val = secure_getenv("KRB5RCACHENAME");
38 if (val != NULL)
39 return k5_rc_resolve(context, val, rc_out);
40
41 /* If KRB5RCACHETYPE is set in the environment, resolve it with an empty
42 * residual (primarily to support KRB5RCACHETYPE=none). */
43 val = secure_getenv("KRB5RCACHETYPE");
44 if (val != NULL) {
45 if (asprintf(&rcname, "%s:", val) < 0)
46 return ENOMEM;
47 ret = k5_rc_resolve(context, rcname, rc_out);
48 free(rcname);
49 return ret;
50 }
51
52 /* If [libdefaults] default_rcache_name is set, expand path tokens in the
53 * value and resolve it. */
54 if (profile_get_string(context->profile, KRB5_CONF_LIBDEFAULTS,
55 KRB5_CONF_DEFAULT_RCACHE_NAME, NULL, NULL,
56 &profstr) == 0 && profstr != NULL) {
57 ret = k5_expand_path_tokens(context, profstr, &rcname);
58 profile_release_string(profstr);
59 if (ret)
60 return ret;
61 ret = k5_rc_resolve(context, rcname, rc_out);
62 free(rcname);
63 return ret;
64 }
65
66 /* Resolve the default type with no residual. */
67 return k5_rc_resolve(context, "dfl:", rc_out);
68 }
69
70
71 krb5_error_code
k5_rc_resolve(krb5_context context,const char * name,krb5_rcache * rc_out)72 k5_rc_resolve(krb5_context context, const char *name, krb5_rcache *rc_out)
73 {
74 krb5_error_code ret;
75 struct typelist *t;
76 const char *sep;
77 size_t len;
78 krb5_rcache rc = NULL;
79
80 *rc_out = NULL;
81
82 sep = strchr(name, ':');
83 if (sep == NULL)
84 return KRB5_RC_PARSE;
85 len = sep - name;
86
87 for (t = typehead; t != NULL; t = t->next) {
88 if (strncmp(t->ops->type, name, len) == 0 && t->ops->type[len] == '\0')
89 break;
90 }
91 if (t == NULL)
92 return KRB5_RC_TYPE_NOTFOUND;
93
94 rc = k5alloc(sizeof(*rc), &ret);
95 if (rc == NULL)
96 goto error;
97 rc->name = strdup(name);
98 if (rc->name == NULL) {
99 ret = ENOMEM;
100 goto error;
101 }
102 ret = t->ops->resolve(context, sep + 1, &rc->data);
103 if (ret)
104 goto error;
105 rc->ops = t->ops;
106 rc->magic = KV5M_RCACHE;
107
108 *rc_out = rc;
109 return 0;
110
111 error:
112 if (rc != NULL) {
113 free(rc->name);
114 free(rc);
115 }
116 return ret;
117 }
118
119 void
k5_rc_close(krb5_context context,krb5_rcache rc)120 k5_rc_close(krb5_context context, krb5_rcache rc)
121 {
122 rc->ops->close(context, rc->data);
123 free(rc->name);
124 free(rc);
125 }
126
127 krb5_error_code
k5_rc_store(krb5_context context,krb5_rcache rc,const krb5_enc_data * authenticator)128 k5_rc_store(krb5_context context, krb5_rcache rc,
129 const krb5_enc_data *authenticator)
130 {
131 krb5_error_code ret;
132 krb5_data tag;
133
134 ret = k5_rc_tag_from_ciphertext(context, authenticator, &tag);
135 if (ret)
136 return ret;
137 return rc->ops->store(context, rc->data, &tag);
138 }
139
140 const char *
k5_rc_get_name(krb5_context context,krb5_rcache rc)141 k5_rc_get_name(krb5_context context, krb5_rcache rc)
142 {
143 return rc->name;
144 }
145
146 krb5_error_code
k5_rc_tag_from_ciphertext(krb5_context context,const krb5_enc_data * enc,krb5_data * tag_out)147 k5_rc_tag_from_ciphertext(krb5_context context, const krb5_enc_data *enc,
148 krb5_data *tag_out)
149 {
150 krb5_error_code ret;
151 const krb5_data *cdata = &enc->ciphertext;
152 unsigned int len;
153
154 *tag_out = empty_data();
155
156 ret = krb5_c_crypto_length(context, enc->enctype,
157 KRB5_CRYPTO_TYPE_CHECKSUM, &len);
158 if (ret)
159 return ret;
160 if (cdata->length < len)
161 return EINVAL;
162 *tag_out = make_data(cdata->data + cdata->length - len, len);
163 return 0;
164 }
165
166 /*
167 * Stub functions for former internal replay cache functions used by OpenSSL
168 * (despite the lack of prototypes) before the OpenSSL 1.1 release.
169 */
170
171 krb5_error_code krb5_rc_default(krb5_context, krb5_rcache *);
172 krb5_error_code KRB5_CALLCONV krb5_rc_destroy(krb5_context, krb5_rcache);
173 krb5_error_code KRB5_CALLCONV krb5_rc_get_lifespan(krb5_context, krb5_rcache,
174 krb5_deltat *);
175 krb5_error_code KRB5_CALLCONV krb5_rc_initialize(krb5_context, krb5_rcache,
176 krb5_deltat);
177
178 krb5_error_code
krb5_rc_default(krb5_context context,krb5_rcache * rc)179 krb5_rc_default(krb5_context context, krb5_rcache *rc)
180 {
181 return EINVAL;
182 }
183
184 krb5_error_code KRB5_CALLCONV
krb5_rc_destroy(krb5_context context,krb5_rcache rc)185 krb5_rc_destroy(krb5_context context, krb5_rcache rc)
186 {
187 return EINVAL;
188 }
189
190 krb5_error_code KRB5_CALLCONV
krb5_rc_get_lifespan(krb5_context context,krb5_rcache rc,krb5_deltat * span)191 krb5_rc_get_lifespan(krb5_context context, krb5_rcache rc, krb5_deltat *span)
192 {
193 return EINVAL;
194 }
195
196 krb5_error_code KRB5_CALLCONV
krb5_rc_initialize(krb5_context context,krb5_rcache rc,krb5_deltat span)197 krb5_rc_initialize(krb5_context context, krb5_rcache rc, krb5_deltat span)
198 {
199 return EINVAL;
200 }
201