1 /*-
2 * Copyright (c) 2003-2005 MAEKAWA Masahide <maekawa@cvsync.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the author nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/types.h>
31 #include <sys/stat.h>
32
33 #include <stdio.h>
34 #include <stdlib.h>
35
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <fnmatch.h>
39 #include <limits.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include "compat_stdbool.h"
44 #include "compat_stdint.h"
45 #include "compat_inttypes.h"
46 #include "compat_limits.h"
47
48 #include "cvsync.h"
49 #include "cvsync_attr.h"
50 #include "filetypes.h"
51 #include "logmsg.h"
52 #include "refuse.h"
53 #include "token.h"
54
55 struct refuse_args *refuse_parse(FILE *);
56 char *refuse_parse_pattern(FILE *);
57
58 struct refuse_args *
refuse_open(const char * fname)59 refuse_open(const char *fname)
60 {
61 struct refuse_args *ra;
62 struct stat st;
63 FILE *fp;
64 int fd;
65
66 if ((fd = open(fname, O_RDONLY, 0)) == -1) {
67 logmsg_err("%s: %s", fname, strerror(errno));
68 return (NULL);
69 }
70 if (fstat(fd, &st) == -1) {
71 logmsg_err("%s: %s", fname, strerror(errno));
72 (void)close(fd);
73 return (NULL);
74 }
75 if (st.st_size > 0) {
76 if ((fp = fdopen(fd, "r")) == NULL) {
77 logmsg_err("%s: %s", fname, strerror(errno));
78 (void)close(fd);
79 return (NULL);
80 }
81 if ((ra = refuse_parse(fp)) == NULL) {
82 (void)fclose(fp);
83 return (NULL);
84 }
85 if (fclose(fp) == EOF) {
86 logmsg_err("%s: %s", fname, strerror(errno));
87 refuse_close(ra);
88 return (NULL);
89 }
90 } else {
91 if (close(fd) == -1) {
92 logmsg_err("%s: %s", fname, strerror(errno));
93 return (NULL);
94 }
95 if ((ra = malloc(sizeof(*ra))) == NULL) {
96 logmsg_err("%s", strerror(errno));
97 return (NULL);
98 }
99 (void)memset(ra, 0, sizeof(*ra));
100 }
101
102 return (ra);
103 }
104
105 void
refuse_close(struct refuse_args * ra)106 refuse_close(struct refuse_args *ra)
107 {
108 size_t i;
109
110 if (ra == NULL)
111 return;
112
113 if (ra->ra_patterns != NULL) {
114 for (i = 0 ; i < ra->ra_size ; i++)
115 free(ra->ra_patterns[i]);
116 free(ra->ra_patterns);
117 }
118
119 free(ra);
120 }
121
122 struct refuse_args *
refuse_parse(FILE * fp)123 refuse_parse(FILE *fp)
124 {
125 struct refuse_args *ra;
126 char *pat;
127 size_t max = 0;
128
129 lineno = 1;
130
131 if ((ra = malloc(sizeof(*ra))) == NULL) {
132 logmsg_err("%s", strerror(errno));
133 return (NULL);
134 }
135 ra->ra_patterns = NULL;
136 ra->ra_size = 0;
137
138 for (;;) {
139 if (!token_skip_whitespace(fp)) {
140 if (feof(fp) == 0) {
141 logmsg_err("Distfile Error: premature EOF");
142 refuse_close(ra);
143 return (NULL);
144 }
145 break;
146 }
147
148 if (ra->ra_size == max) {
149 char **newptr;
150 size_t old = max, new = old + 4;
151
152 if ((newptr = malloc(new * sizeof(*newptr))) == NULL) {
153 logmsg_err("%s", strerror(errno));
154 refuse_close(ra);
155 return (NULL);
156 }
157
158 if (ra->ra_patterns != NULL) {
159 (void)memcpy(newptr, ra->ra_patterns,
160 old * sizeof(*newptr));
161 free(ra->ra_patterns);
162 }
163 ra->ra_patterns = newptr;
164 max = new;
165 }
166
167 if ((pat = refuse_parse_pattern(fp)) == NULL) {
168 refuse_close(ra);
169 return (NULL);
170 }
171
172 ra->ra_patterns[ra->ra_size++] = pat;
173 }
174
175 if (ra->ra_size == 0) {
176 if (ra->ra_patterns != NULL)
177 free(ra->ra_patterns);
178 ra->ra_patterns = NULL;
179 }
180
181 return (ra);
182 }
183
184 char *
refuse_parse_pattern(FILE * fp)185 refuse_parse_pattern(FILE *fp)
186 {
187 char *tok;
188 size_t max = 32, n = 0;
189 int c;
190
191 if ((tok = malloc(max + 1)) == NULL) {
192 logmsg_err("%s", strerror(errno));
193 return (NULL);
194 }
195
196 while ((c = fgetc(fp)) != EOF) {
197 if (c == '\n')
198 break;
199 if (n == max) {
200 char *newptr;
201 size_t old = max, new = old + 32;
202
203 if ((newptr = malloc(new + 1)) == NULL) {
204 logmsg_err("%s", strerror(errno));
205 free(tok);
206 return (NULL);
207 }
208
209 (void)memcpy(newptr, tok, old);
210 free(tok);
211
212 tok = newptr;
213 max = new;
214 }
215
216 tok[n++] = (char)c;
217 }
218 if (c != '\n') {
219 free(tok);
220 return (NULL);
221 }
222 tok[n] = '\0';
223
224 return (tok);
225 }
226
227 bool
refuse_access(struct refuse_args * ra,struct cvsync_attr * ca)228 refuse_access(struct refuse_args *ra, struct cvsync_attr *ca)
229 {
230 char *pat, *ep;
231 size_t namelen, i;
232 int rv;
233
234 if ((ra == NULL) || (ra->ra_size == 0))
235 return (true);
236
237 if (ca->ca_namelen >= sizeof(ca->ca_name))
238 return (true);
239 ca->ca_name[ca->ca_namelen] = '\0';
240
241 for (i = 0 ; i < ra->ra_size ; i++) {
242 pat = ra->ra_patterns[i];
243 if (fnmatch(pat, (char *)ca->ca_name, 0) != FNM_NOMATCH)
244 return (false);
245 if (ca->ca_type != FILETYPE_DIR)
246 continue;
247 namelen = strlen(pat);
248 ep = pat + namelen;
249 while (ep > pat) {
250 if (*--ep != '/')
251 continue;
252
253 *ep = '\0';
254 rv = fnmatch(pat, (char *)ca->ca_name, 0);
255 *ep = '/';
256
257 if (rv != FNM_NOMATCH)
258 return (false);
259
260 namelen = ep - pat;
261 }
262 }
263
264 return (true);
265 }
266