diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2003-03-31 15:47:04 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2003-03-31 15:47:04 +0000 |
commit | c7f37bd495fae7dc3175f11cd72f5121c12a70b1 (patch) | |
tree | d87b280df344c8f025447c49890326f866b64dcb | |
parent | 4a611f430f1d46954f058f1d874d5764815dc156 (diff) |
Rewritten setuserpath() that is much clearer and uses strlcpy()
for added paranoia. tdeval@ and mpech@ OK
-rw-r--r-- | lib/libc/gen/login_cap.c | 111 |
1 files changed, 68 insertions, 43 deletions
diff --git a/lib/libc/gen/login_cap.c b/lib/libc/gen/login_cap.c index 3ae8ab56a57..53d965c6717 100644 --- a/lib/libc/gen/login_cap.c +++ b/lib/libc/gen/login_cap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: login_cap.c,v 1.15 2002/12/15 13:27:06 henning Exp $ */ +/* $OpenBSD: login_cap.c,v 1.16 2003/03/31 15:47:03 millert Exp $ */ /*- * Copyright (c) 1995,1997 Berkeley Software Design, Inc. All rights reserved. @@ -685,57 +685,82 @@ setusercontext(lc, pwd, uid, flags) return (0); } +/* + * Look up "path" for this user in login.conf and replace whitespace + * with ':' and "~/" with "$HOME/" at the beginning of entries. Sets + * the PATH environment variable to the result or _PATH_DEFPATH on error. + */ static int setuserpath(lc, home) login_cap_t *lc; char *home; { - int hlen, plen, error; - int cnt = 0; - char *path; - char *p, *savep; - char *q, *saveq = NULL; - - hlen = strlen(home); - - if ((savep = p = path = login_getcapstr(lc, "path", NULL, NULL))) { - while (*p) - if (*p++ == '~') - ++cnt; - plen = (p - path) + cnt * (hlen + 1) + 1; - p = path; - if ((saveq = q = path = malloc(plen))) { - while (*p) { - p += strspn(p, " \t"); - if (*p == '\0') - break; - plen = strcspn(p, " \t"); - if (hlen == 0 && *p == '~') { - p += plen; - continue; - } - if (q != path) - *q++ = ':'; - if (*p == '~') { - strcpy(q, home); - q += hlen; - ++p; - --plen; - } - memcpy(q, p, plen); - p += plen; - q += plen; + size_t psize, n; + char *p, *path, *opath, *dst, *dend, *tmp, last; + int cnt, error; + + dst = path = NULL; + if ((opath = login_getcapstr(lc, "path", NULL, NULL)) == NULL) + goto done; + + /* Count the number of entries that begin with "~/" or consist of "~" */ + for (p = opath, cnt = 0, last = ' '; *p != '\0'; last = *p++) { + if (p[0] == '~' && (last == ' ' || last == '\t')) { + switch (p[1]) { + case '/': + p++; + /* FALLTHROUGH */ + case ' ': + case '\t': + case '\0': + cnt++; + break; } - *q = '\0'; } } - error = setenv("PATH", path ? path : _PATH_DEFPATH, 1); - - if (savep) - free(savep); - if (saveq) - free(saveq); + /* The '~' in opath counts against strlen(home), hence the decrement. */ + psize = (p - opath) + (cnt * (strlen(home) - 1)) + 1; + if ((dst = path = malloc(psize)) == NULL) + goto done; + + /* Copy path elements from opath into path, expanding ~ as we go. */ + dend = dst + psize; + for (tmp = opath; (p = strsep(&tmp, " \t")) != NULL; ) { + if (*p == '\0') + continue; + if (p[0] == '~' && (p[1] == '/' || p[1] == '\0')) { + n = strlcpy(dst, home, dend - dst); + if (n >= dend - dst) { + dst = path; + goto done; + } + dst += n; + p++; + } + if ((n = strlcpy(dst, p, dend - dst)) >= dend - dst) { + dst = path; + goto done; + } + dst += n; + *dst++ = ':'; + } + if (dst != path) + *--dst = '\0'; /* replace trailing ':' w/ a NUL */ + + /* + * Possible exit states: + * error: path == NULL, opath == NULL, dst == NULL + * error: path == NULL, opath != NULL, dst == NULL + * error: path != NULL, opath != NULL, dst == path + * good: path != NULL, opath != NULL, dst != path + */ +done: + error = setenv("PATH", (path != dst) ? path : _PATH_DEFPATH, 1); + if (opath != NULL) + free(opath); + if (path != opath) + free(path); return (error); } |