1178825Sdfr/*
2178825Sdfr * Copyright (c) 2006 Kungliga Tekniska H�gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
5178825Sdfr *
6178825Sdfr * Redistribution and use in source and binary forms, with or without
7178825Sdfr * modification, are permitted provided that the following conditions
8178825Sdfr * are met:
9178825Sdfr *
10178825Sdfr * 1. Redistributions of source code must retain the above copyright
11178825Sdfr *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
18178825Sdfr *    may be used to endorse or promote products derived from this software
19178825Sdfr *    without specific prior written permission.
20178825Sdfr *
21178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31178825Sdfr * SUCH DAMAGE.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825SdfrRCSID("$Id: ks_dir.c 19778 2007-01-09 10:52:13Z lha $");
36178825Sdfr#include <dirent.h>
37178825Sdfr
38178825Sdfr/*
39178825Sdfr * The DIR keyset module is strange compared to the other modules
40178825Sdfr * since it does lazy evaluation and really doesn't keep any local
41178825Sdfr * state except for the directory iteration and cert iteration of
42178825Sdfr * files. DIR ignores most errors so that the consumer doesn't get
43178825Sdfr * failes for stray files in directories.
44178825Sdfr */
45178825Sdfr
46178825Sdfrstruct dircursor {
47178825Sdfr    DIR *dir;
48178825Sdfr    hx509_certs certs;
49178825Sdfr    void *iter;
50178825Sdfr};
51178825Sdfr
52178825Sdfr/*
53178825Sdfr *
54178825Sdfr */
55178825Sdfr
56178825Sdfrstatic int
57178825Sdfrdir_init(hx509_context context,
58178825Sdfr	 hx509_certs certs, void **data, int flags,
59178825Sdfr	 const char *residue, hx509_lock lock)
60178825Sdfr{
61178825Sdfr    *data = NULL;
62178825Sdfr
63178825Sdfr    {
64178825Sdfr	struct stat sb;
65178825Sdfr	int ret;
66178825Sdfr
67178825Sdfr	ret = stat(residue, &sb);
68178825Sdfr	if (ret == -1) {
69178825Sdfr	    hx509_set_error_string(context, 0, ENOENT,
70178825Sdfr				   "No such file %s", residue);
71178825Sdfr	    return ENOENT;
72178825Sdfr	}
73178825Sdfr
74178825Sdfr	if ((sb.st_mode & S_IFDIR) == 0) {
75178825Sdfr	    hx509_set_error_string(context, 0, ENOTDIR,
76178825Sdfr				   "%s is not a directory", residue);
77178825Sdfr	    return ENOTDIR;
78178825Sdfr	}
79178825Sdfr    }
80178825Sdfr
81178825Sdfr    *data = strdup(residue);
82178825Sdfr    if (*data == NULL) {
83178825Sdfr	hx509_clear_error_string(context);
84178825Sdfr	return ENOMEM;
85178825Sdfr    }
86178825Sdfr
87178825Sdfr    return 0;
88178825Sdfr}
89178825Sdfr
90178825Sdfrstatic int
91178825Sdfrdir_free(hx509_certs certs, void *data)
92178825Sdfr{
93178825Sdfr    free(data);
94178825Sdfr    return 0;
95178825Sdfr}
96178825Sdfr
97178825Sdfr
98178825Sdfr
99178825Sdfrstatic int
100178825Sdfrdir_iter_start(hx509_context context,
101178825Sdfr	       hx509_certs certs, void *data, void **cursor)
102178825Sdfr{
103178825Sdfr    struct dircursor *d;
104178825Sdfr
105178825Sdfr    *cursor = NULL;
106178825Sdfr
107178825Sdfr    d = calloc(1, sizeof(*d));
108178825Sdfr    if (d == NULL) {
109178825Sdfr	hx509_clear_error_string(context);
110178825Sdfr	return ENOMEM;
111178825Sdfr    }
112178825Sdfr
113178825Sdfr    d->dir = opendir(data);
114178825Sdfr    if (d->dir == NULL) {
115178825Sdfr	hx509_clear_error_string(context);
116178825Sdfr	free(d);
117178825Sdfr	return errno;
118178825Sdfr    }
119178825Sdfr    d->certs = NULL;
120178825Sdfr    d->iter = NULL;
121178825Sdfr
122178825Sdfr    *cursor = d;
123178825Sdfr    return 0;
124178825Sdfr}
125178825Sdfr
126178825Sdfrstatic int
127178825Sdfrdir_iter(hx509_context context,
128178825Sdfr	 hx509_certs certs, void *data, void *iter, hx509_cert *cert)
129178825Sdfr{
130178825Sdfr    struct dircursor *d = iter;
131178825Sdfr    int ret = 0;
132178825Sdfr
133178825Sdfr    *cert = NULL;
134178825Sdfr
135178825Sdfr    do {
136178825Sdfr	struct dirent *dir;
137178825Sdfr	char *fn;
138178825Sdfr
139178825Sdfr	if (d->certs) {
140178825Sdfr	    ret = hx509_certs_next_cert(context, d->certs, d->iter, cert);
141178825Sdfr	    if (ret) {
142178825Sdfr		hx509_certs_end_seq(context, d->certs, d->iter);
143178825Sdfr		d->iter = NULL;
144178825Sdfr		hx509_certs_free(&d->certs);
145178825Sdfr		return ret;
146178825Sdfr	    }
147178825Sdfr	    if (*cert) {
148178825Sdfr		ret = 0;
149178825Sdfr		break;
150178825Sdfr	    }
151178825Sdfr	    hx509_certs_end_seq(context, d->certs, d->iter);
152178825Sdfr	    d->iter = NULL;
153178825Sdfr	    hx509_certs_free(&d->certs);
154178825Sdfr	}
155178825Sdfr
156178825Sdfr	dir = readdir(d->dir);
157178825Sdfr	if (dir == NULL) {
158178825Sdfr	    ret = 0;
159178825Sdfr	    break;
160178825Sdfr	}
161178825Sdfr	if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
162178825Sdfr	    continue;
163178825Sdfr
164178825Sdfr	if (asprintf(&fn, "FILE:%s/%s", (char *)data, dir->d_name) == -1)
165178825Sdfr	    return ENOMEM;
166178825Sdfr
167178825Sdfr	ret = hx509_certs_init(context, fn, 0, NULL, &d->certs);
168178825Sdfr	if (ret == 0) {
169178825Sdfr
170178825Sdfr	    ret = hx509_certs_start_seq(context, d->certs, &d->iter);
171178825Sdfr	    if (ret)
172178825Sdfr	    hx509_certs_free(&d->certs);
173178825Sdfr	}
174178825Sdfr	/* ignore errors */
175178825Sdfr	if (ret) {
176178825Sdfr	    d->certs = NULL;
177178825Sdfr	    ret = 0;
178178825Sdfr	}
179178825Sdfr
180178825Sdfr	free(fn);
181178825Sdfr    } while(ret == 0);
182178825Sdfr
183178825Sdfr    return ret;
184178825Sdfr}
185178825Sdfr
186178825Sdfr
187178825Sdfrstatic int
188178825Sdfrdir_iter_end(hx509_context context,
189178825Sdfr	     hx509_certs certs,
190178825Sdfr	     void *data,
191178825Sdfr	     void *cursor)
192178825Sdfr{
193178825Sdfr    struct dircursor *d = cursor;
194178825Sdfr
195178825Sdfr    if (d->certs) {
196178825Sdfr	hx509_certs_end_seq(context, d->certs, d->iter);
197178825Sdfr	d->iter = NULL;
198178825Sdfr	hx509_certs_free(&d->certs);
199178825Sdfr    }
200178825Sdfr    closedir(d->dir);
201178825Sdfr    free(d);
202178825Sdfr    return 0;
203178825Sdfr}
204178825Sdfr
205178825Sdfr
206178825Sdfrstatic struct hx509_keyset_ops keyset_dir = {
207178825Sdfr    "DIR",
208178825Sdfr    0,
209178825Sdfr    dir_init,
210178825Sdfr    NULL,
211178825Sdfr    dir_free,
212178825Sdfr    NULL,
213178825Sdfr    NULL,
214178825Sdfr    dir_iter_start,
215178825Sdfr    dir_iter,
216178825Sdfr    dir_iter_end
217178825Sdfr};
218178825Sdfr
219178825Sdfrvoid
220178825Sdfr_hx509_ks_dir_register(hx509_context context)
221178825Sdfr{
222178825Sdfr    _hx509_ks_register(context, &keyset_dir);
223178825Sdfr}
224