[BACK]Return to sftp-realpath.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/sftp-realpath.c, Revision 1.1

1.1     ! djm         1: /*     $OpenBSD: realpath.c,v 1.20 2015/10/13 20:55:37 millert Exp $ */
        !             2: /*
        !             3:  * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
        !             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. The names of the authors may not be used to endorse or promote
        !            14:  *    products derived from this software without specific prior written
        !            15:  *    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/param.h>
        !            32: #include <sys/stat.h>
        !            33:
        !            34: #include <errno.h>
        !            35: #include <stdlib.h>
        !            36: #include <stddef.h>
        !            37: #include <string.h>
        !            38: #include <unistd.h>
        !            39: #include <limits.h>
        !            40:
        !            41: #ifndef SYMLOOP_MAX
        !            42: # define SYMLOOP_MAX 32
        !            43: #endif
        !            44:
        !            45: /* XXX rewrite sftp-server to use POSIX realpath and remove this hack */
        !            46:
        !            47: char *sftp_realpath(const char *path, char *resolved);
        !            48:
        !            49: /*
        !            50:  * char *realpath(const char *path, char resolved[PATH_MAX]);
        !            51:  *
        !            52:  * Find the real name of path, by removing all ".", ".." and symlink
        !            53:  * components.  Returns (resolved) on success, or (NULL) on failure,
        !            54:  * in which case the path which caused trouble is left in (resolved).
        !            55:  */
        !            56: char *
        !            57: sftp_realpath(const char *path, char *resolved)
        !            58: {
        !            59:        struct stat sb;
        !            60:        char *p, *q, *s;
        !            61:        size_t left_len, resolved_len;
        !            62:        unsigned symlinks;
        !            63:        int serrno, slen, mem_allocated;
        !            64:        char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
        !            65:
        !            66:        if (path[0] == '\0') {
        !            67:                errno = ENOENT;
        !            68:                return (NULL);
        !            69:        }
        !            70:
        !            71:        serrno = errno;
        !            72:
        !            73:        if (resolved == NULL) {
        !            74:                resolved = malloc(PATH_MAX);
        !            75:                if (resolved == NULL)
        !            76:                        return (NULL);
        !            77:                mem_allocated = 1;
        !            78:        } else
        !            79:                mem_allocated = 0;
        !            80:
        !            81:        symlinks = 0;
        !            82:        if (path[0] == '/') {
        !            83:                resolved[0] = '/';
        !            84:                resolved[1] = '\0';
        !            85:                if (path[1] == '\0')
        !            86:                        return (resolved);
        !            87:                resolved_len = 1;
        !            88:                left_len = strlcpy(left, path + 1, sizeof(left));
        !            89:        } else {
        !            90:                if (getcwd(resolved, PATH_MAX) == NULL) {
        !            91:                        if (mem_allocated)
        !            92:                                free(resolved);
        !            93:                        else
        !            94:                                strlcpy(resolved, ".", PATH_MAX);
        !            95:                        return (NULL);
        !            96:                }
        !            97:                resolved_len = strlen(resolved);
        !            98:                left_len = strlcpy(left, path, sizeof(left));
        !            99:        }
        !           100:        if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
        !           101:                errno = ENAMETOOLONG;
        !           102:                goto err;
        !           103:        }
        !           104:
        !           105:        /*
        !           106:         * Iterate over path components in `left'.
        !           107:         */
        !           108:        while (left_len != 0) {
        !           109:                /*
        !           110:                 * Extract the next path component and adjust `left'
        !           111:                 * and its length.
        !           112:                 */
        !           113:                p = strchr(left, '/');
        !           114:                s = p ? p : left + left_len;
        !           115:                if (s - left >= (ptrdiff_t)sizeof(next_token)) {
        !           116:                        errno = ENAMETOOLONG;
        !           117:                        goto err;
        !           118:                }
        !           119:                memcpy(next_token, left, s - left);
        !           120:                next_token[s - left] = '\0';
        !           121:                left_len -= s - left;
        !           122:                if (p != NULL)
        !           123:                        memmove(left, s + 1, left_len + 1);
        !           124:                if (resolved[resolved_len - 1] != '/') {
        !           125:                        if (resolved_len + 1 >= PATH_MAX) {
        !           126:                                errno = ENAMETOOLONG;
        !           127:                                goto err;
        !           128:                        }
        !           129:                        resolved[resolved_len++] = '/';
        !           130:                        resolved[resolved_len] = '\0';
        !           131:                }
        !           132:                if (next_token[0] == '\0')
        !           133:                        continue;
        !           134:                else if (strcmp(next_token, ".") == 0)
        !           135:                        continue;
        !           136:                else if (strcmp(next_token, "..") == 0) {
        !           137:                        /*
        !           138:                         * Strip the last path component except when we have
        !           139:                         * single "/"
        !           140:                         */
        !           141:                        if (resolved_len > 1) {
        !           142:                                resolved[resolved_len - 1] = '\0';
        !           143:                                q = strrchr(resolved, '/') + 1;
        !           144:                                *q = '\0';
        !           145:                                resolved_len = q - resolved;
        !           146:                        }
        !           147:                        continue;
        !           148:                }
        !           149:
        !           150:                /*
        !           151:                 * Append the next path component and lstat() it. If
        !           152:                 * lstat() fails we still can return successfully if
        !           153:                 * there are no more path components left.
        !           154:                 */
        !           155:                resolved_len = strlcat(resolved, next_token, PATH_MAX);
        !           156:                if (resolved_len >= PATH_MAX) {
        !           157:                        errno = ENAMETOOLONG;
        !           158:                        goto err;
        !           159:                }
        !           160:                if (lstat(resolved, &sb) != 0) {
        !           161:                        if (errno == ENOENT && p == NULL) {
        !           162:                                errno = serrno;
        !           163:                                return (resolved);
        !           164:                        }
        !           165:                        goto err;
        !           166:                }
        !           167:                if (S_ISLNK(sb.st_mode)) {
        !           168:                        if (symlinks++ > SYMLOOP_MAX) {
        !           169:                                errno = ELOOP;
        !           170:                                goto err;
        !           171:                        }
        !           172:                        slen = readlink(resolved, symlink, sizeof(symlink) - 1);
        !           173:                        if (slen < 0)
        !           174:                                goto err;
        !           175:                        symlink[slen] = '\0';
        !           176:                        if (symlink[0] == '/') {
        !           177:                                resolved[1] = 0;
        !           178:                                resolved_len = 1;
        !           179:                        } else if (resolved_len > 1) {
        !           180:                                /* Strip the last path component. */
        !           181:                                resolved[resolved_len - 1] = '\0';
        !           182:                                q = strrchr(resolved, '/') + 1;
        !           183:                                *q = '\0';
        !           184:                                resolved_len = q - resolved;
        !           185:                        }
        !           186:
        !           187:                        /*
        !           188:                         * If there are any path components left, then
        !           189:                         * append them to symlink. The result is placed
        !           190:                         * in `left'.
        !           191:                         */
        !           192:                        if (p != NULL) {
        !           193:                                if (symlink[slen - 1] != '/') {
        !           194:                                        if (slen + 1 >=
        !           195:                                            (ptrdiff_t)sizeof(symlink)) {
        !           196:                                                errno = ENAMETOOLONG;
        !           197:                                                goto err;
        !           198:                                        }
        !           199:                                        symlink[slen] = '/';
        !           200:                                        symlink[slen + 1] = 0;
        !           201:                                }
        !           202:                                left_len = strlcat(symlink, left, sizeof(symlink));
        !           203:                                if (left_len >= sizeof(symlink)) {
        !           204:                                        errno = ENAMETOOLONG;
        !           205:                                        goto err;
        !           206:                                }
        !           207:                        }
        !           208:                        left_len = strlcpy(left, symlink, sizeof(left));
        !           209:                }
        !           210:        }
        !           211:
        !           212:        /*
        !           213:         * Remove trailing slash except when the resolved pathname
        !           214:         * is a single "/".
        !           215:         */
        !           216:        if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
        !           217:                resolved[resolved_len - 1] = '\0';
        !           218:        return (resolved);
        !           219:
        !           220: err:
        !           221:        if (mem_allocated)
        !           222:                free(resolved);
        !           223:        return (NULL);
        !           224: }