1*173dc874Sderaadt /* $OpenBSD: symlinks.c,v 1.7 2021/09/02 21:06:06 deraadt Exp $ */
260a32ee9Sbenno /*
360a32ee9Sbenno * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
460a32ee9Sbenno *
560a32ee9Sbenno * Permission to use, copy, modify, and distribute this software for any
660a32ee9Sbenno * purpose with or without fee is hereby granted, provided that the above
760a32ee9Sbenno * copyright notice and this permission notice appear in all copies.
860a32ee9Sbenno *
960a32ee9Sbenno * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1060a32ee9Sbenno * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1160a32ee9Sbenno * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1260a32ee9Sbenno * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1360a32ee9Sbenno * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1460a32ee9Sbenno * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1560a32ee9Sbenno * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1660a32ee9Sbenno */
1760a32ee9Sbenno
1860a32ee9Sbenno #include <assert.h>
1960a32ee9Sbenno #include <stdint.h>
2060a32ee9Sbenno #include <stdlib.h>
21*173dc874Sderaadt #include <limits.h>
2260a32ee9Sbenno #include <unistd.h>
2360a32ee9Sbenno
2460a32ee9Sbenno #include "extern.h"
2560a32ee9Sbenno
2660a32ee9Sbenno /*
2760a32ee9Sbenno * Allocate space for a readlink(2) invocation.
2860a32ee9Sbenno * Returns NULL on failure or a buffer otherwise.
2960a32ee9Sbenno * The buffer must be passed to free() by the caller.
3060a32ee9Sbenno */
3160a32ee9Sbenno char *
symlink_read(const char * path)32ba617adaSbenno symlink_read(const char *path)
3360a32ee9Sbenno {
3460a32ee9Sbenno char *buf = NULL;
3560a32ee9Sbenno size_t sz;
3660a32ee9Sbenno ssize_t nsz = 0;
3760a32ee9Sbenno void *pp;
3860a32ee9Sbenno
39*173dc874Sderaadt for (sz = PATH_MAX; ; sz *= 2) {
40f1dcb30aSderaadt if ((pp = realloc(buf, sz + 1)) == NULL) {
41b2a7eac7Sbenno ERR("realloc");
4260a32ee9Sbenno free(buf);
4360a32ee9Sbenno return NULL;
4460a32ee9Sbenno }
4560a32ee9Sbenno buf = pp;
4660a32ee9Sbenno
47f1dcb30aSderaadt if ((nsz = readlink(path, buf, sz)) == -1) {
48b2a7eac7Sbenno ERR("%s: readlink", path);
4960a32ee9Sbenno free(buf);
5060a32ee9Sbenno return NULL;
51f1dcb30aSderaadt } else if (nsz == 0) {
52b2a7eac7Sbenno ERRX("%s: empty link", path);
5360a32ee9Sbenno free(buf);
5460a32ee9Sbenno return NULL;
5560a32ee9Sbenno } else if ((size_t)nsz < sz)
5660a32ee9Sbenno break;
5760a32ee9Sbenno }
5860a32ee9Sbenno
59f1dcb30aSderaadt assert(buf != NULL);
6060a32ee9Sbenno assert(nsz > 0);
6160a32ee9Sbenno buf[nsz] = '\0';
6260a32ee9Sbenno return buf;
6360a32ee9Sbenno }
6460a32ee9Sbenno
6560a32ee9Sbenno /*
6660a32ee9Sbenno * Allocate space for a readlinkat(2) invocation.
6760a32ee9Sbenno * Returns NULL on failure or a buffer otherwise.
6860a32ee9Sbenno * The buffer must be passed to free() by the caller.
6960a32ee9Sbenno */
7060a32ee9Sbenno char *
symlinkat_read(int fd,const char * path)71ba617adaSbenno symlinkat_read(int fd, const char *path)
7260a32ee9Sbenno {
7360a32ee9Sbenno char *buf = NULL;
7460a32ee9Sbenno size_t sz;
7560a32ee9Sbenno ssize_t nsz = 0;
7660a32ee9Sbenno void *pp;
7760a32ee9Sbenno
78*173dc874Sderaadt for (sz = PATH_MAX; ; sz *= 2) {
79f1dcb30aSderaadt if ((pp = realloc(buf, sz + 1)) == NULL) {
80b2a7eac7Sbenno ERR("realloc");
8160a32ee9Sbenno free(buf);
8260a32ee9Sbenno return NULL;
8360a32ee9Sbenno }
8460a32ee9Sbenno buf = pp;
8560a32ee9Sbenno
86f1dcb30aSderaadt if ((nsz = readlinkat(fd, path, buf, sz)) == -1) {
87b2a7eac7Sbenno ERR("%s: readlinkat", path);
8860a32ee9Sbenno free(buf);
8960a32ee9Sbenno return NULL;
90f1dcb30aSderaadt } else if (nsz == 0) {
91b2a7eac7Sbenno ERRX("%s: empty link", path);
9260a32ee9Sbenno free(buf);
9360a32ee9Sbenno return NULL;
9460a32ee9Sbenno } else if ((size_t)nsz < sz)
9560a32ee9Sbenno break;
9660a32ee9Sbenno }
9760a32ee9Sbenno
98f1dcb30aSderaadt assert(buf != NULL);
9960a32ee9Sbenno assert(nsz > 0);
10060a32ee9Sbenno buf[nsz] = '\0';
10160a32ee9Sbenno return buf;
10260a32ee9Sbenno }
103