1178825Sdfr/*
2233294Sstas * Copyright (c) 2006 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
5178825Sdfr *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
9178825Sdfr *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
12178825Sdfr *
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.
16178825Sdfr *
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.
20178825Sdfr *
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.
32178825Sdfr */
33178825Sdfr
34178825Sdfr#include "hx_locl.h"
35178825Sdfr#include <dirent.h>
36178825Sdfr
37178825Sdfr/*
38178825Sdfr * The DIR keyset module is strange compared to the other modules
39178825Sdfr * since it does lazy evaluation and really doesn't keep any local
40178825Sdfr * state except for the directory iteration and cert iteration of
41178825Sdfr * files. DIR ignores most errors so that the consumer doesn't get
42178825Sdfr * failes for stray files in directories.
43178825Sdfr */
44178825Sdfr
45178825Sdfrstruct dircursor {
46178825Sdfr    DIR *dir;
47178825Sdfr    hx509_certs certs;
48178825Sdfr    void *iter;
49178825Sdfr};
50178825Sdfr
51178825Sdfr/*
52178825Sdfr *
53178825Sdfr */
54178825Sdfr
55178825Sdfrstatic int
56178825Sdfrdir_init(hx509_context context,
57233294Sstas	 hx509_certs certs, void **data, int flags,
58178825Sdfr	 const char *residue, hx509_lock lock)
59178825Sdfr{
60178825Sdfr    *data = NULL;
61178825Sdfr
62178825Sdfr    {
63178825Sdfr	struct stat sb;
64178825Sdfr	int ret;
65178825Sdfr
66178825Sdfr	ret = stat(residue, &sb);
67178825Sdfr	if (ret == -1) {
68178825Sdfr	    hx509_set_error_string(context, 0, ENOENT,
69178825Sdfr				   "No such file %s", residue);
70178825Sdfr	    return ENOENT;
71178825Sdfr	}
72178825Sdfr
73233294Sstas	if (!S_ISDIR(sb.st_mode)) {
74178825Sdfr	    hx509_set_error_string(context, 0, ENOTDIR,
75178825Sdfr				   "%s is not a directory", residue);
76178825Sdfr	    return ENOTDIR;
77178825Sdfr	}
78178825Sdfr    }
79178825Sdfr
80178825Sdfr    *data = strdup(residue);
81178825Sdfr    if (*data == NULL) {
82178825Sdfr	hx509_clear_error_string(context);
83178825Sdfr	return ENOMEM;
84178825Sdfr    }
85178825Sdfr
86178825Sdfr    return 0;
87178825Sdfr}
88178825Sdfr
89178825Sdfrstatic int
90178825Sdfrdir_free(hx509_certs certs, void *data)
91178825Sdfr{
92178825Sdfr    free(data);
93178825Sdfr    return 0;
94178825Sdfr}
95178825Sdfr
96233294Sstasstatic int
97178825Sdfrdir_iter_start(hx509_context context,
98178825Sdfr	       hx509_certs certs, void *data, void **cursor)
99178825Sdfr{
100178825Sdfr    struct dircursor *d;
101178825Sdfr
102178825Sdfr    *cursor = NULL;
103178825Sdfr
104178825Sdfr    d = calloc(1, sizeof(*d));
105178825Sdfr    if (d == NULL) {
106178825Sdfr	hx509_clear_error_string(context);
107178825Sdfr	return ENOMEM;
108178825Sdfr    }
109178825Sdfr
110178825Sdfr    d->dir = opendir(data);
111178825Sdfr    if (d->dir == NULL) {
112178825Sdfr	hx509_clear_error_string(context);
113178825Sdfr	free(d);
114178825Sdfr	return errno;
115178825Sdfr    }
116233294Sstas    rk_cloexec_dir(d->dir);
117178825Sdfr    d->certs = NULL;
118178825Sdfr    d->iter = NULL;
119178825Sdfr
120178825Sdfr    *cursor = d;
121178825Sdfr    return 0;
122178825Sdfr}
123178825Sdfr
124178825Sdfrstatic int
125178825Sdfrdir_iter(hx509_context context,
126178825Sdfr	 hx509_certs certs, void *data, void *iter, hx509_cert *cert)
127178825Sdfr{
128178825Sdfr    struct dircursor *d = iter;
129178825Sdfr    int ret = 0;
130233294Sstas
131178825Sdfr    *cert = NULL;
132178825Sdfr
133178825Sdfr    do {
134178825Sdfr	struct dirent *dir;
135178825Sdfr	char *fn;
136178825Sdfr
137178825Sdfr	if (d->certs) {
138178825Sdfr	    ret = hx509_certs_next_cert(context, d->certs, d->iter, cert);
139178825Sdfr	    if (ret) {
140178825Sdfr		hx509_certs_end_seq(context, d->certs, d->iter);
141178825Sdfr		d->iter = NULL;
142178825Sdfr		hx509_certs_free(&d->certs);
143178825Sdfr		return ret;
144178825Sdfr	    }
145178825Sdfr	    if (*cert) {
146178825Sdfr		ret = 0;
147178825Sdfr		break;
148178825Sdfr	    }
149178825Sdfr	    hx509_certs_end_seq(context, d->certs, d->iter);
150178825Sdfr	    d->iter = NULL;
151178825Sdfr	    hx509_certs_free(&d->certs);
152178825Sdfr	}
153178825Sdfr
154178825Sdfr	dir = readdir(d->dir);
155178825Sdfr	if (dir == NULL) {
156178825Sdfr	    ret = 0;
157178825Sdfr	    break;
158178825Sdfr	}
159178825Sdfr	if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0)
160178825Sdfr	    continue;
161233294Sstas
162178825Sdfr	if (asprintf(&fn, "FILE:%s/%s", (char *)data, dir->d_name) == -1)
163178825Sdfr	    return ENOMEM;
164233294Sstas
165178825Sdfr	ret = hx509_certs_init(context, fn, 0, NULL, &d->certs);
166178825Sdfr	if (ret == 0) {
167178825Sdfr
168178825Sdfr	    ret = hx509_certs_start_seq(context, d->certs, &d->iter);
169178825Sdfr	    if (ret)
170178825Sdfr	    hx509_certs_free(&d->certs);
171178825Sdfr	}
172178825Sdfr	/* ignore errors */
173178825Sdfr	if (ret) {
174178825Sdfr	    d->certs = NULL;
175178825Sdfr	    ret = 0;
176178825Sdfr	}
177178825Sdfr
178178825Sdfr	free(fn);
179178825Sdfr    } while(ret == 0);
180178825Sdfr
181178825Sdfr    return ret;
182178825Sdfr}
183178825Sdfr
184178825Sdfr
185178825Sdfrstatic int
186178825Sdfrdir_iter_end(hx509_context context,
187178825Sdfr	     hx509_certs certs,
188178825Sdfr	     void *data,
189178825Sdfr	     void *cursor)
190178825Sdfr{
191178825Sdfr    struct dircursor *d = cursor;
192178825Sdfr
193178825Sdfr    if (d->certs) {
194178825Sdfr	hx509_certs_end_seq(context, d->certs, d->iter);
195178825Sdfr	d->iter = NULL;
196178825Sdfr	hx509_certs_free(&d->certs);
197178825Sdfr    }
198178825Sdfr    closedir(d->dir);
199178825Sdfr    free(d);
200178825Sdfr    return 0;
201178825Sdfr}
202178825Sdfr
203178825Sdfr
204178825Sdfrstatic struct hx509_keyset_ops keyset_dir = {
205178825Sdfr    "DIR",
206178825Sdfr    0,
207178825Sdfr    dir_init,
208178825Sdfr    NULL,
209178825Sdfr    dir_free,
210178825Sdfr    NULL,
211178825Sdfr    NULL,
212178825Sdfr    dir_iter_start,
213178825Sdfr    dir_iter,
214178825Sdfr    dir_iter_end
215178825Sdfr};
216178825Sdfr
217178825Sdfrvoid
218178825Sdfr_hx509_ks_dir_register(hx509_context context)
219178825Sdfr{
220178825Sdfr    _hx509_ks_register(context, &keyset_dir);
221178825Sdfr}
222