1 /* $NetBSD: conf.c,v 1.10 2003/08/07 10:04:30 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software donated to Berkeley by 8 * Jan-Simon Pendry. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from: Id: conf.c,v 1.2 1992/05/27 07:09:27 jsp Exp 35 * @(#)conf.c 8.2 (Berkeley) 3/27/94 36 */ 37 38 #include <sys/cdefs.h> 39 #ifndef lint 40 __RCSID("$NetBSD: conf.c,v 1.10 2003/08/07 10:04:30 agc Exp $"); 41 #endif /* not lint */ 42 43 #include <sys/types.h> 44 #include <sys/param.h> 45 #include <sys/syslog.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <unistd.h> 49 #include <string.h> 50 #include <errno.h> 51 #include <limits.h> 52 #include <regex.h> 53 54 #include "portald.h" 55 56 #define ALLOC(ty) (xmalloc(sizeof(ty))) 57 58 typedef struct path path; 59 struct path { 60 qelem p_q; /* 2-way linked list */ 61 int p_lno; /* Line number of this record */ 62 char *p_args; /* copy of arg string (malloc) */ 63 char *p_key; /* Pathname to match (also p_argv[0]) */ 64 regex_t p_re; /* RE to match against pathname (malloc) */ 65 int p_use_re; /* true if entry is RE */ 66 int p_argc; /* number of elements in arg string */ 67 char **p_argv; /* argv[] pointers into arg string (malloc) */ 68 }; 69 70 static void ins_que __P((qelem *, qelem *)); 71 static path *palloc __P((char *, int, const char *)); 72 static void pfree __P((path *)); 73 static int pinsert __P((path *, qelem *)); 74 static void preplace __P((qelem *, qelem *)); 75 static void readfp __P((qelem *, FILE *, const char *)); 76 static void rem_que __P((qelem *)); 77 static void *xmalloc __P((size_t)); 78 79 /* 80 * Add an element to a 2-way list, 81 * just after (pred) 82 */ 83 static void 84 ins_que(elem, pred) 85 qelem *elem, *pred; 86 { 87 qelem *p = pred->q_forw; 88 elem->q_back = pred; 89 elem->q_forw = p; 90 pred->q_forw = elem; 91 p->q_back = elem; 92 } 93 94 /* 95 * Remove an element from a 2-way list 96 */ 97 static void 98 rem_que(elem) 99 qelem *elem; 100 { 101 qelem *p = elem->q_forw; 102 qelem *p2 = elem->q_back; 103 p2->q_forw = p; 104 p->q_back = p2; 105 } 106 107 /* 108 * Error checking malloc 109 */ 110 static void * 111 xmalloc(siz) 112 size_t siz; 113 { 114 void *p = malloc(siz); 115 if (p) 116 return (p); 117 syslog(LOG_ERR, "malloc: failed to get %lu bytes", (u_long)siz); 118 exit(1); 119 } 120 121 /* 122 * Insert the path in the list. 123 * If there is already an element with the same key then 124 * the *second* one is ignored (return 0). If the key is 125 * not found then the path is added to the end of the list 126 * and 1 is returned. 127 */ 128 static int 129 pinsert(p0, q0) 130 path *p0; 131 qelem *q0; 132 { 133 qelem *q; 134 135 if (p0->p_argc == 0) 136 return (0); 137 138 for (q = q0->q_forw; q != q0; q = q->q_forw) { 139 path *p = (path *) q; 140 if (strcmp(p->p_key, p0->p_key) == 0) 141 return (0); 142 } 143 ins_que(&p0->p_q, q0->q_back); 144 return (1); 145 146 } 147 148 static path * 149 palloc(cline, lno, conf_file) 150 char *cline; 151 int lno; 152 const char *conf_file; 153 { 154 int c, errcode; 155 char *s; 156 char *key; 157 path *p; 158 char **ap; 159 160 /* 161 * Implement comment chars 162 */ 163 s = strchr(cline, '#'); 164 if (s) 165 *s = 0; 166 167 /* 168 * Do a pass through the string to count the number 169 * of arguments 170 */ 171 c = 0; 172 key = strdup(cline); 173 for (s = key; s != NULL; ) { 174 char *val; 175 while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0') 176 ; 177 if (val) 178 c++; 179 } 180 c++; 181 free(key); 182 183 if (c <= 1) 184 return (0); 185 186 /* 187 * Now do another pass and generate a new path structure 188 */ 189 p = ALLOC(path); 190 p->p_argc = 0; 191 p->p_argv = xmalloc(c * sizeof(char *)); 192 p->p_args = strdup(cline); 193 ap = p->p_argv; 194 for (s = p->p_args; s != NULL; ) { 195 char *val; 196 while ((val = strsep(&s, " \t\n")) != NULL && *val == '\0') 197 ; 198 if (val) { 199 *ap++ = val; 200 p->p_argc++; 201 } 202 } 203 *ap = 0; 204 205 #ifdef DEBUG 206 for (c = 0; c < p->p_argc; c++) 207 printf("%sv[%d] = %s\n", c?"\t":"", c, p->p_argv[c]); 208 #endif 209 210 p->p_key = p->p_argv[0]; 211 p->p_use_re = 0; 212 if (strpbrk(p->p_key, RE_CHARS)) { 213 errcode = regcomp(&p->p_re, p->p_key, REG_EXTENDED|REG_NOSUB); 214 if (errcode == 0) 215 p->p_use_re = 1; 216 else { 217 char buf[200]; 218 regerror(errcode, &p->p_re, buf, sizeof(buf)); 219 220 syslog(LOG_WARNING, "%s, line %d: regcomp \"%s\": %s", 221 conf_file, p->p_lno, p->p_key, buf); 222 } 223 } 224 p->p_lno = lno; 225 226 return (p); 227 } 228 229 /* 230 * Free a path structure 231 */ 232 static void 233 pfree(p) 234 path *p; 235 { 236 free(p->p_args); 237 free((char *) p->p_argv); 238 if (p->p_use_re) 239 regfree(&p->p_re); 240 free((char *) p); 241 } 242 243 /* 244 * Discard all currently held path structures on q0. 245 * and add all the ones on xq. 246 */ 247 static void 248 preplace(q0, xq) 249 qelem *q0; 250 qelem *xq; 251 { 252 /* 253 * While the list is not empty, 254 * take the first element off the list 255 * and free it. 256 */ 257 while (q0->q_forw != q0) { 258 qelem *q = q0->q_forw; 259 rem_que(q); 260 pfree((path *) q); 261 } 262 while (xq->q_forw != xq) { 263 qelem *q = xq->q_forw; 264 rem_que(q); 265 ins_que(q, q0); 266 } 267 } 268 269 /* 270 * Read the lines from the configuration file and 271 * add them to the list of paths. 272 */ 273 static void 274 readfp(q0, fp, conf_file) 275 qelem *q0; 276 FILE *fp; 277 const char *conf_file; 278 { 279 char cline[LINE_MAX]; 280 int nread = 0; 281 qelem q; 282 283 /* 284 * Make a new empty list. 285 */ 286 q.q_forw = q.q_back = &q; 287 288 /* 289 * Read the lines from the configuration file. 290 */ 291 while (fgets(cline, sizeof(cline), fp)) { 292 path *p = palloc(cline, nread+1, conf_file); 293 if (p && !pinsert(p, &q)) 294 pfree(p); 295 nread++; 296 } 297 298 /* 299 * If some records were read, then throw 300 * away the old list and replace with the 301 * new one. 302 */ 303 if (nread) 304 preplace(q0, &q); 305 } 306 307 /* 308 * Read the configuration file (conf) and replace 309 * the existing path list with the new version. 310 * If the file is not readable, then no changes take place 311 */ 312 void 313 conf_read(q, conf) 314 qelem *q; 315 char *conf; 316 { 317 FILE *fp = fopen(conf, "r"); 318 if (fp) { 319 readfp(q, fp, conf); 320 (void) fclose(fp); 321 } else 322 syslog(LOG_WARNING, "open config file \"%s\": %m", conf); 323 } 324 325 326 char ** 327 conf_match(q0, key) 328 qelem *q0; 329 char *key; 330 { 331 qelem *q; 332 333 for (q = q0->q_forw; q != q0; q = q->q_forw) { 334 path *p = (path *) q; 335 if (p->p_use_re) { 336 if (regexec(&p->p_re, key, 0, NULL, 0) == 0) 337 return (p->p_argv+1); 338 } else { 339 if (strncmp(p->p_key, key, strlen(p->p_key)) == 0) 340 return (p->p_argv+1); 341 } 342 } 343 344 return (0); 345 } 346