roken: Add rk_undumptext() and support ttys and such

Add rk_undumptext(), which NUL-terminates the contents it reads.

rk_undumptext(), and now also rk_undumpdata(), can read from regular and
non-regular files (e.g., ttys, pipes, devices, but -on Windows- not
sockets).

This means that `asn1_print` can now read from `/dev/stdin`, which can
be a pipe.

There's a way to set a limit on how much to read from non-regular files,
and that limit defaults to 10MB.

At any rate, the rk_dumpdata(), rk_undumpdata(), and rk_undumptext() functions
really do not belong in lib/roken but in lib/base.  There are other utility
functions in lib/roken that don't belong there too.  A rationalization of the
split between lib/roken and lib/base is overdue.  And while we're at it -lest I
forget- it'd be nice to move all the krb5_storage functions out of lib/krb5 and
into lib/base, as those could come in handy for, e.g., implementing OpenSSH
style certificates and other things outside the krb5 universe.
This commit is contained in:
Nicolas Williams
2022-12-20 22:22:06 -06:00
parent ca2467a4c4
commit 8b6926f4c0
3 changed files with 149 additions and 1 deletions

View File

@@ -51,8 +51,84 @@ rk_dumpdata (const char *filename, const void *buf, size_t size)
close(fd);
}
/* For not-regular files */
static int
undump_not_file(int fd, char **out, size_t *size, int nul_terminate)
{
size_t lim = 10 * 1024 * 1024;
size_t bufsz = 0;
size_t sz = 0;
char *buf = NULL;
char *tmp;
*out = NULL;
if (size && *size != 0 && *size < lim)
lim = *size;
if (size)
*size = 0;
/*
* We can't use net_read() if we're on WIN32 because that really wants a
* socket FD, which is in a distinct FD namespace from those returned by
* open() on Windows.
*/
do {
ssize_t bytes;
if (sz == bufsz) {
if (bufsz == 0)
bufsz = 1024;
else
bufsz += bufsz >> 1;
tmp = realloc(buf, bufsz);
if (tmp == NULL) {
free(buf);
return ENOMEM;
}
buf = tmp;
}
bytes = read(fd, buf + sz, bufsz - sz);
if (bytes == 0)
break;
if (bytes < 0 &&
(errno == EAGAIN || errno == EWOULDBLOCK))
continue;
if (bytes < 0)
return errno;
sz += bytes;
} while (sz < lim);
*out = buf;
if (size)
*size = sz;
if (!nul_terminate)
return 0;
if (bufsz > sz) {
buf[sz] = '\0';
return 0;
}
tmp = realloc(buf, bufsz + 1);
if (tmp == NULL) {
free(buf);
return ENOMEM;
}
buf = tmp;
buf[sz] = '\0';
return 0;
}
/*
* Read all data from a filename, care about errors.
* Read all data from a file, care about errors.
*
* If `*size' is not zero and the file is not a regular file, then up to that
* many bytes will be read.
*
* Returns zero on success or a system error code on failure.
*/
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
@@ -71,6 +147,14 @@ rk_undumpdata(const char *filename, void **buf, size_t *size)
ret = errno;
goto out;
}
if (!S_ISREG(sb.st_mode)) {
char *char_buf;
ret = undump_not_file(fd, &char_buf, size, 0);
(void) close(fd);
*buf = char_buf;
return ret;
}
if (sb.st_size < 0)
sb.st_size = 0;
@@ -97,3 +181,63 @@ rk_undumpdata(const char *filename, void **buf, size_t *size)
close(fd);
return ret;
}
/*
* Read all text from a file.
*
* Outputs a C string. It is up to the caller to check for embedded NULs.
* The number of bytes read will be stored in `*size' if `size' is not NULL.
*
* If `size' is not NULL and `*size' is not zero and the file is not a regular
* file, then up to that many bytes will be read.
*
* Returns zero on success or a system error code on failure.
*/
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_undumptext(const char *filename, char **out, size_t *size)
{
struct stat sb;
int fd, ret;
ssize_t sret;
char *buf;
*out = NULL;
fd = open(filename, O_RDONLY, 0);
if (fd < 0 || fstat(fd, &sb) != 0)
return errno;
if (!S_ISREG(sb.st_mode)) {
ret = undump_not_file(fd, out, size, 1);
(void) close(fd);
return ret;
}
if (sb.st_size < 0)
sb.st_size = 0;
buf = malloc(sb.st_size + 1);
if (buf == NULL) {
ret = ENOMEM;
goto out;
}
if (size)
*size = sb.st_size;
sret = read(fd, buf, sb.st_size);
if (sret < 0)
ret = errno;
else if (sret != (ssize_t)sb.st_size)
ret = EINVAL;
else
ret = 0;
out:
if (ret) {
free(buf);
} else {
buf[sb.st_size] = '\0';
*out = buf;
}
close(fd);
return ret;
}

View File

@@ -532,6 +532,9 @@ rk_dumpdata (const char *, const void *, size_t);
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_undumpdata (const char *, void **, size_t *);
ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
rk_undumptext (const char *, char **, size_t *);
ROKEN_LIB_FUNCTION void ROKEN_LIB_CALL
rk_xfree (void *);

View File

@@ -171,6 +171,7 @@ HEIMDAL_ROKEN_2.0 {
rk_tsearch;
rk_twalk;
rk_undumpdata;
rk_undumptext;
rk_unparse_flags;
rk_unparse_time;
rk_unparse_time_approx;