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