1*1c9681d1Schristos /*	$NetBSD: dcache.c,v 1.2 2017/01/28 21:31:49 christos Exp $	*/
2e0895134Schristos 
3e0895134Schristos /*
4e0895134Schristos  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
5e0895134Schristos  * (Royal Institute of Technology, Stockholm, Sweden).
6e0895134Schristos  * All rights reserved.
7e0895134Schristos  *
8e0895134Schristos  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9e0895134Schristos  *
10e0895134Schristos  * Redistribution and use in source and binary forms, with or without
11e0895134Schristos  * modification, are permitted provided that the following conditions
12e0895134Schristos  * are met:
13e0895134Schristos  *
14e0895134Schristos  * 1. Redistributions of source code must retain the above copyright
15e0895134Schristos  *    notice, this list of conditions and the following disclaimer.
16e0895134Schristos  *
17e0895134Schristos  * 2. Redistributions in binary form must reproduce the above copyright
18e0895134Schristos  *    notice, this list of conditions and the following disclaimer in the
19e0895134Schristos  *    documentation and/or other materials provided with the distribution.
20e0895134Schristos  *
21e0895134Schristos  * 3. Neither the name of the Institute nor the names of its contributors
22e0895134Schristos  *    may be used to endorse or promote products derived from this software
23e0895134Schristos  *    without specific prior written permission.
24e0895134Schristos  *
25e0895134Schristos  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26e0895134Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27e0895134Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28e0895134Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29e0895134Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30e0895134Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31e0895134Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32e0895134Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33e0895134Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34e0895134Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35e0895134Schristos  * SUCH DAMAGE.
36e0895134Schristos  */
37e0895134Schristos 
38e0895134Schristos #include "krb5_locl.h"
39e0895134Schristos 
40e0895134Schristos typedef struct krb5_dcache{
41e0895134Schristos     krb5_ccache fcache;
42e0895134Schristos     char *dir;
43e0895134Schristos     char *name;
44e0895134Schristos } krb5_dcache;
45e0895134Schristos 
46e0895134Schristos #define DCACHE(X) ((krb5_dcache*)(X)->data.data)
47e0895134Schristos #define D2FCACHE(X) ((X)->fcache)
48e0895134Schristos 
49e0895134Schristos static krb5_error_code KRB5_CALLCONV dcc_close(krb5_context, krb5_ccache);
50e0895134Schristos static krb5_error_code KRB5_CALLCONV dcc_get_default_name(krb5_context, char **);
51e0895134Schristos 
52e0895134Schristos 
53e0895134Schristos static char *
primary_create(krb5_dcache * dc)54e0895134Schristos primary_create(krb5_dcache *dc)
55e0895134Schristos {
56e0895134Schristos     char *primary = NULL;
57e0895134Schristos 
58e0895134Schristos     asprintf(&primary, "%s/primary", dc->dir);
59e0895134Schristos     if (primary == NULL)
60e0895134Schristos 	return NULL;
61e0895134Schristos 
62e0895134Schristos     return primary;
63e0895134Schristos }
64e0895134Schristos 
65e0895134Schristos static int
is_filename_cacheish(const char * name)66e0895134Schristos is_filename_cacheish(const char *name)
67e0895134Schristos {
68e0895134Schristos     return strncmp(name, "tkt", 3) == 0;
69e0895134Schristos 
70e0895134Schristos }
71e0895134Schristos 
72e0895134Schristos static krb5_error_code
set_default_cache(krb5_context context,krb5_dcache * dc,const char * residual)73e0895134Schristos set_default_cache(krb5_context context, krb5_dcache *dc, const char *residual)
74e0895134Schristos {
75e0895134Schristos     char *path = NULL, *primary = NULL;
76e0895134Schristos     krb5_error_code ret;
77e0895134Schristos     struct iovec iov[2];
78e0895134Schristos     size_t len;
79e0895134Schristos     int fd = -1;
80e0895134Schristos 
81e0895134Schristos     if (!is_filename_cacheish(residual)) {
82e0895134Schristos 	krb5_set_error_message(context, KRB5_CC_FORMAT,
83e0895134Schristos 			       "name %s is not a cache (doesn't start with tkt)", residual);
84e0895134Schristos 	return KRB5_CC_FORMAT;
85e0895134Schristos     }
86e0895134Schristos 
87e0895134Schristos     asprintf(&path, "%s/primary-XXXXXX", dc->dir);
88e0895134Schristos     if (path == NULL)
89e0895134Schristos 	return krb5_enomem(context);
90e0895134Schristos 
91e0895134Schristos     fd = mkstemp(path);
92e0895134Schristos     if (fd < 0) {
93e0895134Schristos 	ret = errno;
94e0895134Schristos 	goto out;
95e0895134Schristos     }
96e0895134Schristos     rk_cloexec(fd);
97e0895134Schristos #ifndef _WIN32
98e0895134Schristos     if (fchmod(fd, S_IRUSR | S_IWUSR) < 0) {
99e0895134Schristos 	ret = errno;
100e0895134Schristos 	goto out;
101e0895134Schristos     }
102e0895134Schristos #endif
103e0895134Schristos     len = strlen(residual);
104e0895134Schristos 
105e0895134Schristos     iov[0].iov_base = rk_UNCONST(residual);
106e0895134Schristos     iov[0].iov_len = len;
107e0895134Schristos     iov[1].iov_base = "\n";
108e0895134Schristos     iov[1].iov_len = 1;
109e0895134Schristos 
110e0895134Schristos     if (writev(fd, iov, sizeof(iov)/sizeof(iov[0])) != len + 1) {
111e0895134Schristos 	ret = errno;
112e0895134Schristos 	goto out;
113e0895134Schristos     }
114e0895134Schristos 
115e0895134Schristos     primary = primary_create(dc);
116e0895134Schristos     if (primary == NULL) {
117e0895134Schristos 	ret = krb5_enomem(context);
118e0895134Schristos 	goto out;
119e0895134Schristos     }
120e0895134Schristos 
121e0895134Schristos     if (rename(path, primary) < 0) {
122e0895134Schristos 	ret = errno;
123e0895134Schristos 	goto out;
124e0895134Schristos     }
125e0895134Schristos 
126e0895134Schristos     close(fd);
127e0895134Schristos     fd = -1;
128e0895134Schristos 
129e0895134Schristos     ret = 0;
130e0895134Schristos  out:
131e0895134Schristos     if (fd >= 0) {
132e0895134Schristos 	(void)unlink(path);
133e0895134Schristos 	close(fd);
134e0895134Schristos     }
135e0895134Schristos     if (path)
136e0895134Schristos 	free(path);
137e0895134Schristos     if (primary)
138e0895134Schristos 	free(primary);
139e0895134Schristos 
140e0895134Schristos     return ret;
141e0895134Schristos }
142e0895134Schristos 
143e0895134Schristos static krb5_error_code
get_default_cache(krb5_context context,krb5_dcache * dc,char ** residual)144e0895134Schristos get_default_cache(krb5_context context, krb5_dcache *dc, char **residual)
145e0895134Schristos {
146e0895134Schristos     krb5_error_code ret;
147e0895134Schristos     char buf[MAXPATHLEN];
148e0895134Schristos     char *primary;
149e0895134Schristos     FILE *f;
150e0895134Schristos 
151e0895134Schristos     *residual = NULL;
152e0895134Schristos     primary = primary_create(dc);
153e0895134Schristos     if (primary == NULL)
154e0895134Schristos 	return krb5_enomem(context);
155e0895134Schristos 
156e0895134Schristos     f = fopen(primary, "r");
157e0895134Schristos     if (f == NULL) {
158e0895134Schristos 	if (errno == ENOENT) {
159e0895134Schristos 	    free(primary);
160e0895134Schristos 	    *residual = strdup("tkt");
161e0895134Schristos 	    if (*residual == NULL)
162e0895134Schristos 		return krb5_enomem(context);
163e0895134Schristos 	    return 0;
164e0895134Schristos 	}
165e0895134Schristos 	ret = errno;
166e0895134Schristos 	krb5_set_error_message(context, ret, "failed to open %s", primary);
167e0895134Schristos 	free(primary);
168e0895134Schristos 	return ret;
169e0895134Schristos     }
170e0895134Schristos 
171e0895134Schristos     if (fgets(buf, sizeof(buf), f) == NULL) {
172e0895134Schristos 	ret = ferror(f);
173e0895134Schristos 	fclose(f);
174e0895134Schristos 	krb5_set_error_message(context, ret, "read file %s", primary);
175e0895134Schristos 	free(primary);
176e0895134Schristos 	return ret;
177e0895134Schristos     }
178e0895134Schristos     fclose(f);
179e0895134Schristos 
180e0895134Schristos     buf[strcspn(buf, "\r\n")] = '\0';
181e0895134Schristos 
182e0895134Schristos     if (!is_filename_cacheish(buf)) {
183e0895134Schristos 	krb5_set_error_message(context, KRB5_CC_FORMAT,
184e0895134Schristos 			       "name in %s is not a cache (doesn't start with tkt)", primary);
185e0895134Schristos 	free(primary);
186e0895134Schristos         return KRB5_CC_FORMAT;
187e0895134Schristos     }
188e0895134Schristos 
189e0895134Schristos     free(primary);
190e0895134Schristos 
191e0895134Schristos     *residual = strdup(buf);
192e0895134Schristos     if (*residual == NULL)
193e0895134Schristos 	return krb5_enomem(context);
194e0895134Schristos 
195e0895134Schristos     return 0;
196e0895134Schristos }
197e0895134Schristos 
198e0895134Schristos 
199e0895134Schristos 
200e0895134Schristos static const char* KRB5_CALLCONV
dcc_get_name(krb5_context context,krb5_ccache id)201e0895134Schristos dcc_get_name(krb5_context context,
202e0895134Schristos 	     krb5_ccache id)
203e0895134Schristos {
204e0895134Schristos     krb5_dcache *dc = DCACHE(id);
205e0895134Schristos     return dc->name;
206e0895134Schristos }
207e0895134Schristos 
208e0895134Schristos 
209e0895134Schristos static krb5_error_code
verify_directory(krb5_context context,const char * path)210e0895134Schristos verify_directory(krb5_context context, const char *path)
211e0895134Schristos {
212e0895134Schristos     struct stat sb;
213e0895134Schristos 
214e0895134Schristos     if (stat(path, &sb) != 0) {
215e0895134Schristos 	if (errno == ENOENT) {
216e0895134Schristos 	    /* XXX should use mkdirx_np()  */
217e0895134Schristos 	    if (rk_mkdir(path, S_IRWXU) == 0)
218e0895134Schristos 		return 0;
219e0895134Schristos 
220e0895134Schristos 	    krb5_set_error_message(context, ENOENT,
221e0895134Schristos 				   N_("DIR directory %s doesn't exists", ""), path);
222e0895134Schristos 	    return ENOENT;
223e0895134Schristos 	} else {
224e0895134Schristos 	    int ret = errno;
225e0895134Schristos 	    krb5_set_error_message(context, ret,
226e0895134Schristos 				   N_("DIR directory %s is bad: %s", ""), path, strerror(ret));
227e0895134Schristos 	    return errno;
228e0895134Schristos 	}
229e0895134Schristos     }
230e0895134Schristos     if (!S_ISDIR(sb.st_mode)) {
231e0895134Schristos 	krb5_set_error_message(context, KRB5_CC_BADNAME,
232e0895134Schristos 			       N_("DIR directory %s is not a directory", ""), path);
233e0895134Schristos 	return KRB5_CC_BADNAME;
234e0895134Schristos     }
235e0895134Schristos 
236e0895134Schristos     return 0;
237e0895134Schristos }
238e0895134Schristos 
239e0895134Schristos static void
dcc_release(krb5_context context,krb5_dcache * dc)240e0895134Schristos dcc_release(krb5_context context, krb5_dcache *dc)
241e0895134Schristos {
242e0895134Schristos     if (dc->fcache)
243e0895134Schristos 	krb5_cc_close(context, dc->fcache);
244e0895134Schristos     if (dc->dir)
245e0895134Schristos 	free(dc->dir);
246e0895134Schristos     if (dc->name)
247e0895134Schristos 	free(dc->name);
248e0895134Schristos     memset(dc, 0, sizeof(*dc));
249e0895134Schristos     free(dc);
250e0895134Schristos }
251e0895134Schristos 
252e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_resolve(krb5_context context,krb5_ccache * id,const char * res)253e0895134Schristos dcc_resolve(krb5_context context, krb5_ccache *id, const char *res)
254e0895134Schristos {
255e0895134Schristos     char *filename = NULL;
256e0895134Schristos     krb5_error_code ret;
257e0895134Schristos     krb5_dcache *dc;
258e0895134Schristos     const char *p;
259e0895134Schristos 
260e0895134Schristos     p = res;
261e0895134Schristos     do {
262e0895134Schristos 	p = strstr(p, "..");
263e0895134Schristos 	if (p && (p == res || ISPATHSEP(p[-1])) && (ISPATHSEP(p[2]) || p[2] == '\0')) {
264e0895134Schristos 	    krb5_set_error_message(context, KRB5_CC_FORMAT,
265e0895134Schristos 				   N_("Path contains a .. component", ""));
266e0895134Schristos 	    return KRB5_CC_FORMAT;
267e0895134Schristos 	}
268e0895134Schristos 	if (p)
269e0895134Schristos 	    p += 3;
270e0895134Schristos     } while (p);
271e0895134Schristos 
272e0895134Schristos     dc = calloc(1, sizeof(*dc));
273e0895134Schristos     if (dc == NULL) {
274e0895134Schristos 	krb5_set_error_message(context, KRB5_CC_NOMEM,
275e0895134Schristos 			       N_("malloc: out of memory", ""));
276e0895134Schristos 	return KRB5_CC_NOMEM;
277e0895134Schristos     }
278e0895134Schristos 
279e0895134Schristos     /* check for explicit component */
280e0895134Schristos     if (res[0] == ':') {
281e0895134Schristos 	char *q;
282e0895134Schristos 
283e0895134Schristos 	dc->dir = strdup(&res[1]);
284e0895134Schristos #ifdef _WIN32
285e0895134Schristos 	q = strrchr(dc->dir, '\\');
286e0895134Schristos 	if (q == NULL)
287e0895134Schristos #endif
288e0895134Schristos 	q = strrchr(dc->dir, '/');
289e0895134Schristos 	if (q) {
290e0895134Schristos 	    *q++ = '\0';
291e0895134Schristos 	} else {
292e0895134Schristos 	    krb5_set_error_message(context, KRB5_CC_FORMAT, N_("Cache not an absolute path: %s", ""), dc->dir);
293e0895134Schristos 	    dcc_release(context, dc);
294e0895134Schristos 	    return KRB5_CC_FORMAT;
295e0895134Schristos 	}
296e0895134Schristos 
297e0895134Schristos 	if (!is_filename_cacheish(q)) {
298e0895134Schristos 	    krb5_set_error_message(context, KRB5_CC_FORMAT,
299e0895134Schristos 				   N_("Name %s is not a cache (doesn't start with tkt)", ""), q);
300e0895134Schristos 	    dcc_release(context, dc);
301e0895134Schristos 	    return KRB5_CC_FORMAT;
302e0895134Schristos 	}
303e0895134Schristos 
304e0895134Schristos 	ret = verify_directory(context, dc->dir);
305e0895134Schristos 	if (ret) {
306e0895134Schristos 	    dcc_release(context, dc);
307e0895134Schristos 	    return ret;
308e0895134Schristos 	}
309e0895134Schristos 
310e0895134Schristos 	dc->name = strdup(res);
311e0895134Schristos 	if (dc->name == NULL) {
312e0895134Schristos 	    dcc_release(context, dc);
313e0895134Schristos 	    return krb5_enomem(context);
314e0895134Schristos 	}
315e0895134Schristos 
316e0895134Schristos     } else {
317e0895134Schristos 	char *residual;
318e0895134Schristos 	size_t len;
319e0895134Schristos 
320e0895134Schristos 	dc->dir = strdup(res);
321e0895134Schristos 	if (dc->dir == NULL) {
322e0895134Schristos 	    dcc_release(context, dc);
323e0895134Schristos 	    return krb5_enomem(context);
324e0895134Schristos 	}
325e0895134Schristos 
326e0895134Schristos 	len = strlen(dc->dir);
327e0895134Schristos 
328e0895134Schristos 	if (ISPATHSEP(dc->dir[len - 1]))
329e0895134Schristos 	    dc->dir[len - 1] = '\0';
330e0895134Schristos 
331e0895134Schristos 	ret = verify_directory(context, dc->dir);
332e0895134Schristos 	if (ret) {
333e0895134Schristos 	    dcc_release(context, dc);
334e0895134Schristos 	    return ret;
335e0895134Schristos 	}
336e0895134Schristos 
337e0895134Schristos 	ret = get_default_cache(context, dc, &residual);
338e0895134Schristos 	if (ret) {
339e0895134Schristos 	    dcc_release(context, dc);
340e0895134Schristos 	    return ret;
341e0895134Schristos 	}
342e0895134Schristos 	asprintf(&dc->name, ":%s/%s", dc->dir, residual);
343e0895134Schristos 	free(residual);
344e0895134Schristos 	if (dc->name == NULL) {
345e0895134Schristos 	    dcc_release(context, dc);
346e0895134Schristos 	    return krb5_enomem(context);
347e0895134Schristos 	}
348e0895134Schristos     }
349e0895134Schristos 
350e0895134Schristos     asprintf(&filename, "FILE%s", dc->name);
351e0895134Schristos     if (filename == NULL) {
352e0895134Schristos 	dcc_release(context, dc);
353e0895134Schristos 	return krb5_enomem(context);
354e0895134Schristos     }
355e0895134Schristos 
356e0895134Schristos     ret = krb5_cc_resolve(context, filename, &dc->fcache);
357e0895134Schristos     free(filename);
358e0895134Schristos     if (ret) {
359e0895134Schristos 	dcc_release(context, dc);
360e0895134Schristos 	return ret;
361e0895134Schristos     }
362e0895134Schristos 
363e0895134Schristos 
364e0895134Schristos     (*id)->data.data = dc;
365e0895134Schristos     (*id)->data.length = sizeof(*dc);
366e0895134Schristos     return 0;
367e0895134Schristos }
368e0895134Schristos 
369e0895134Schristos static char *
copy_default_dcc_cache(krb5_context context)370e0895134Schristos copy_default_dcc_cache(krb5_context context)
371e0895134Schristos {
372e0895134Schristos     const char *defname;
373e0895134Schristos     krb5_error_code ret;
374e0895134Schristos     char *name = NULL;
375e0895134Schristos     size_t len;
376e0895134Schristos 
377e0895134Schristos     len = strlen(krb5_dcc_ops.prefix);
378e0895134Schristos 
379e0895134Schristos     defname = krb5_cc_default_name(context);
380e0895134Schristos     if (defname == NULL ||
381e0895134Schristos 	strncmp(defname, krb5_dcc_ops.prefix, len) != 0 ||
382e0895134Schristos 	defname[len] != ':')
383e0895134Schristos     {
384e0895134Schristos 	ret = dcc_get_default_name(context, &name);
385e0895134Schristos 	if (ret)
386e0895134Schristos 	    return NULL;
387e0895134Schristos 
388e0895134Schristos 	return name;
389e0895134Schristos     } else {
390e0895134Schristos 	return strdup(&defname[len + 1]);
391e0895134Schristos     }
392e0895134Schristos }
393e0895134Schristos 
394e0895134Schristos 
395e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_gen_new(krb5_context context,krb5_ccache * id)396e0895134Schristos dcc_gen_new(krb5_context context, krb5_ccache *id)
397e0895134Schristos {
398e0895134Schristos     krb5_error_code ret;
399e0895134Schristos     char *name = NULL;
400e0895134Schristos     krb5_dcache *dc;
401e0895134Schristos     int fd;
402e0895134Schristos     size_t len;
403e0895134Schristos 
404e0895134Schristos     name = copy_default_dcc_cache(context);
405e0895134Schristos     if (name == NULL) {
406e0895134Schristos 	krb5_set_error_message(context, KRB5_CC_FORMAT,
407e0895134Schristos 			       N_("Can't generate DIR caches unless its the default type", ""));
408e0895134Schristos 	return KRB5_CC_FORMAT;
409e0895134Schristos     }
410e0895134Schristos 
411e0895134Schristos     len = strlen(krb5_dcc_ops.prefix);
412e0895134Schristos     if (strncmp(name, krb5_dcc_ops.prefix, len) == 0 && name[len] == ':')
413e0895134Schristos 	++len;
414e0895134Schristos     else
415e0895134Schristos 	len = 0;
416e0895134Schristos 
417e0895134Schristos     ret = dcc_resolve(context, id, name + len);
418e0895134Schristos     free(name);
419e0895134Schristos     name = NULL;
420e0895134Schristos     if (ret)
421e0895134Schristos 	return ret;
422e0895134Schristos 
423e0895134Schristos     dc = DCACHE((*id));
424e0895134Schristos 
425e0895134Schristos     asprintf(&name, ":%s/tktXXXXXX", dc->dir);
426e0895134Schristos     if (name == NULL) {
427e0895134Schristos 	dcc_close(context, *id);
428e0895134Schristos 	return krb5_enomem(context);
429e0895134Schristos     }
430e0895134Schristos 
431e0895134Schristos     fd = mkstemp(&name[1]);
432e0895134Schristos     if (fd < 0) {
433e0895134Schristos 	dcc_close(context, *id);
434e0895134Schristos 	return krb5_enomem(context);
435e0895134Schristos     }
436e0895134Schristos     close(fd);
437e0895134Schristos 
438e0895134Schristos     free(dc->name);
439e0895134Schristos     dc->name = name;
440e0895134Schristos 
441e0895134Schristos     return 0;
442e0895134Schristos }
443e0895134Schristos 
444e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_initialize(krb5_context context,krb5_ccache id,krb5_principal primary_principal)445e0895134Schristos dcc_initialize(krb5_context context,
446e0895134Schristos 	       krb5_ccache id,
447e0895134Schristos 	       krb5_principal primary_principal)
448e0895134Schristos {
449e0895134Schristos     krb5_dcache *dc = DCACHE(id);
450e0895134Schristos     return krb5_cc_initialize(context, D2FCACHE(dc), primary_principal);
451e0895134Schristos }
452e0895134Schristos 
453e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_close(krb5_context context,krb5_ccache id)454e0895134Schristos dcc_close(krb5_context context,
455e0895134Schristos 	  krb5_ccache id)
456e0895134Schristos {
457e0895134Schristos     dcc_release(context, DCACHE(id));
458e0895134Schristos     return 0;
459e0895134Schristos }
460e0895134Schristos 
461e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_destroy(krb5_context context,krb5_ccache id)462e0895134Schristos dcc_destroy(krb5_context context,
463e0895134Schristos 	    krb5_ccache id)
464e0895134Schristos {
465e0895134Schristos     krb5_dcache *dc = DCACHE(id);
466e0895134Schristos     krb5_ccache fcache = D2FCACHE(dc);
467e0895134Schristos     dc->fcache = NULL;
468e0895134Schristos     return krb5_cc_destroy(context, fcache);
469e0895134Schristos }
470e0895134Schristos 
471e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_store_cred(krb5_context context,krb5_ccache id,krb5_creds * creds)472e0895134Schristos dcc_store_cred(krb5_context context,
473e0895134Schristos 	       krb5_ccache id,
474e0895134Schristos 	       krb5_creds *creds)
475e0895134Schristos {
476e0895134Schristos     krb5_dcache *dc = DCACHE(id);
477e0895134Schristos     return krb5_cc_store_cred(context, D2FCACHE(dc), creds);
478e0895134Schristos }
479e0895134Schristos 
480e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_principal(krb5_context context,krb5_ccache id,krb5_principal * principal)481e0895134Schristos dcc_get_principal(krb5_context context,
482e0895134Schristos 		  krb5_ccache id,
483e0895134Schristos 		  krb5_principal *principal)
484e0895134Schristos {
485e0895134Schristos     krb5_dcache *dc = DCACHE(id);
486e0895134Schristos     return krb5_cc_get_principal(context, D2FCACHE(dc), principal);
487e0895134Schristos }
488e0895134Schristos 
489e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_first(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)490e0895134Schristos dcc_get_first (krb5_context context,
491e0895134Schristos 	       krb5_ccache id,
492e0895134Schristos 	       krb5_cc_cursor *cursor)
493e0895134Schristos {
494e0895134Schristos     krb5_dcache *dc = DCACHE(id);
495e0895134Schristos     return krb5_cc_start_seq_get(context, D2FCACHE(dc), cursor);
496e0895134Schristos }
497e0895134Schristos 
498e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_next(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor,krb5_creds * creds)499e0895134Schristos dcc_get_next (krb5_context context,
500e0895134Schristos 	      krb5_ccache id,
501e0895134Schristos 	      krb5_cc_cursor *cursor,
502e0895134Schristos 	      krb5_creds *creds)
503e0895134Schristos {
504e0895134Schristos     krb5_dcache *dc = DCACHE(id);
505e0895134Schristos     return krb5_cc_next_cred(context, D2FCACHE(dc), cursor, creds);
506e0895134Schristos }
507e0895134Schristos 
508e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_end_get(krb5_context context,krb5_ccache id,krb5_cc_cursor * cursor)509e0895134Schristos dcc_end_get (krb5_context context,
510e0895134Schristos 	     krb5_ccache id,
511e0895134Schristos 	     krb5_cc_cursor *cursor)
512e0895134Schristos {
513e0895134Schristos     krb5_dcache *dc = DCACHE(id);
514e0895134Schristos     return krb5_cc_end_seq_get(context, D2FCACHE(dc), cursor);
515e0895134Schristos }
516e0895134Schristos 
517e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_remove_cred(krb5_context context,krb5_ccache id,krb5_flags which,krb5_creds * cred)518e0895134Schristos dcc_remove_cred(krb5_context context,
519e0895134Schristos 		 krb5_ccache id,
520e0895134Schristos 		 krb5_flags which,
521e0895134Schristos 		 krb5_creds *cred)
522e0895134Schristos {
523e0895134Schristos     krb5_dcache *dc = DCACHE(id);
524e0895134Schristos     return krb5_cc_remove_cred(context, D2FCACHE(dc), which, cred);
525e0895134Schristos }
526e0895134Schristos 
527e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_set_flags(krb5_context context,krb5_ccache id,krb5_flags flags)528e0895134Schristos dcc_set_flags(krb5_context context,
529e0895134Schristos 	      krb5_ccache id,
530e0895134Schristos 	      krb5_flags flags)
531e0895134Schristos {
532e0895134Schristos     krb5_dcache *dc = DCACHE(id);
533e0895134Schristos     return krb5_cc_set_flags(context, D2FCACHE(dc), flags);
534e0895134Schristos }
535e0895134Schristos 
536e0895134Schristos static int KRB5_CALLCONV
dcc_get_version(krb5_context context,krb5_ccache id)537e0895134Schristos dcc_get_version(krb5_context context,
538e0895134Schristos 		krb5_ccache id)
539e0895134Schristos {
540e0895134Schristos     krb5_dcache *dc = DCACHE(id);
541e0895134Schristos     return krb5_cc_get_version(context, D2FCACHE(dc));
542e0895134Schristos }
543e0895134Schristos 
544e0895134Schristos struct dcache_iter {
545e0895134Schristos     int first;
546e0895134Schristos     krb5_dcache *dc;
547e0895134Schristos };
548e0895134Schristos 
549e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_cache_first(krb5_context context,krb5_cc_cursor * cursor)550e0895134Schristos dcc_get_cache_first(krb5_context context, krb5_cc_cursor *cursor)
551e0895134Schristos {
552e0895134Schristos     struct dcache_iter *iter;
553e0895134Schristos     krb5_error_code ret;
554e0895134Schristos     char *name;
555e0895134Schristos 
556e0895134Schristos     *cursor = NULL;
557e0895134Schristos     iter = calloc(1, sizeof(*iter));
558e0895134Schristos     if (iter == NULL)
559e0895134Schristos 	return krb5_enomem(context);
560e0895134Schristos     iter->first = 1;
561e0895134Schristos 
562e0895134Schristos     name = copy_default_dcc_cache(context);
563e0895134Schristos     if (name == NULL) {
564e0895134Schristos         free(iter);
565e0895134Schristos 	krb5_set_error_message(context, KRB5_CC_FORMAT,
566e0895134Schristos 			       N_("Can't generate DIR caches unless its the default type", ""));
567e0895134Schristos 	return KRB5_CC_FORMAT;
568e0895134Schristos     }
569e0895134Schristos 
570e0895134Schristos     ret = dcc_resolve(context, NULL, name);
571e0895134Schristos     free(name);
572e0895134Schristos     if (ret) {
573e0895134Schristos         free(iter);
574e0895134Schristos         return ret;
575e0895134Schristos     }
576e0895134Schristos 
577e0895134Schristos     /* XXX We need to opendir() here */
578e0895134Schristos 
579e0895134Schristos     *cursor = iter;
580e0895134Schristos     return 0;
581e0895134Schristos }
582e0895134Schristos 
583e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_cache_next(krb5_context context,krb5_cc_cursor cursor,krb5_ccache * id)584e0895134Schristos dcc_get_cache_next(krb5_context context, krb5_cc_cursor cursor, krb5_ccache *id)
585e0895134Schristos {
586e0895134Schristos     struct dcache_iter *iter = cursor;
587e0895134Schristos 
588e0895134Schristos     if (iter == NULL)
589e0895134Schristos         return krb5_einval(context, 2);
590e0895134Schristos 
591e0895134Schristos     if (!iter->first) {
592e0895134Schristos 	krb5_clear_error_message(context);
593e0895134Schristos 	return KRB5_CC_END;
594e0895134Schristos     }
595e0895134Schristos 
596e0895134Schristos     /* XXX We need to readdir() here */
597e0895134Schristos     iter->first = 0;
598e0895134Schristos 
599e0895134Schristos     return KRB5_CC_END;
600e0895134Schristos }
601e0895134Schristos 
602e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_end_cache_get(krb5_context context,krb5_cc_cursor cursor)603e0895134Schristos dcc_end_cache_get(krb5_context context, krb5_cc_cursor cursor)
604e0895134Schristos {
605e0895134Schristos     struct dcache_iter *iter = cursor;
606e0895134Schristos 
607e0895134Schristos     if (iter == NULL)
608e0895134Schristos         return krb5_einval(context, 2);
609e0895134Schristos 
610e0895134Schristos     /* XXX We need to closedir() here */
611e0895134Schristos     if (iter->dc)
612e0895134Schristos 	dcc_release(context, iter->dc);
613e0895134Schristos     free(iter);
614e0895134Schristos     return 0;
615e0895134Schristos }
616e0895134Schristos 
617e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_move(krb5_context context,krb5_ccache from,krb5_ccache to)618e0895134Schristos dcc_move(krb5_context context, krb5_ccache from, krb5_ccache to)
619e0895134Schristos {
620e0895134Schristos     krb5_dcache *dcfrom = DCACHE(from);
621e0895134Schristos     krb5_dcache *dcto = DCACHE(to);
622e0895134Schristos     return krb5_cc_move(context, D2FCACHE(dcfrom), D2FCACHE(dcto));
623e0895134Schristos }
624e0895134Schristos 
625e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_default_name(krb5_context context,char ** str)626e0895134Schristos dcc_get_default_name(krb5_context context, char **str)
627e0895134Schristos {
628e0895134Schristos     return _krb5_expand_default_cc_name(context,
629e0895134Schristos 					KRB5_DEFAULT_CCNAME_DIR,
630e0895134Schristos 					str);
631e0895134Schristos }
632e0895134Schristos 
633e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_set_default(krb5_context context,krb5_ccache id)634e0895134Schristos dcc_set_default(krb5_context context, krb5_ccache id)
635e0895134Schristos {
636e0895134Schristos     krb5_dcache *dc = DCACHE(id);
637e0895134Schristos     const char *name;
638e0895134Schristos 
639e0895134Schristos     name = krb5_cc_get_name(context, D2FCACHE(dc));
640e0895134Schristos     if (name == NULL)
641e0895134Schristos 	return ENOENT;
642e0895134Schristos 
643e0895134Schristos     return set_default_cache(context, dc, name);
644e0895134Schristos }
645e0895134Schristos 
646e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_lastchange(krb5_context context,krb5_ccache id,krb5_timestamp * mtime)647e0895134Schristos dcc_lastchange(krb5_context context, krb5_ccache id, krb5_timestamp *mtime)
648e0895134Schristos {
649e0895134Schristos     krb5_dcache *dc = DCACHE(id);
650e0895134Schristos     return krb5_cc_last_change_time(context, D2FCACHE(dc), mtime);
651e0895134Schristos }
652e0895134Schristos 
653e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_set_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat kdc_offset)654e0895134Schristos dcc_set_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat kdc_offset)
655e0895134Schristos {
656e0895134Schristos     krb5_dcache *dc = DCACHE(id);
657e0895134Schristos     return krb5_cc_set_kdc_offset(context, D2FCACHE(dc), kdc_offset);
658e0895134Schristos }
659e0895134Schristos 
660e0895134Schristos static krb5_error_code KRB5_CALLCONV
dcc_get_kdc_offset(krb5_context context,krb5_ccache id,krb5_deltat * kdc_offset)661e0895134Schristos dcc_get_kdc_offset(krb5_context context, krb5_ccache id, krb5_deltat *kdc_offset)
662e0895134Schristos {
663e0895134Schristos     krb5_dcache *dc = DCACHE(id);
664e0895134Schristos     return krb5_cc_get_kdc_offset(context, D2FCACHE(dc), kdc_offset);
665e0895134Schristos }
666e0895134Schristos 
667e0895134Schristos 
668e0895134Schristos /**
669e0895134Schristos  * Variable containing the DIR based credential cache implemention.
670e0895134Schristos  *
671e0895134Schristos  * @ingroup krb5_ccache
672e0895134Schristos  */
673e0895134Schristos 
674e0895134Schristos KRB5_LIB_VARIABLE const krb5_cc_ops krb5_dcc_ops = {
675e0895134Schristos     KRB5_CC_OPS_VERSION,
676e0895134Schristos     "DIR",
677e0895134Schristos     dcc_get_name,
678e0895134Schristos     dcc_resolve,
679e0895134Schristos     dcc_gen_new,
680e0895134Schristos     dcc_initialize,
681e0895134Schristos     dcc_destroy,
682e0895134Schristos     dcc_close,
683e0895134Schristos     dcc_store_cred,
684e0895134Schristos     NULL, /* dcc_retrieve */
685e0895134Schristos     dcc_get_principal,
686e0895134Schristos     dcc_get_first,
687e0895134Schristos     dcc_get_next,
688e0895134Schristos     dcc_end_get,
689e0895134Schristos     dcc_remove_cred,
690e0895134Schristos     dcc_set_flags,
691e0895134Schristos     dcc_get_version,
692e0895134Schristos     dcc_get_cache_first,
693e0895134Schristos     dcc_get_cache_next,
694e0895134Schristos     dcc_end_cache_get,
695e0895134Schristos     dcc_move,
696e0895134Schristos     dcc_get_default_name,
697e0895134Schristos     dcc_set_default,
698e0895134Schristos     dcc_lastchange,
699e0895134Schristos     dcc_set_kdc_offset,
700e0895134Schristos     dcc_get_kdc_offset
701e0895134Schristos };
702