00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00027 #include <errno.h>
00028 #include <pwd.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <sys/types.h>
00032 #include <unistd.h>
00033
00034 #include "treeconf_int.h"
00035
00036 RCSTAG("@(#)$Id: tc_path.c,v 1.7 2005/06/08 13:17:36 klmitch Exp $");
00037
00043 struct buf {
00044 char *str;
00045 int len;
00046 int size;
00047 };
00048
00056 #define BUF_CHUNK 256
00057
00073 static unsigned int
00074 _get_pwd(struct passwd **pwd_p, const char *uname, int len)
00075 {
00076 struct passwd *pwd = 0;
00077 char ubuf[512];
00078
00079 if (uname) {
00080 strncpy(ubuf, uname, len);
00081 ubuf[len] = '\0';
00082 pwd = getpwnam(ubuf);
00083 } else
00084 pwd = getpwuid(geteuid());
00085
00086 if (!pwd)
00087 return !errno ? ENOENT : errno;
00088
00089 *pwd_p = pwd;
00090
00091 return 0;
00092 }
00093
00110 static unsigned int
00111 _add_str(struct buf *buf, const char *str, int len)
00112 {
00113 char *tmp = 0;
00114
00115 if (!str) {
00116 struct passwd *pwd = 0;
00117 unsigned int err;
00118
00119 if ((err = _get_pwd(&pwd, 0, 0)))
00120 return err;
00121
00122 str = pwd->pw_name;
00123 len = strlen(str);
00124 }
00125
00126 if (len < 0)
00127 len = strlen(str);
00128
00129 if (buf->size < buf->len + len + 1) {
00130 while (buf->size < buf->len + len)
00131 buf->size += BUF_CHUNK;
00132
00133
00134 if (!(tmp = (char *)realloc(buf->str, buf->size)))
00135 return ENOMEM;
00136 else
00137 buf->str = tmp;
00138 }
00139
00140 strncpy(buf->str + buf->len, str, len);
00141 buf->len += len;
00142 buf->str[buf->len] = '\0';
00143
00144 return 0;
00145 }
00146
00162 static unsigned int
00163 _tilde(struct buf *buf, const char *uname, int len)
00164 {
00165 struct passwd *pwd = 0;
00166 unsigned int err;
00167
00168 return (err = _get_pwd(&pwd, uname, len)) ? err :
00169 _add_str(buf, pwd->pw_dir, -1);
00170 }
00171
00179 #define STOP 0
00180
00188 #define CONTINUE 1
00189
00199 #define stop(e) do { *err = (e); return STOP; } while (0)
00200
00207 #define cont() do { *err = 0; return CONTINUE; } while (0)
00208
00216 #define _TC_PATH_DEFAULT 0x04
00217
00225 #define _TC_PATH_PERCENT 0x08
00226
00256 static int
00257 _subst(struct buf *buf, treeconf_str_t *element,
00258 treeconf_subst_t substs[], int s_cnt, unsigned int flags,
00259 treeconf_file_t call, void *call_data, unsigned int *err)
00260 {
00261 const char *str = 0, *tmp = 0;
00262 unsigned int _e = 0;
00263 int i, j, len = 0;
00264
00265 if (!element->ts_length)
00266 cont();
00267
00268 if (*element->ts_string == '~')
00269 switch (element->ts_length > 1 ? element->ts_string[1] : '\0') {
00270 case '/': case '\0':
00271 if (flags & TC_PATH_SECURE)
00272 cont();
00273 if ((_e = _tilde(buf, 0, 0)))
00274 stop(_e);
00275
00276 str = element->ts_length > 1 ? element->ts_string + 1 : 0;
00277 len = element->ts_length > 1 ? element->ts_length - 1 : 0;
00278 break;
00279 default:
00280
00281 for (i = 1; i < element->ts_length; i++)
00282 if (element->ts_string[i] == '/')
00283 break;
00284
00285 if ((_e = _tilde(buf, element->ts_string + 1, i - 2)))
00286 stop(_e);
00287
00288 str = i < element->ts_length ? element->ts_string + i : 0;
00289 len = i < element->ts_length ? element->ts_length - i : 0;
00290 break;
00291 }
00292 else {
00293 str = element->ts_string;
00294 len = element->ts_length;
00295 }
00296
00297
00298 for (i = 0, tmp = str; i < len; i++)
00299 if (flags & _TC_PATH_PERCENT) {
00300 flags &= ~_TC_PATH_PERCENT;
00301 if (str[i] == '%')
00302 tmp = str + i;
00303 else
00304 for (j = 0; j < s_cnt; j++)
00305 if (str[i] == substs[j].tu_char) {
00306 if ((substs[j].tu_flags & TC_SUBST_IGNORE) ||
00307 (flags & (substs[j].tu_flags & TC_SUBST_INSECURE)))
00308 cont();
00309 else if ((_e = _add_str(buf, substs[j].tu_value, -1)))
00310 stop(_e);
00311 break;
00312 }
00313
00314 } else if (str[i] == '%') {
00315 if ((_e = _add_str(buf, tmp, (str + i) - tmp)))
00316 stop(_e);
00317 flags |= _TC_PATH_PERCENT;
00318 tmp = 0;
00319 } else if (!tmp)
00320 tmp = str + i;
00321
00322 if (flags & _TC_PATH_PERCENT)
00323 stop(EINVAL);
00324 else if (tmp && (_e = _add_str(buf, tmp, (str + i) - tmp)))
00325 stop(_e);
00326
00327
00328
00329
00330
00331 if (access(buf->str, R_OK)) {
00332 *err = 0;
00333 buf->str[0] = '\0';
00334 buf->len = 0;
00335 cont();
00336 }
00337
00338 if ((_e = (call)(buf->str, call_data)))
00339 stop(_e);
00340
00341 *err = 0;
00342 buf->str[0] = '\0';
00343 buf->len = 0;
00344
00345 return flags & TC_PATH_ALL ? CONTINUE : STOP;
00346 }
00347
00348 unsigned int
00349 tc_path(const char *path, const char *def,
00350 treeconf_subst_t substs[], int s_cnt, unsigned int flags,
00351 treeconf_file_t call, void *call_data)
00352 {
00353 treeconf_str_t *p_str = 0, *d_str = 0;
00354 struct buf buf = { 0, 0, 0 };
00355 int p_cnt, d_cnt, i, j;
00356 unsigned int err = 0;
00357
00358 initialize_trcf_error_table();
00359
00360
00361 if (!def || (s_cnt && !substs) || !call)
00362 return EINVAL;
00363
00364 flags &= TC_PATH_SECURE | TC_PATH_ALL;
00365
00366
00367 if (!path) {
00368 path = def;
00369 flags |= _TC_PATH_DEFAULT;
00370 }
00371
00372
00373 if ((err = tc_break(&p_str, &p_cnt, path, ":")))
00374 goto error;
00375
00376
00377 for (i = 0; i < p_cnt; i++)
00378 if (!p_str[i].ts_length) {
00379 if (flags & _TC_PATH_DEFAULT)
00380 continue;
00381 flags |= _TC_PATH_DEFAULT;
00382 if ((err = tc_break(&d_str, &d_cnt, def, ":")))
00383 goto error;
00384
00385 for (j = 0; j < d_cnt; j++)
00386 if (!d_str[j].ts_length)
00387 continue;
00388 else if (_subst(&buf, d_str + j, substs, s_cnt, flags, call,
00389 call_data, &err) != CONTINUE)
00390 goto error;
00391 } else if (_subst(&buf, p_str + i, substs, s_cnt, flags, call,
00392 call_data, &err) != CONTINUE)
00393 break;
00394
00395 error:
00396 if (p_str)
00397 free(p_str);
00398 if (d_str)
00399 free(d_str);
00400 if (buf.str)
00401 free(buf.str);
00402
00403 return err;
00404 }