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