Compare commits

...

7 Commits

Author SHA1 Message Date
Jonas 'Sortie' Termansen 4ac7072f2a Add AI_ADDRCONFIG to getaddrinfo(3). 2023-03-19 21:56:54 +01:00
Jonas 'Sortie' Termansen c57ff050e9 Add include and comment support to passwd(5) and group(5). 2023-03-19 21:53:21 +01:00
Jonas 'Sortie' Termansen da86ca1873 Fix typo in ssh instructions in installation(7). 2023-03-19 11:08:01 +01:00
Jonas 'Sortie' Termansen e9877d8080 Fix fmemopen(3) fseeko(3) overflow detection. 2023-03-19 11:08:01 +01:00
Jonas 'Sortie' Termansen 03ee6d4d89 Update to libressl-3.7.1. 2023-03-16 11:11:33 +01:00
Jonas 'Sortie' Termansen 98c92bcdcc Update to openssh-9.3p1. 2023-03-16 10:49:47 +01:00
Jonas 'Sortie' Termansen 47e1cc439a Add glob(3).
Switch sh(1) to use glob(3).

Remove compatibility for no glob(3) from the ports.
2023-03-16 00:20:43 +01:00
29 changed files with 1094 additions and 539 deletions

View File

@ -447,7 +447,9 @@ $(LIVE_INITRD): sysroot
mkdir -p $(LIVE_INITRD).d/etc/init
echo require single-user exit-code > $(LIVE_INITRD).d/etc/init/default
echo "root::0:0:root:/root:sh" > $(LIVE_INITRD).d/etc/passwd
echo "include /etc/default/passwd.d/*" >> $(LIVE_INITRD).d/etc/passwd
echo "root::0:root" > $(LIVE_INITRD).d/etc/group
echo "include /etc/default/group.d/*" >> $(LIVE_INITRD).d/etc/group
mkdir -p $(LIVE_INITRD).d/home
mkdir -p $(LIVE_INITRD).d/root -m 700
cp -RT "$(SYSROOT)/etc/skel" $(LIVE_INITRD).d/root

View File

@ -367,6 +367,8 @@ fstab/scanfsent.o \
fstab/setfsent.o \
getopt/getopt_long.o \
getopt/getopt.o \
glob/glob.o \
glob/globfree.o \
grp/endgrent.o \
grp/fgetgrent.o \
grp/fgetgrent_r.o \
@ -476,7 +478,9 @@ pwd/getpwnam.o \
pwd/getpwnam_r.o \
pwd/getpwuid.o \
pwd/getpwuid_r.o \
pwd/__openent.o \
pwd/openpw.o \
pwd/scanpwent.o \
pwd/setpwent.o \
sched/sched_yield.o \
pty/openpty.o \

474
libc/glob/glob.c Normal file
View File

@ -0,0 +1,474 @@
/*
* Copyright (c) 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* glob/glob.c
* Search for paths matching a pattern.
*/
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <regex.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int strcoll_indirect(const void* a_ptr, const void* b_ptr)
{
const char* a = *(const char* const*) a_ptr;
const char* b = *(const char* const*) b_ptr;
return strcoll(a, b);
}
struct segment
{
char* prefix;
size_t prefix_length;
DIR* dir;
bool trivial;
bool leading_period;
bool match_directory;
bool done;
union
{
struct
{
size_t start;
size_t length;
};
regex_t regex;
};
};
int glob(const char* restrict pattern,
int flags,
int (*errfunc)(const char*, int),
glob_t* restrict gl)
{
if ( !(flags & GLOB_DOOFFS) )
gl->gl_offs = 0;
if ( !(flags & GLOB_APPEND) )
{
gl->gl_pathv = NULL;
gl->gl_pathc = 0;
}
if ( gl->gl_offs == SIZE_MAX )
return GLOB_NOSPACE;
size_t initial_pathc = gl->gl_pathc;
// Reserve room for at least one string and the trailing null to prevent
// the possibly of late errors in the GLOB_NOCHECK case.
size_t pathl;
if ( __builtin_add_overflow(gl->gl_offs, gl->gl_pathc, &pathl) ||
__builtin_add_overflow(pathl, 2, &pathl) )
return GLOB_NOSPACE;
char** new_pathv = reallocarray(gl->gl_pathv, pathl, sizeof(char*));
if ( !new_pathv )
return GLOB_NOSPACE;
gl->gl_pathv = new_pathv;
size_t paths_length = gl->gl_pathc + 1;
// Parse the pattern into segments where trivial segments are fixed path
// components that can be directly opened and non-trivial segments require
// searching a directory for entries that match the pattern.
struct segment* segments = NULL;
size_t segments_count = 0;
size_t segments_length = 0;
int result = 0;
for ( size_t offset = 0; pattern[offset] && !result; )
{
// Combine multiple trivial path components into a trivial segment, but
// each non-trivial path component must be its own segment.
size_t segment_length = 0;
bool is_trivial = true;
for ( size_t i = 0; pattern[offset + i]; i++ )
{
if ( pattern[offset + i] == '*' ||
pattern[offset + i] == '?' ||
pattern[offset + i] == '[' )
{
if ( segment_length )
break;
is_trivial = false;
}
if ( pattern[offset + i] == '/' || !pattern[offset + i + 1] )
{
segment_length = i + 1;
if ( !is_trivial )
break;
}
}
// Grow the list of segments as needed.
if ( segments_count == segments_length )
{
size_t old_length = segments_length ? segments_length : 1;
struct segment* new_segments =
reallocarray(segments, old_length, 2 * sizeof(struct segment));
if ( !new_segments )
{
result = GLOB_NOSPACE;
break;
}
segments = new_segments;
segments_length = 2 * old_length;
}
struct segment* segment = &segments[segments_count++];
segment->match_directory = pattern[offset + segment_length - 1] == '/';
// Trivial segments just contain the pattern indices to directly open.
if ( (segment->trivial = is_trivial) )
{
segment->start = offset;
segment->length = segment_length;
}
// Non-trivial segments are translated to a regular expression that is
// compiled right now so it can be efficiently reused during the search.
else
{
// Match a leading period only if the pattern explicitly starts with
// a period. POSIX requires that leading periods aren't matched by
// the * and ? and [ operators, but also are not matched by negated
// patterns like [^a]. It's unspecified whether [.] would match a
// leading period. Although regular expressions can express such
// patterns, it's difficult to translate, and it's much easier to
// just special case the leading period like this.
segment->leading_period = pattern[offset] == '.';
char* re = NULL;
size_t re_size;
FILE* fp = open_memstream(&re, &re_size);
bool escaped = false;
fputc('^', fp);
// Translate the pattern to an extended regular expression.
for ( size_t i = 0; fp && i < segment_length; i++ )
{
unsigned char c = pattern[offset + i];
if ( !escaped && c == '*' )
fputs(".*", fp);
else if ( !escaped && c == '?' )
fputs(".", fp);
else if ( !escaped && c == '[' )
{
// The whole character range is passed directly to regcomp
// so the correct end just has to be found, taking the edge
// cases into account. POSIX requires using ! instead of ^
// for character range negations. As an extension, ^ is
// also just passed directly to regcomp and works.
const char* expr = pattern + offset + i;
size_t max = segment_length - i;
size_t len = 1;
if ( len < max && (expr[len] == '!' || expr[len] == '^') )
len++;
if ( len < max && expr[len] == ']' )
len++;
while ( len < max && expr[len] != ']' )
{
if ( 2 <= max - len && expr[len] == '[' &&
(expr[len + 1] == '.' || expr[len + 1] == '=' ||
expr[len + 1] == ':' ) )
{
char t = expr[len + 1];
len += 2;
while ( 2 <= max - len &&
!(expr[len] == t && expr[len + 1] == ']') )
len++;
len += max - len < 2 ? max - len : 2;
}
else
len++;
}
if ( len < max && expr[len] == ']' )
{
for ( size_t n = 0; n <= len; n++ )
{
if ( n == 1 && expr[n] == '!' )
fputc('^', fp);
else
fputc((unsigned char) expr[n], fp);
}
i += len;
}
else
fputs("\\[", fp);
}
else if ( !escaped && c == '\\' && !(flags & GLOB_NOESCAPE) )
escaped = true;
else if ( c != '/' )
{
if ( c == '\\' || c == '(' || c == ')' || c == '{' ||
c == '}' || c == '.' || c == '*' || c == '[' ||
c == ']' || c == '^' || c == '$' || c == '+' ||
c == '?' || c == '|' )
fputc('\\', fp);
fputc(c, fp);
escaped = false;
}
}
fputc('$', fp);
if ( !fp || ferror(fp) || fflush(fp) == EOF )
{
if ( fp )
fclose(fp);
free(re);
result = GLOB_NOSPACE;
segments_count--;
break;
}
fclose(fp);
// Compile and reuse the regular expression for this segment.
int ret = regcomp(&segment->regex, re, REG_EXTENDED);
free(re);
if ( ret )
{
result = GLOB_NOSPACE;
segments_count--;
break;
}
}
offset += segment_length;
}
// Start the search with the first segment.
if ( !result && segments_count )
{
segments[0].prefix = NULL;
segments[0].prefix_length = 0;
segments[0].dir = NULL;
segments[0].done = false;
// If the first segment is non-trivial then the current working
// directory needs to be opened and searched.
if ( !segments[0].trivial && !(segments[0].dir = opendir(".")) )
{
if ( errno == ENOMEM )
result = GLOB_NOSPACE;
else if ( (errfunc && errfunc(".", errno)) || (flags & GLOB_ERR) )
result = GLOB_ABORTED;
else
segments[0].done = true;
}
}
// Search the filesystem depth first for paths matching the pattern. The
// segments array is used for the hierarchical state to avoid recursion.
// Each active segment has a directory currently being searched and yields
// paths to be explored by the subsequent segment. The last segment adds
// paths to the output array if they match the pattern. The search is
// complete when the outermost segment is done or has failed.
size_t current_segment = 0;
while ( segments_count &&
(current_segment || !(segments[0].done || result) ))
{
struct segment* segment = &segments[current_segment];
// Pop to the the parent segment if the directory has been searched or
// if an error has happened and the search is aborting.
if ( segment->done || result )
{
free(segment->prefix);
segment->prefix = NULL;
if ( segment->dir )
closedir(segment->dir);
current_segment--;
continue;
}
char* name;
size_t name_length;
unsigned char type = DT_UNKNOWN;
// A trivial segment yields only the singular path it can match.
if ( segment->trivial )
{
name = strndup(pattern + segment->start, segment->length);
name_length = segment->length;
segment->done = true;
}
// Search the directory for entries matching the pattern.
else
{
errno = 0;
struct dirent* entry = readdir(segment->dir);
if ( !entry )
{
const char* path = segment->prefix ? segment->prefix : ".";
if ( errno == ENOMEM )
result = GLOB_NOSPACE;
else if ( (errfunc && errfunc(path, errno)) ||
(flags & GLOB_ERR) )
result = GLOB_ABORTED;
segment->done = true;
continue;
}
// Skip known non-directories when a directory needs to be found.
if ( (current_segment + 1 < segments_count ||
segment->match_directory) &&
entry->d_type != DT_UNKNOWN &&
entry->d_type != DT_DIR &&
entry->d_type != DT_LNK )
continue;
if ( !strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..") )
continue;
if ( entry->d_name[0] == '.' && !segment->leading_period )
continue;
if ( regexec(&segment->regex, entry->d_name, 0, NULL, 0) )
continue;
name = strdup(entry->d_name);
name_length = strlen(entry->d_name);
type = entry->d_type;
}
if ( !name )
{
result = GLOB_NOSPACE;
continue;
}
// Append the segment's prefix with the name but keep an extra byte for
// a possible trailing slash and of course the terminating nul byte.
size_t size = 0;
if ( __builtin_add_overflow(segment->prefix_length, name_length,
&size) ||
__builtin_add_overflow(size, 1 + 1, &size) )
{
free(name);
result = GLOB_NOSPACE;
continue;
}
char* path = malloc(size);
if ( !path )
{
free(name);
free(path);
result = GLOB_NOSPACE;
continue;
}
if ( segment->prefix_length )
memcpy(path, segment->prefix, segment->prefix_length);
memcpy(path + segment->prefix_length, name, name_length);
path[segment->prefix_length + name_length] = '\0';
int fd = segment->dir ? dirfd(segment->dir) : AT_FDCWD;
// If this is not the last segment, push to the next segment to search
// the directory just found.
if ( current_segment + 1 < segments_count )
{
struct segment* next_segment = &segments[current_segment + 1];
int mode = next_segment->trivial ? O_SEARCH : O_RDONLY;
int subdirfd = openat(fd, name, mode | O_DIRECTORY | O_CLOEXEC);
free(name);
next_segment->dir = subdirfd < 0 ? NULL : fdopendir(subdirfd);
if ( !next_segment->dir )
{
if ( 0 <= subdirfd )
close(subdirfd);
if ( errno != ENOENT && errno != ENOTDIR &&
((errfunc && errfunc(path, errno)) || (flags & GLOB_ERR)) )
result = GLOB_ABORTED;
free(path);
continue;
}
next_segment->prefix = path;
next_segment->prefix_length = size - 2;
// Add a trailing slash to the searched directory entries.
if ( !segment->trivial )
{
next_segment->prefix[next_segment->prefix_length++] = '/';
next_segment->prefix[next_segment->prefix_length] = '\0';
}
next_segment->done = false;
current_segment++;
continue;
}
// The last segment just needs to output paths if they exist.
else
{
bool want_slash = (flags & GLOB_MARK) || segment->match_directory;
bool exists = true, is_dir = false;
// The path is known to already exist for non-trivial segments since
// it was returned by readdir, but we may need to check if the path
// is a directory if readdir didn't tell us already.
if ( !segment->trivial &&
(!want_slash || (type != DT_UNKNOWN && type != DT_LNK)) )
is_dir = type == DT_DIR;
// Just check if the path exists if we don't add slashes to dirs.
else if ( !want_slash )
exists = !faccessat(fd, name, F_OK, AT_SYMLINK_NOFOLLOW);
// Otherwise use the slower stat operation to obtain the inode type.
else
{
struct stat st;
exists = !fstatat(fd, name, &st, AT_SYMLINK_NOFOLLOW);
if ( want_slash && S_ISLNK(st.st_mode) )
fstatat(fd, name, &st, 0);
is_dir = S_ISDIR(st.st_mode);
}
free(name);
if ( segment->match_directory && !is_dir )
{
free(path);
continue;
}
if ( want_slash && path[size - 3] != '/' )
path[size - 2] = '/', path[size - 1] = '\0';
if ( !exists )
{
if ( errno != ENOENT &&
((errfunc && errfunc(path, errno)) || (flags & GLOB_ERR)) )
result = GLOB_ABORTED;
free(path);
continue;
}
// Grow the output array as needed.
if ( gl->gl_pathc == paths_length )
{
size_t old_pathc = gl->gl_pathc ? gl->gl_pathc : 1;
if ( __builtin_mul_overflow(2, old_pathc, &pathl) ||
__builtin_add_overflow(gl->gl_offs, pathl, &pathl) ||
__builtin_add_overflow(1, pathl, &pathl) ||
!(new_pathv = reallocarray(gl->gl_pathv, pathl,
sizeof(char*))) )
{
free(path);
result = GLOB_NOSPACE;
continue;
}
gl->gl_pathv = new_pathv;
paths_length = old_pathc * 2;
}
gl->gl_pathv[gl->gl_offs + gl->gl_pathc++] = path;
}
}
// Clean up the segments and free the compiled regular expressions.
if ( segments_count && segments[0].dir )
closedir(segments[0].dir);
for ( size_t i = 0; i < segments_count; i++ )
if ( !segments[i].trivial )
regfree(&segments[i].regex);
free(segments);
// Output the input pattern if nothing matched when GLOB_NOCHECK.
if ( !result && gl->gl_pathc == initial_pathc )
{
if ( (flags & GLOB_NOCHECK) )
{
if ( (gl->gl_pathv[gl->gl_offs] = strdup(pattern)) )
gl->gl_pathc = 1;
else
result = GLOB_NOSPACE;
}
else
result = GLOB_NOMATCH;
}
// Sort the new entries per LC_COLLATE per POSIX.
if ( !(flags & GLOB_NOSORT) )
qsort(gl->gl_pathv + gl->gl_offs + initial_pathc,
gl->gl_pathc - initial_pathc, sizeof(char*),
strcoll_indirect);
gl->gl_pathv[gl->gl_offs + gl->gl_pathc] = NULL;
return result;
}

28
libc/glob/globfree.c Normal file
View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* glob/globfree.c
* Free allocate glob storage.
*/
#include <glob.h>
#include <stdlib.h>
void globfree(glob_t* gl)
{
for ( size_t i = 0; i < gl->gl_pathc; i++ )
free(gl->gl_pathv[gl->gl_offs + i]);
free(gl->gl_pathv);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -18,9 +18,10 @@
*/
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
FILE* opengr(void)
{
return fopen("/etc/group", "r");
return __openent("/etc/group");
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -24,8 +24,9 @@ FILE* __grp_file = NULL;
void setgrent(void)
{
if ( __grp_file )
FILE* new_file = opengr();
if ( !new_file && __grp_file )
rewind(__grp_file);
else
__grp_file = opengr();
__grp_file = new_file;
}

62
libc/include/glob.h Normal file
View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* glob.h
* Search for paths matching a pattern.
*/
#ifndef _INCLUDE_GLOB_H
#define _INCLUDE_GLOB_H
#include <sys/cdefs.h>
#ifndef __size_t_defined
#define __size_t_defined
#define __need_size_t
#include <stddef.h>
#endif
typedef struct
{
size_t gl_pathc;
char** gl_pathv;
size_t gl_offs;
} glob_t;
#define GLOB_APPEND (1 << 0)
#define GLOB_DOOFFS (1 << 1)
#define GLOB_ERR (1 << 2)
#define GLOB_MARK (1 << 3)
#define GLOB_NOCHECK (1 << 4)
#define GLOB_NOESCAPE (1 << 5)
#define GLOB_NOSORT (1 << 6)
#define GLOB_ABORTED 1
#define GLOB_NOMATCH 2
#define GLOB_NOSPACE 3
#ifdef __cplusplus
extern "C" {
#endif
int glob(const char* __restrict, int, int (*)(const char *, int),
glob_t* __restrict);
void globfree(glob_t*);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -62,6 +62,8 @@ struct passwd
#if defined(__is_sortix_libc)
extern FILE* __pwd_file;
FILE* __openent(const char*);
#endif
int bcrypt_newhash(const char*, int, char*, size_t);
@ -79,6 +81,7 @@ int getpwnam_r(const char* __restrict, struct passwd* __restrict,
struct passwd* getpwuid(uid_t);
int getpwuid_r(uid_t, struct passwd* __restrict, char* __restrict, size_t,
struct passwd** __restrict);
int scanpwent(char* __restrict, struct passwd* __restrict);
FILE* openpw(void);
void setpwent(void);

View File

@ -408,7 +408,9 @@ int getaddrinfo(const char* restrict node,
}
// TODO: Implement missing flags.
int supported = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV | AI_CANONNAME;
// TODO: Revisit AI_ADDRCONFIG when IPv6 is implemented.
int supported = AI_PASSIVE | AI_NUMERICHOST | AI_NUMERICSERV |
AI_CANONNAME | AI_ADDRCONFIG;
if ( flags & ~supported )
return EAI_BADFLAGS;

104
libc/pwd/__openent.c Normal file
View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* pwd/__openent.c
* Preprocesses include statements in an entry database.
*/
#include <ctype.h>
#include <errno.h>
#include <glob.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
bool __openent_append(FILE* out, const char* path)
{
FILE* fp = fopen(path, "r");
if ( !fp )
return false;
char* line = NULL;
size_t size = 0;
ssize_t amount;
bool success = true;
while ( success && 0 < (amount = getline(&line, &size, fp)) )
{
size_t length = amount;
size_t offset = 0;
while ( offset < length && isspace((unsigned char) line[offset]) )
offset++;
if ( !line[offset] || line[offset] == '#' )
continue;
size_t include_length = strlen("include");
if ( !strncmp(line + offset, "include", include_length) &&
isspace((unsigned char) line[offset + include_length]) )
{
while ( length && isspace((unsigned char) line[length - 1]) )
line[--length] = '\0';
offset = offset + include_length;
while ( offset < length && isspace((unsigned char) line[offset]) )
offset++;
const char* pattern = line + offset;
glob_t gl;
if ( !glob(pattern, GLOB_NOCHECK, NULL, &gl) )
{
for ( size_t i = 0; success && i < gl.gl_pathc; i++ )
if ( !__openent_append(out, gl.gl_pathv[i]) &&
errno != ENOENT )
success = false;
}
else
success = false;
globfree(&gl);
continue;
}
if ( fwrite(line, 1, length, out) != length )
success = false;
}
free(line);
if ( ferror(fp) )
success = false;
fclose(fp);
return success;
}
FILE* __openent(const char* path)
{
char* data;
size_t size;
FILE* memstream = open_memstream(&data, &size);
if ( !memstream )
return NULL;
if ( !__openent_append(memstream, path) ||
ferror(memstream) || fflush(memstream) == EOF )
{
fclose(memstream);
free(data);
return NULL;
}
fclose(memstream);
size = strlen(data);
FILE* result = fmemopen(NULL, size, "r+");
if ( !result )
return free(data), NULL;
size_t amount = fwrite(data, 1, size, result);
free(data);
if ( amount != size || fflush(result) == EOF )
return fclose(result), NULL;
rewind(result);
return result;
}

View File

@ -17,70 +17,9 @@
* Reads a passwd entry from a FILE.
*/
#include <sys/types.h>
#include <errno.h>
#include <inttypes.h>
#include <pwd.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static char* next_field(char** current)
{
char* result = *current;
if ( result )
{
char* next = result;
while ( *next && *next != ':' )
next++;
if ( !*next )
next = NULL;
else
*next++ = '\0';
*current = next;
}
return result;
}
static bool next_field_uintmax(char** current, uintmax_t* result)
{
char* id_str = next_field(current);
if ( !id_str )
return false;
char* id_endptr;
uintmax_t id_umax = strtoumax(id_str, &id_endptr, 10);
if ( *id_endptr )
return false;
*result = id_umax;
return true;
}
static bool next_field_gid(char** current, gid_t* result)
{
uintmax_t id_umax;
if ( !next_field_uintmax(current, &id_umax) )
return false;
gid_t gid = (gid_t) id_umax;
if ( (uintmax_t) gid != (uintmax_t) id_umax )
return false;
*result = gid;
return true;
}
static bool next_field_uid(char** current, uid_t* result)
{
uintmax_t id_umax;
if ( !next_field_uintmax(current, &id_umax) )
return false;
uid_t uid = (uid_t) id_umax;
if ( (uintmax_t) uid != (uintmax_t) id_umax )
return false;
*result = uid;
return true;
}
int fgetpwent_r(FILE* restrict fp,
struct passwd* restrict result,
@ -144,22 +83,7 @@ int fgetpwent_r(FILE* restrict fp,
}
buf[buf_used] = '\0';
char* parse_str = buf;
if ( !(result->pw_name = next_field(&parse_str)) )
goto parse_failure;
if ( !(result->pw_passwd = next_field(&parse_str)) )
goto parse_failure;
if ( !next_field_uid(&parse_str, &result->pw_uid) )
goto parse_failure;
if ( !next_field_gid(&parse_str, &result->pw_gid) )
goto parse_failure;
if ( !(result->pw_gecos = next_field(&parse_str)) )
goto parse_failure;
if ( !(result->pw_dir = next_field(&parse_str)) )
goto parse_failure;
if ( !(result->pw_shell = next_field(&parse_str)) )
goto parse_failure;
if ( parse_str )
if ( !scanpwent(buf, result) )
goto parse_failure;
funlockfile(fp);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -22,5 +22,5 @@
FILE* openpw(void)
{
return fopen("/etc/passwd", "r");
return __openent("/etc/passwd");
}

94
libc/pwd/scanpwent.c Normal file
View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2013, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* pwd/scanfpwent.c
* Parse passwd entry.
*/
#include <ctype.h>
#include <inttypes.h>
#include <pwd.h>
#include <stdbool.h>
#include <stddef.h>
static char* next_field(char** current)
{
char* result = *current;
if ( result )
{
char* next = result;
while ( *next && *next != ':' )
next++;
if ( !*next )
next = NULL;
else
*next++ = '\0';
*current = next;
}
return result;
}
static bool next_field_uintmax(char** current, uintmax_t* result)
{
char* id_str = next_field(current);
if ( !id_str )
return false;
char* id_endptr;
uintmax_t id_umax = strtoumax(id_str, &id_endptr, 10);
if ( *id_endptr )
return false;
*result = id_umax;
return true;
}
static bool next_field_gid(char** current, gid_t* result)
{
uintmax_t id_umax;
if ( !next_field_uintmax(current, &id_umax) )
return false;
gid_t gid = (gid_t) id_umax;
if ( (uintmax_t) gid != (uintmax_t) id_umax )
return false;
*result = gid;
return true;
}
static bool next_field_uid(char** current, uid_t* result)
{
uintmax_t id_umax;
if ( !next_field_uintmax(current, &id_umax) )
return false;
uid_t uid = (uid_t) id_umax;
if ( (uintmax_t) uid != (uintmax_t) id_umax )
return false;
*result = uid;
return true;
}
int scanpwent(char* str, struct passwd* passwd)
{
while ( *str && isspace((unsigned char) *str) )
str++;
if ( !*str || *str == '#' ||
!(passwd->pw_name = next_field(&str)) ||
!(passwd->pw_passwd = next_field(&str)) ||
!next_field_uid(&str, &passwd->pw_uid) ||
!next_field_gid(&str, &passwd->pw_gid) ||
!(passwd->pw_gecos = next_field(&str)) ||
!(passwd->pw_dir = next_field(&str)) ||
!(passwd->pw_shell = next_field(&str)) )
return 0;
return 1;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2013, 2015, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -24,8 +24,9 @@ FILE* __pwd_file = NULL;
void setpwent(void)
{
if ( __pwd_file )
FILE* new_file = openpw();
if ( !new_file && __pwd_file )
rewind(__pwd_file);
else
__pwd_file = openpw();
__pwd_file = new_file;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2014, 2015, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -114,7 +114,7 @@ static off_t fmemopen_seek(void* state_ptr, off_t offset, int whence)
case SEEK_END: base = (off_t) state->buffer_used; break;
default: return errno = EINVAL, -1;
}
if ( offset < -base || base - (off_t) state->buffer_size < offset )
if ( offset < -base || (off_t) state->buffer_size - base < offset )
return errno = EOVERFLOW, -1;
return (off_t) (state->buffer_offset = (size_t) (base + offset));
}

View File

@ -12,7 +12,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
#include <ctype.h>
#include <err.h>
@@ -468,8 +471,12 @@
@@ -467,8 +470,12 @@
} else {
strlcpy(unix_dg_tmp_socket_buf, "/tmp/nc.XXXXXXXXXX",
UNIX_DG_TMP_SOCKET_SIZE);
@ -26,7 +26,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
unix_dg_tmp_socket = unix_dg_tmp_socket_buf;
}
}
@@ -1403,7 +1410,8 @@
@@ -1385,7 +1392,8 @@
memset(&cmsgbuf, 0, sizeof(cmsgbuf));
memset(&iov, 0, sizeof(iov));
@ -36,7 +36,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
mh.msg_controllen = sizeof(cmsgbuf.buf);
cmsg = CMSG_FIRSTHDR(&mh);
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
@@ -1440,6 +1448,7 @@
@@ -1422,6 +1430,7 @@
void
atelnet(int nfd, unsigned char *buf, unsigned int size)
{
@ -44,7 +44,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
unsigned char *p, *end;
unsigned char obuf[4];
@@ -1465,6 +1474,9 @@
@@ -1447,6 +1456,9 @@
if (atomicio(vwrite, nfd, obuf, 3) != 3)
warn("Write Error!");
}
@ -54,7 +54,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
}
int
@@ -1578,16 +1590,20 @@
@@ -1590,16 +1602,20 @@
err(1, NULL);
}
if (Tflag != -1) {
@ -77,7 +77,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
errno = ENOPROTOOPT;
err(1, "set IPv6 traffic class not supported");
}
@@ -1605,13 +1621,16 @@
@@ -1617,13 +1633,16 @@
}
if (ttl != -1) {
@ -96,7 +96,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
}
if (minttl != -1) {
@@ -1649,7 +1668,9 @@
@@ -1661,7 +1680,9 @@
{ "af41", IPTOS_DSCP_AF41 },
{ "af42", IPTOS_DSCP_AF42 },
{ "af43", IPTOS_DSCP_AF43 },
@ -106,7 +106,7 @@ diff -Paur --no-dereference -- libssl.upstream/apps/nc/netcat.c libssl/apps/nc/n
{ "cs0", IPTOS_DSCP_CS0 },
{ "cs1", IPTOS_DSCP_CS1 },
{ "cs2", IPTOS_DSCP_CS2 },
@@ -1659,11 +1680,21 @@
@@ -1671,11 +1692,21 @@
{ "cs6", IPTOS_DSCP_CS6 },
{ "cs7", IPTOS_DSCP_CS7 },
{ "ef", IPTOS_DSCP_EF },
@ -214,6 +214,20 @@ diff -Paur --no-dereference -- libssl.upstream/apps/openssl/s_socket.c libssl/ap
static int init_server(int *sock, int port, int type);
static int init_server_long(int *sock, int port, char *ip, int type);
static int do_accept(int acc_sock, int *sock);
diff -Paur --no-dereference -- libssl.upstream/configure libssl/configure
--- libssl.upstream/configure
+++ libssl/configure
@@ -11775,6 +11775,10 @@
HOST_OS=midipix
CPPFLAGS="$CPPFLAGS -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_SOURCE -D_GNU_SOURCE"
;;
+ *sortix*)
+ HOST_OS=sortix
+ HOST_ABI=elf
+ ;;
*netbsd*)
HOST_OS=netbsd
HOST_ABI=elf
diff -Paur --no-dereference -- libssl.upstream/crypto/bio/b_sock.c libssl/crypto/bio/b_sock.c
--- libssl.upstream/crypto/bio/b_sock.c
+++ libssl/crypto/bio/b_sock.c

View File

@ -1,10 +1,10 @@
NAME=libssl
BUILD_LIBRARIES=
VERSION=3.7.0
VERSION=3.7.1
DISTNAME=libressl-$VERSION
COMPRESSION=tar.gz
ARCHIVE=$DISTNAME.$COMPRESSION
SHA256SUM=3fc1290f4007ec75f6e9acecbb25512630d1b9ab8c53ba79844e395868c3e006
SHA256SUM=98086961a2b8b657ed0fea3056fb2db14294b6bfa193c15a5236a0a35c843ded
UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/LibreSSL
UPSTREAM_ARCHIVE=$ARCHIVE
LICENSE=OpenSSL

View File

@ -157,77 +157,3 @@ diff -Paur --no-dereference -- libxml2.upstream/nanohttp.c libxml2/nanohttp.c
{
struct hostent *h;
struct in_addr ia;
diff -Paur --no-dereference -- libxml2.upstream/runtest.c libxml2/runtest.c
--- libxml2.upstream/runtest.c
+++ libxml2/runtest.c
@@ -198,6 +198,33 @@
}
}
+#elif defined(__sortix__)
+
+typedef struct
+{
+ size_t gl_pathc; /* Count of paths matched so far */
+ char **gl_pathv; /* List of matched pathnames. */
+ size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
+} glob_t;
+
+#define GLOB_DOOFFS 0
+static int glob(const char *pattern, int flags,
+ int errfunc(const char *epath, int eerrno),
+ glob_t *pglob) {
+ (void) pattern;
+ (void) flags;
+ (void) errfunc;
+ (void) pglob;
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ pglob->gl_offs = 0;
+ return -1;
+}
+
+static void globfree(glob_t *pglob) {
+ (void) pglob;
+}
+
#else
#include <glob.h>
#endif
diff -Paur --no-dereference -- libxml2.upstream/testrecurse.c libxml2/testrecurse.c
--- libxml2.upstream/testrecurse.c
+++ libxml2/testrecurse.c
@@ -146,6 +146,33 @@
}
}
+#elif defined(__sortix__)
+
+typedef struct
+{
+ size_t gl_pathc; /* Count of paths matched so far */
+ char **gl_pathv; /* List of matched pathnames. */
+ size_t gl_offs; /* Slots to reserve in 'gl_pathv'. */
+} glob_t;
+
+#define GLOB_DOOFFS 0
+static int glob(const char *pattern, int flags,
+ int errfunc(const char *epath, int eerrno),
+ glob_t *pglob) {
+ (void) pattern;
+ (void) flags;
+ (void) errfunc;
+ (void) pglob;
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ pglob->gl_offs = 0;
+ return -1;
+}
+
+static void globfree(glob_t *pglob) {
+ (void) pglob;
+}
+
#else
#include <glob.h>
#endif

View File

@ -313,7 +313,7 @@ diff -Paur --no-dereference -- mdocml.upstream/eqn.c mdocml/eqn.c
diff -Paur --no-dereference -- mdocml.upstream/main.c mdocml/main.c
--- mdocml.upstream/main.c
+++ mdocml/main.c
@@ -19,14 +19,16 @@
@@ -19,7 +19,6 @@
#include "config.h"
#include <sys/types.h>
@ -321,50 +321,7 @@ diff -Paur --no-dereference -- mdocml.upstream/main.c mdocml/main.c
#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
+/* PATCH: Sortix doesn't have glob.h at this time. */
+#if defined(__has_include) && __has_include(<glob.h>)
#include <glob.h>
+#endif
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
@@ -531,10 +533,16 @@
const char *sec, const char *arch, const char *name,
struct manpage **res, size_t *ressz)
{
+#if defined(__has_include) && __has_include(<glob.h>)
glob_t globinfo;
+#endif
struct manpage *page;
char *file;
+#if defined(__has_include) && __has_include(<glob.h>)
int form, globres;
+#else
+ int form;
+#endif
form = FORM_SRC;
mandoc_asprintf(&file, "%s/man%s/%s.%s",
@@ -559,6 +567,7 @@
free(file);
}
+#if defined(__has_include) && __has_include(<glob.h>)
mandoc_asprintf(&file, "%s/man%s/%s.*",
paths->paths[ipath], sec, name);
globres = glob(file, 0, NULL, &globinfo);
@@ -570,6 +579,7 @@
file = mandoc_strdup(*globinfo.gl_pathv);
globfree(&globinfo);
if (globres != 0)
+#endif
return(0);
found:
@@ -606,7 +616,38 @@
@@ -606,7 +605,38 @@
*res = NULL;
*ressz = lastsz = 0;
while (argc) {
@ -404,7 +361,7 @@ diff -Paur --no-dereference -- mdocml.upstream/main.c mdocml/main.c
if (cfg->sec != NULL) {
if (fs_lookup(paths, ipath, cfg->sec,
cfg->arch, *argv, res, ressz) &&
@@ -989,7 +1030,7 @@
@@ -989,7 +1019,7 @@
if (pager == NULL || *pager == '\0')
pager = getenv("PAGER");
if (pager == NULL || *pager == '\0')
@ -413,7 +370,7 @@ diff -Paur --no-dereference -- mdocml.upstream/main.c mdocml/main.c
cp = mandoc_strdup(pager);
/*
@@ -1014,7 +1055,7 @@
@@ -1014,7 +1044,7 @@
/* Hand over to the pager. */
execvp(argv[0], argv);

View File

@ -48,17 +48,7 @@ diff -Paur --no-dereference -- nano.upstream/src/nano.c nano/src/nano.c
diff -Paur --no-dereference -- nano.upstream/src/rcfile.c nano/src/rcfile.c
--- nano.upstream/src/rcfile.c
+++ nano/src/rcfile.c
@@ -27,7 +27,9 @@
#include <ctype.h>
#include <errno.h>
+#if __has_include(<glob.h>)
#include <glob.h>
+#endif
#include <string.h>
#include <unistd.h>
@@ -577,6 +579,11 @@
@@ -577,6 +577,11 @@
* null-terminate it, and return a pointer to the succeeding text. */
char *parse_next_regex(char *ptr)
{
@ -70,7 +60,7 @@ diff -Paur --no-dereference -- nano.upstream/src/rcfile.c nano/src/rcfile.c
char *starting_point = ptr;
if (*(ptr - 1) != '"') {
@@ -584,11 +591,28 @@
@@ -584,11 +589,28 @@
return NULL;
}
@ -103,7 +93,7 @@ diff -Paur --no-dereference -- nano.upstream/src/rcfile.c nano/src/rcfile.c
if (*ptr == '\0') {
jot_error(N_("Regex strings must begin and end with a \" character"));
@@ -601,7 +625,8 @@
@@ -601,7 +623,8 @@
}
/* Null-terminate the regex and skip until the next non-blank. */
@ -113,32 +103,3 @@ diff -Paur --no-dereference -- nano.upstream/src/rcfile.c nano/src/rcfile.c
while (isblank((unsigned char)*ptr))
ptr++;
@@ -966,8 +991,10 @@
void parse_includes(char *ptr)
{
char *pattern, *expanded;
+#if __has_include(<glob.h>)
glob_t files;
int result;
+#endif
check_for_nonempty_syntax();
@@ -978,6 +1005,7 @@
/* Expand a tilde first, then try to match the globbing pattern. */
expanded = real_dir_from_tilde(pattern);
+#if __has_include(<glob.h>)
result = glob(expanded, GLOB_ERR, NULL, &files);
/* If there are matches, process each of them. Otherwise, only
@@ -989,6 +1017,9 @@
jot_error(N_("Error expanding %s: %s"), pattern, strerror(errno));
globfree(&files);
+#else
+ parse_one_include(expanded);
+#endif
free(expanded);
}

View File

@ -1,7 +1,7 @@
diff -Paur --no-dereference -- ssh.upstream/auth.c ssh/auth.c
--- ssh.upstream/auth.c
+++ ssh/auth.c
@@ -100,7 +100,9 @@
@@ -99,7 +99,9 @@
int
allowed_user(struct ssh *ssh, struct passwd * pw)
{
@ -11,7 +11,7 @@ diff -Paur --no-dereference -- ssh.upstream/auth.c ssh/auth.c
const char *hostname = NULL, *ipaddr = NULL;
u_int i;
int r;
@@ -121,6 +123,8 @@
@@ -120,6 +122,8 @@
*/
if (options.chroot_directory == NULL ||
strcasecmp(options.chroot_directory, "none") == 0) {
@ -20,7 +20,7 @@ diff -Paur --no-dereference -- ssh.upstream/auth.c ssh/auth.c
char *shell = xstrdup((pw->pw_shell[0] == '\0') ?
_PATH_BSHELL : pw->pw_shell); /* empty = /bin/sh */
@@ -138,6 +142,7 @@
@@ -137,6 +141,7 @@
return 0;
}
free(shell);
@ -83,7 +83,7 @@ diff -Paur --no-dereference -- ssh.upstream/channels.c ssh/channels.c
c->path = xstrdup(host);
} else { /* SOCKS4A: two strings */
have = sshbuf_len(input);
@@ -2450,8 +2451,8 @@
@@ -2458,8 +2459,8 @@
return;
}
if ((euid != 0) && (getuid() != euid)) {
@ -482,7 +482,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
-rmdir $(DESTDIR)$(sysconfdir)
-rmdir $(DESTDIR)$(bindir)
-rmdir $(DESTDIR)$(sbindir)
@@ -553,7 +544,7 @@
@@ -557,7 +548,7 @@
regress/unittests/sshbuf/test_sshbuf$(EXEEXT): ${UNITTESTS_TEST_SSHBUF_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -491,7 +491,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -567,7 +558,7 @@
@@ -571,7 +562,7 @@
regress/unittests/sshkey/test_sshkey$(EXEEXT): ${UNITTESTS_TEST_SSHKEY_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -500,7 +500,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -578,7 +569,7 @@
@@ -582,7 +573,7 @@
regress/unittests/sshsig/test_sshsig$(EXEEXT): ${UNITTESTS_TEST_SSHSIG_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -509,7 +509,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -587,7 +578,7 @@
@@ -591,7 +582,7 @@
regress/unittests/bitmap/test_bitmap$(EXEEXT): ${UNITTESTS_TEST_BITMAP_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -518,7 +518,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -599,7 +590,7 @@
@@ -603,7 +594,7 @@
regress/unittests/authopt/test_authopt$(EXEEXT): \
${UNITTESTS_TEST_AUTHOPT_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -527,7 +527,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -609,7 +600,7 @@
@@ -613,7 +604,7 @@
regress/unittests/conversion/test_conversion$(EXEEXT): \
${UNITTESTS_TEST_CONVERSION_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -536,7 +536,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -621,7 +612,7 @@
@@ -625,7 +616,7 @@
regress/unittests/kex/test_kex$(EXEEXT): ${UNITTESTS_TEST_KEX_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -545,7 +545,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -633,7 +624,7 @@
@@ -637,7 +628,7 @@
regress/unittests/hostkeys/test_hostkeys$(EXEEXT): \
${UNITTESTS_TEST_HOSTKEYS_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -554,7 +554,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -643,7 +634,7 @@
@@ -647,7 +638,7 @@
regress/unittests/match/test_match$(EXEEXT): \
${UNITTESTS_TEST_MATCH_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -563,7 +563,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -660,7 +651,7 @@
@@ -664,7 +655,7 @@
regress/unittests/misc/test_misc$(EXEEXT): \
${UNITTESTS_TEST_MISC_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -572,7 +572,7 @@ diff -Paur --no-dereference -- ssh.upstream/Makefile.in ssh/Makefile.in
regress/unittests/test_helper/libtest_helper.a \
-lssh -lopenbsd-compat -lssh -lopenbsd-compat $(TESTLIBS)
@@ -670,7 +661,7 @@
@@ -674,7 +665,7 @@
regress/unittests/utf8/test_utf8$(EXEEXT): \
${UNITTESTS_TEST_UTF8_OBJS} \
regress/unittests/test_helper/libtest_helper.a libssh.a
@ -618,7 +618,7 @@ diff -Paur --no-dereference -- ssh.upstream/misc.c ssh/misc.c
/* remove newline at end of string */
char *
chop(char *s)
@@ -2745,17 +2772,17 @@
@@ -2742,17 +2769,17 @@
if (geteuid() == 0 &&
initgroups(pw->pw_name, pw->pw_gid) == -1) {
@ -669,7 +669,7 @@ diff -Paur --no-dereference -- ssh.upstream/monitor_fdpass.c ssh/monitor_fdpass.
diff -Paur --no-dereference -- ssh.upstream/mux.c ssh/mux.c
--- ssh.upstream/mux.c
+++ ssh/mux.c
@@ -497,7 +497,7 @@
@@ -495,7 +495,7 @@
/* prepare reply */
if ((r = sshbuf_put_u32(reply, MUX_S_ALIVE)) != 0 ||
(r = sshbuf_put_u32(reply, rid)) != 0 ||
@ -829,7 +829,7 @@ diff -Paur --no-dereference -- ssh.upstream/openbsd-compat/getrrsetbyname.c ssh/
#if defined(HAVE_DECL_H_ERRNO) && !HAVE_DECL_H_ERRNO
extern int h_errno;
#endif
@@ -612,4 +634,6 @@
@@ -643,4 +665,6 @@
return (n);
}
@ -922,7 +922,7 @@ diff -Paur --no-dereference -- ssh.upstream/pathnames.h ssh/pathnames.h
diff -Paur --no-dereference -- ssh.upstream/progressmeter.c ssh/progressmeter.c
--- ssh.upstream/progressmeter.c
+++ ssh/progressmeter.c
@@ -81,7 +81,8 @@
@@ -80,7 +80,8 @@
static int
can_output(void)
{
@ -931,11 +931,11 @@ diff -Paur --no-dereference -- ssh.upstream/progressmeter.c ssh/progressmeter.c
+ return (getpgid(0) == tcgetpgrp(STDOUT_FILENO));
}
static void
/* size needed to format integer type v, using (nbits(v) * log2(10) / 10) */
diff -Paur --no-dereference -- ssh.upstream/readconf.c ssh/readconf.c
--- ssh.upstream/readconf.c
+++ ssh/readconf.c
@@ -510,6 +510,10 @@
@@ -509,6 +509,10 @@
int
default_ssh_port(void)
{
@ -946,7 +946,7 @@ diff -Paur --no-dereference -- ssh.upstream/readconf.c ssh/readconf.c
static int port;
struct servent *sp;
@@ -518,6 +522,7 @@
@@ -517,6 +521,7 @@
port = sp ? ntohs(sp->s_port) : SSH_DEFAULT_PORT;
}
return port;
@ -974,7 +974,7 @@ diff -Paur --no-dereference -- ssh.upstream/regress/netcat.c ssh/regress/netcat.
diff -Paur --no-dereference -- ssh.upstream/scp.c ssh/scp.c
--- ssh.upstream/scp.c
+++ ssh/scp.c
@@ -645,7 +645,7 @@
@@ -647,7 +647,7 @@
mode = MODE_SCP;
if ((pwd = getpwuid(userid = getuid())) == NULL)
@ -983,7 +983,7 @@ diff -Paur --no-dereference -- ssh.upstream/scp.c ssh/scp.c
if (!isatty(STDOUT_FILENO))
showprogress = 0;
@@ -1007,7 +1007,7 @@
@@ -1009,7 +1009,7 @@
static struct sftp_conn *
do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
@ -995,7 +995,7 @@ diff -Paur --no-dereference -- ssh.upstream/scp.c ssh/scp.c
diff -Paur --no-dereference -- ssh.upstream/servconf.c ssh/servconf.c
--- ssh.upstream/servconf.c
+++ ssh/servconf.c
@@ -309,7 +309,10 @@
@@ -308,7 +308,10 @@
if (options->pid_file == NULL)
options->pid_file = xstrdup(_PATH_SSH_DAEMON_PID_FILE);
if (options->moduli_file == NULL)
@ -1007,7 +1007,7 @@ diff -Paur --no-dereference -- ssh.upstream/servconf.c ssh/servconf.c
if (options->login_grace_time == -1)
options->login_grace_time = 120;
if (options->permit_root_login == PERMIT_NOT_SET)
@@ -454,7 +457,12 @@
@@ -453,7 +456,12 @@
/* Turn privilege separation and sandboxing on by default */
if (use_privsep == -1)
@ -1023,7 +1023,7 @@ diff -Paur --no-dereference -- ssh.upstream/servconf.c ssh/servconf.c
diff -Paur --no-dereference -- ssh.upstream/session.c ssh/session.c
--- ssh.upstream/session.c
+++ ssh/session.c
@@ -104,6 +104,15 @@
@@ -103,6 +103,15 @@
#include <selinux/selinux.h>
#endif
@ -1039,7 +1039,7 @@ diff -Paur --no-dereference -- ssh.upstream/session.c ssh/session.c
#define IS_INTERNAL_SFTP(c) \
(!strncmp(c, INTERNAL_SFTP_NAME, sizeof(INTERNAL_SFTP_NAME) - 1) && \
(c[sizeof(INTERNAL_SFTP_NAME) - 1] == '\0' || \
@@ -1052,9 +1061,11 @@
@@ -1051,9 +1060,11 @@
#endif /* HAVE_LOGIN_CAP */
if (!options.use_pam) {
@ -1157,7 +1157,7 @@ diff -Paur --no-dereference -- ssh.upstream/sftp-server-main.c ssh/sftp-server-m
diff -Paur --no-dereference -- ssh.upstream/ssh-add.c ssh/ssh-add.c
--- ssh.upstream/ssh-add.c
+++ ssh/ssh-add.c
@@ -979,8 +979,8 @@
@@ -982,8 +982,8 @@
int count = 0;
if ((pw = getpwuid(getuid())) == NULL) {
@ -1171,7 +1171,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-add.c ssh/ssh-add.c
diff -Paur --no-dereference -- ssh.upstream/ssh-agent.c ssh/ssh-agent.c
--- ssh.upstream/ssh-agent.c
+++ ssh/ssh-agent.c
@@ -1749,8 +1749,8 @@
@@ -1748,8 +1748,8 @@
return -1;
}
if ((euid != 0) && (getuid() != euid)) {
@ -1218,7 +1218,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh.c ssh/ssh.c
diff -Paur --no-dereference -- ssh.upstream/sshconnect.c ssh/sshconnect.c
--- ssh.upstream/sshconnect.c
+++ ssh/sshconnect.c
@@ -164,7 +164,8 @@
@@ -163,7 +163,8 @@
* Execute the proxy command.
* Note that we gave up any extra privileges above.
*/
@ -1228,7 +1228,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshconnect.c ssh/sshconnect.c
perror(argv[0]);
exit(1);
}
@@ -248,7 +249,7 @@
@@ -247,7 +248,7 @@
* extra privileges above.
*/
ssh_signal(SIGPIPE, SIG_DFL);
@ -1237,7 +1237,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshconnect.c ssh/sshconnect.c
perror(argv[0]);
exit(1);
}
@@ -306,7 +307,9 @@
@@ -305,7 +306,9 @@
for (allow_local = 0; allow_local < 2; allow_local++) {
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || ifa->ifa_name == NULL ||
@ -1247,7 +1247,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshconnect.c ssh/sshconnect.c
ifa->ifa_addr->sa_family != af ||
strcmp(ifa->ifa_name, options.bind_interface) != 0)
continue;
@@ -1671,7 +1674,7 @@
@@ -1670,7 +1673,7 @@
if (pid == 0) {
ssh_signal(SIGPIPE, SIG_DFL);
debug3("Executing %s -c \"%s\"", shell, args);
@ -1279,7 +1279,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.8 ssh/sshd.8
.Pp
The options are as follows:
.Bl -tag -width Ds
@@ -994,14 +994,6 @@
@@ -1008,14 +1008,6 @@
during privilege separation in the pre-authentication phase.
The directory should not contain any files and must be owned by root
and not group or world-writable.
@ -1297,7 +1297,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.8 ssh/sshd.8
diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
--- ssh.upstream/sshd.c
+++ ssh/sshd.c
@@ -129,6 +129,15 @@
@@ -128,6 +128,15 @@
#include "srclimit.h"
#include "dh.h"
@ -1313,7 +1313,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
/* Re-exec fds */
#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
@@ -234,7 +243,11 @@
@@ -233,7 +242,11 @@
static int startup_pipe = -1; /* in child */
/* variables used for privilege separation */
@ -1325,7 +1325,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
struct monitor *pmonitor = NULL;
int privsep_is_preauth = 1;
static int privsep_chroot = 1;
@@ -460,8 +473,8 @@
@@ -455,8 +468,8 @@
fatal("chdir(\"/\"): %s", strerror(errno));
/* Drop our privileges */
@ -1336,7 +1336,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
gidset[0] = privsep_pw->pw_gid;
if (setgroups(1, gidset) == -1)
fatal("setgroups: %.100s", strerror(errno));
@@ -1579,6 +1592,10 @@
@@ -1589,6 +1602,10 @@
/* Initialize configuration options to their default values. */
initialize_server_options(&options);
@ -1346,10 +1346,10 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
+
/* Parse command-line arguments. */
while ((opt = getopt(ac, av,
"C:E:b:c:f:g:h:k:o:p:u:46DQRTdeiqrtV")) != -1) {
@@ -1695,10 +1712,32 @@
"C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) {
@@ -1708,10 +1725,32 @@
rexec_flag = 0;
if (!test_flag && rexec_flag && !path_absolute(av[0]))
if (!test_flag && !do_dump_cfg && rexec_flag && !path_absolute(av[0]))
fatal("sshd re-exec requires execution with an absolute path");
- if (rexeced_flag)
- closefrom(REEXEC_MIN_FREE_FD);
@ -1384,7 +1384,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
seed_rng();
@@ -2074,7 +2113,8 @@
@@ -2081,7 +2120,8 @@
* Write out the pid file after the sigterm handler
* is setup and the listen sockets are bound
*/
@ -1394,7 +1394,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
FILE *f = fopen(options.pid_file, "w");
if (f == NULL) {
@@ -2086,6 +2126,15 @@
@@ -2093,6 +2133,15 @@
}
}
@ -1410,7 +1410,7 @@ diff -Paur --no-dereference -- ssh.upstream/sshd.c ssh/sshd.c
/* Accept a connection and return in a forked child */
server_accept_loop(&sock_in, &sock_out,
&newsock, config_s);
@@ -2445,10 +2494,10 @@
@@ -2447,10 +2496,10 @@
do_cleanup(the_active_state, the_authctxt);
if (use_privsep && privsep_is_preauth &&
pmonitor != NULL && pmonitor->m_pid > 1) {
@ -1473,7 +1473,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.1 ssh/ssh-keygen.1
diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.c ssh/ssh-keygen.c
--- ssh.upstream/ssh-keygen.c
+++ ssh/ssh-keygen.c
@@ -829,7 +829,7 @@
@@ -831,7 +831,7 @@
}
sshkey_free(prv);
free(comment);
@ -1482,7 +1482,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.c ssh/ssh-keygen.c
}
static void
@@ -987,7 +987,7 @@
@@ -989,7 +989,7 @@
free(line);
fclose(f);
fingerprint_private(path);
@ -1491,7 +1491,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.c ssh/ssh-keygen.c
}
/*
@@ -1035,7 +1035,7 @@
@@ -1037,7 +1037,7 @@
if (invalid)
fatal("%s is not a public key file.", path);
@ -1500,7 +1500,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.c ssh/ssh-keygen.c
}
static void
@@ -1075,14 +1075,32 @@
@@ -1077,14 +1077,32 @@
/* Check whether private key exists and is not zero-length */
if (stat(prv_file, &st) == 0) {
@ -1534,7 +1534,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.c ssh/ssh-keygen.c
/*
* Private key doesn't exist or is invalid; proceed with
* key generation.
@@ -3347,7 +3365,7 @@
@@ -3363,7 +3381,7 @@
/* we need this for the home * directory. */
pw = getpwuid(getuid());
if (!pw)
@ -1543,7 +1543,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keygen.c ssh/ssh-keygen.c
pw = pwcopy(pw);
if (gethostname(hostname, sizeof(hostname)) == -1)
fatal("gethostname: %s", strerror(errno));
@@ -3703,8 +3721,10 @@
@@ -3719,8 +3737,10 @@
}
return do_download_sk(sk_provider, sk_device);
}
@ -1570,7 +1570,7 @@ diff -Paur --no-dereference -- ssh.upstream/ssh-keyscan.c ssh/ssh-keyscan.c
#include "xmalloc.h"
#include "ssh.h"
#include "sshbuf.h"
@@ -54,6 +59,14 @@
@@ -55,6 +60,14 @@
#include "dns.h"
#include "addr.h"

View File

@ -1,10 +1,10 @@
NAME=ssh
BUILD_LIBRARIES='libz libssl'
VERSION=9.2p1
VERSION=9.3p1
DISTNAME=openssh-$VERSION
COMPRESSION=tar.gz
ARCHIVE=$DISTNAME.$COMPRESSION
SHA256SUM=3f66dbf1655fb45f50e1c56da62ab01218c228807b21338d634ebcdf9d71cf46
SHA256SUM=e9baba7701a76a51f3d85a62c383a3c9dcd97fa900b859bc7db114c1868af8a8
UPSTREAM_SITE=https://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable
UPSTREAM_ARCHIVE=$ARCHIVE
LICENSE='SSH-OpenSSH AND BSD-2-Clause AND BSD-3-Clause AND ISC AND MIT'

284
sh/sh.c
View File

@ -27,6 +27,7 @@
#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <glob.h>
#include <inttypes.h>
#include <ioleast.h>
#include <libgen.h>
@ -106,21 +107,6 @@ void update_env(void)
}
}
bool matches_simple_pattern(const char* string, const char* pattern)
{
size_t wildcard_index = strcspn(pattern, "*");
if ( !pattern[wildcard_index] )
return strcmp(string, pattern) == 0;
if ( pattern[0] == '*' && string[0] == '.' )
return false;
size_t string_length = strlen(string);
size_t pattern_length = strlen(pattern);
size_t pattern_last = pattern_length - (wildcard_index + 1);
return strncmp(string, pattern, wildcard_index) == 0 &&
strcmp(string + string_length - pattern_last,
pattern + wildcard_index + 1) == 0;
}
void array_shrink_free(void*** array_ptr,
size_t* used_ptr,
size_t* length_ptr,
@ -347,13 +333,6 @@ bool token_expand_variables_split(void*** out,
return result;
}
static int strcoll_indirect(const void* a_ptr, const void* b_ptr)
{
const char* a = *(const char* const*) a_ptr;
const char* b = *(const char* const*) b_ptr;
return strcoll(a, b);
}
bool token_expand_wildcards(void*** out,
size_t* out_used,
size_t* out_length,
@ -361,217 +340,112 @@ bool token_expand_wildcards(void*** out,
{
size_t old_used = *out_used;
size_t index = 0;
size_t num_escaped_wildcards = 0; // We don't properly support them yet.
struct stringbuf buf;
stringbuf_begin(&buf);
// First check if the token contains any wildcards at all.
bool escape = false;
bool single_quote = false;
bool double_quote = false;
for ( ; token[index]; index++ )
bool any_wildcards = false;
for ( size_t i = 0; token[i]; i++ )
{
if ( !escape && !single_quote && token[index] == '\\' )
{
char c = token[i];
if ( !escape && !single_quote && c == '\\' )
escape = true;
}
else if ( !escape && !double_quote && token[index] == '\'' )
{
else if ( !escape && !double_quote && c == '\'' )
single_quote = !single_quote;
}
else if ( !escape && !single_quote && token[index] == '"' )
{
else if ( !escape && !single_quote && c == '"' )
double_quote = !double_quote;
}
else if ( !(escape || single_quote || double_quote) &&
token[index] == '*' )
(c == '?' || c == '*' || c == '[') )
{
break;
any_wildcards = true;
stringbuf_append_c(&buf, c);
}
else
{
if ( escape && double_quote &&
token[index] != '$' && token[index] != '`' &&
token[index] != '"' && token[index] != '\\' )
c != '$' && c != '`' && c != '"' && c != '\\' )
stringbuf_append_c(&buf, '\\');
if ( token[index] == '*' )
num_escaped_wildcards++;
stringbuf_append_c(&buf, token[index]);
else if ( (escape || single_quote || double_quote) &&
(c == '?' || c == '*' || c == '[') )
stringbuf_append_c(&buf, '\\');
stringbuf_append_c(&buf, c);
escape = false;
}
}
if ( token[index] != '*' || num_escaped_wildcards )
char* pattern = stringbuf_finish(&buf);
if ( !pattern )
return false;
// If the token didn't contain any wildcards, just return it.
if ( !any_wildcards )
{
char* value;
free(stringbuf_finish(&buf));
free(pattern);
just_return_input:
value = strdup(token);
if ( !value )
pattern = strdup(token);
if ( !pattern )
return false;
if ( !array_add(out, out_used, out_length, value) )
return free(value), false;
if ( !array_add(out, out_used, out_length, pattern) )
return free(pattern), false;
return true;
}
char* before = stringbuf_finish(&buf);
if ( !before )
return false;
stringbuf_begin(&buf);
index++;
for ( ; token[index]; index++ )
{
if ( !escape && !single_quote && token[index] == '\\' )
{
escape = true;
}
else if ( !escape && !double_quote && token[index] == '\'' )
{
single_quote = !single_quote;
}
else if ( !escape && !single_quote && token[index] == '"' )
{
double_quote = !double_quote;
}
else if ( !(escape || single_quote || double_quote) &&
token[index] == '*' )
{
break;
}
else
{
if ( escape && double_quote &&
token[index] != '$' && token[index] != '`' &&
token[index] != '"' && token[index] != '\\' )
stringbuf_append_c(&buf, '\\');
if ( token[index] == '*' )
num_escaped_wildcards++;
stringbuf_append_c(&buf, token[index]);
escape = false;
}
}
if ( token[index] == '*' )
{
// TODO: We don't support double use of wildcards yet.
free(stringbuf_finish(&buf));
free(before);
goto just_return_input;
}
char* after = stringbuf_finish(&buf);
if ( !after )
return free(before), false;
char* pattern;
if ( asprintf(&pattern, "%s*%s", before, after) < 0 )
return free(after), free(before), false;
free(after);
free(before);
size_t wildcard_pos = strcspn(pattern, "*");
bool found_slash = false;
size_t last_slash = 0;
for ( size_t n = 0; n < wildcard_pos; n++ )
if ( pattern[n] == '/' )
last_slash = n, found_slash = true;
size_t match_from = found_slash ? last_slash + 1 : 0;
size_t pattern_prefix = 0;
DIR* dir = NULL;
if ( !found_slash )
{
if ( !(dir = opendir(".")) )
{
free(pattern);
goto just_return_input;
}
}
else
{
char* dirpath = strdup(pattern);
if ( !dirpath )
{
free(pattern);
goto just_return_input;
}
dirpath[last_slash] = '\0';
pattern_prefix = last_slash + 1;
dir = opendir(dirpath);
free(dirpath);
if ( !dir )
{
free(pattern);
goto just_return_input;
}
}
size_t num_inserted = 0;
struct dirent* entry;
while ( (entry = readdir(dir)) )
{
if ( !matches_simple_pattern(entry->d_name, pattern + match_from) )
continue;
stringbuf_begin(&buf);
for ( size_t i = 0; i < pattern_prefix; i++ )
{
if ( pattern[i] == '\n' )
{
stringbuf_append_c(&buf, '\'');
stringbuf_append_c(&buf, '\n');
stringbuf_append_c(&buf, '\'');
}
else
{
if ( might_need_shell_quote(pattern[i]) )
stringbuf_append_c(&buf, '\\');
stringbuf_append_c(&buf, pattern[i]);
}
}
for ( size_t i = 0; entry->d_name[i]; i++ )
{
if ( entry->d_name[i] == '\n' )
{
stringbuf_append_c(&buf, '\'');
stringbuf_append_c(&buf, '\n');
stringbuf_append_c(&buf, '\'');
}
else
{
if ( might_need_shell_quote(entry->d_name[i]) )
stringbuf_append_c(&buf, '\\');
stringbuf_append_c(&buf, entry->d_name[i]);
}
}
char* name = stringbuf_finish(&buf);
if ( !name )
{
free(pattern);
closedir(dir);
array_shrink_free(out, out_used, out_length, old_used);
return false;
}
if ( !array_add(out, out_used, out_length, name) )
{
free(name);
free(pattern);
closedir(dir);
array_shrink_free(out, out_used, out_length, old_used);
return false;
}
num_inserted++;
}
closedir(dir);
// Search the filesystem for paths matching the pattern.
glob_t gl;
int globerr = glob(pattern, 0, NULL, &gl);
free(pattern);
if ( num_inserted == 0 )
goto just_return_input;
char** out_tokens;
memcpy(&out_tokens, out, sizeof(out_tokens));
char** sort_from = out_tokens + old_used;
size_t sort_count = *out_used - old_used;
qsort(sort_from, sort_count, sizeof(char*), strcoll_indirect);
if ( globerr )
{
globfree(&gl);
// GLOB_NOCHECK is not used since we don't want the escaped pattern back
// since it would contain e.g. \* which is difficult to discern from a
// real file actually called \* and the original token is escaped in the
// correct fashion.
if ( globerr == GLOB_NOMATCH )
goto just_return_input;
return false;
}
// Escape the paths as tokens.
for ( size_t n = 0; n < gl.gl_pathc; n++ )
{
const char* path = gl.gl_pathv[n];
stringbuf_begin(&buf);
for ( size_t i = 0; path[i]; i++ )
{
if ( path[i] == '\n' )
{
stringbuf_append_c(&buf, '\'');
stringbuf_append_c(&buf, '\n');
stringbuf_append_c(&buf, '\'');
}
else
{
if ( might_need_shell_quote(path[i]) )
stringbuf_append_c(&buf, '\\');
stringbuf_append_c(&buf, path[i]);
}
}
char* new_token = stringbuf_finish(&buf);
if ( !new_token )
{
globfree(&gl);
array_shrink_free(out, out_used, out_length, old_used);
return false;
}
if ( !array_add(out, out_used, out_length, new_token) )
{
free(new_token);
globfree(&gl);
array_shrink_free(out, out_used, out_length, old_used);
return false;
}
}
globfree(&gl);
return true;
}

View File

@ -69,6 +69,24 @@ releasing Sortix x.y, foo." to allow the maintainer to easily
.Xr grep 1
for it after a release.
.Sh CHANGES
.Ss Add include and comment support to passwd(5) and group(5)
The
.Xr passwd 5
and
.Xr group 5
files have gained support for include statements via libc support.
Installations must now include
.Pa /etc/default/passwd.d/*
and
.Pa /etc/default/group.d/*
respectively in order to have system users and groups.
.Pp
An upgrade hook will add the inclusions to
.Pa /etc/passwd
and
.Pa /etc/group .
Applications accessing passwd and group databases must be recompiled with the
latest libc.
.Ss Add memory statistics to struct psctl_stat
The
.Xr psctl 2

View File

@ -80,7 +80,7 @@ per the instructions in
.Xr release-iso-modification 7 .
.Pp
If you want to ssh into your installation, it's recommended to amend the
installation .iso with your public key, pregenerated the server keys and obtain
installation .iso with your public key, pregenerate the server keys and obtain
fingerprints, and seed randomness using this procedure.
.Pp
The release modification procedure lets you customize aspects such as the

View File

@ -55,6 +55,8 @@ install: all
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-tix-manifest-mode
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-leaked-files
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-init
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-passwd
touch $(DESTDIR)$(DATADIR)/sysinstall/hooks/sortix-1.1-group
sysinstall: $(SYSINSTALL_OBJS)
$(CC) $(SYSINSTALL_OBJS) -o $@ -lmount

View File

@ -296,6 +296,64 @@ void upgrade_prepare(const struct release* old_release,
free(init_target_path);
free(init_default_path);
}
// TODO: After releasing Sortix 1.1, remove this compatibility.
if ( hook_needs_to_be_run(source_prefix, target_prefix,
"sortix-1.1-passwd") )
{
char* passwd_path = join_paths(target_prefix, "/etc/passwd");
if ( !passwd_path )
{
warn("malloc");
_exit(2);
}
FILE* fp = fopen(passwd_path, "a");
if ( fp )
{
printf(" - Including /etc/default/passwd.d/* in /etc/passwd...\n");
if ( fprintf(fp, "include /etc/default/passwd.d/*\n") < 0 ||
fclose(fp) == EOF )
{
warn("%s", passwd_path);
_exit(2);
}
}
else if ( errno != ENOENT )
{
warn("%s", passwd_path);
_exit(2);
}
free(passwd_path);
}
// TODO: After releasing Sortix 1.1, remove this compatibility.
if ( hook_needs_to_be_run(source_prefix, target_prefix,
"sortix-1.1-group") )
{
char* group_path = join_paths(target_prefix, "/etc/group");
if ( !group_path )
{
warn("malloc");
_exit(2);
}
FILE* fp = fopen(group_path, "a");
if ( fp )
{
printf(" - Including /etc/default/group.d/* in /etc/group...\n");
if ( fprintf(fp, "include /etc/default/group.d/*\n") < 0 ||
fclose(fp) == EOF )
{
warn("%s", group_path);
_exit(2);
}
}
else if ( errno != ENOENT )
{
warn("%s", group_path);
_exit(2);
}
free(group_path);
}
}
void upgrade_finalize(const struct release* old_release,

View File

@ -220,16 +220,23 @@ static bool passwd_check(const char* passwd_path,
warn("%s", passwd_path);
return false;
}
struct passwd* pwd;
while ( (errno = 0, pwd = fgetpwent(passwd)) )
char* line = NULL;
size_t size = 0;
ssize_t length;
while ( 0 < (length = getline(&line, &size, passwd) ) )
{
if ( check(pwd, check_ctx) )
if ( line[size - 1] == '\n' )
line[--size] = '\0';
struct passwd pwd;
if ( scanpwent(line, &pwd) && check(&pwd, check_ctx) )
{
free(line);
fclose(passwd);
return true;
}
}
if ( errno != 0 )
free(line);
if ( ferror(passwd) )
warn("%s", passwd_path);
fclose(passwd);
return false;
@ -1025,10 +1032,13 @@ int main(void)
}
explicit_bzero(first, sizeof(first));
if ( !install_configurationf("etc/passwd", "a",
"root:%s:0:0:root:/root:sh\n", hash) )
"root:%s:0:0:root:/root:sh\n"
"include /etc/default/passwd.d/*\n", hash) )
continue;
textf("User '%s' added to /etc/passwd\n", "root");
if ( !install_configurationf("etc/group", "a", "root::0:root\n") )
if ( !install_configurationf("etc/group", "a",
"root::0:root\n"
"include /etc/default/group.d/*\n") )
continue;
install_skel("/root", 0, 0);
textf("Group '%s' added to /etc/group.\n", "root");
@ -1230,7 +1240,7 @@ int main(void)
"connections as well.\n\n");
bool might_want_sshd =
any_ssh_keys ||
any_sshd_keys ||
any_sshd_keys ||
!access_or_die("/etc/sshd_config", F_OK);
while ( true )
{

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015 Jonas 'Sortie' Termansen.
* Copyright (c) 2015, 2023 Jonas 'Sortie' Termansen.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@ -24,6 +24,7 @@
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -155,24 +156,50 @@ int main(int argc, char* argv[])
if ( crypt_newhash(first, cipher, newhash, sizeof(newhash)) < 0 )
err(1, "crypt_newhash");
explicit_bzero(first, sizeof(first));
// TODO: This is subject to races and is obviously an insecure design.
// The backend and coordination of the passwd database should be moved
// to its own daemon.
FILE* in = fopen("/etc/passwd", "r");
if ( !in )
err(1, "/etc/passwd");
int fd = open("/etc/passwd.new", O_WRONLY | O_CREAT | O_EXCL, 0644);
if ( fd < 0 )
err(1, "/etc/passwd.new");
fchown(fd, 0, 0); // HACK.
FILE* fp = fdopen(fd, "w");
if ( !fp )
err(1, "fdopen");
setpwent();
while ( (errno = 0, pwd = getpwent()) )
{
unlink("/etc/passwd.new");
err(1, "fdopen");
}
char* line = NULL;
size_t size = 0;
ssize_t length;
bool found = false;
while ( 0 < (length = getline(&line, &size, in)) )
{
char* copy = strdup(line);
if ( !copy )
{
unlink("/etc/passwd.new");
err(1, "malloc");
}
if ( copy[length - 1] == '\n' )
copy[--length] = '\0';
struct passwd passwd;
if ( !scanpwent(copy, (pwd = &passwd)) )
{
fputs(line, fp);
free(copy);
continue;
}
fputs(pwd->pw_name, fp);
fputc(':', fp);
if ( !strcmp(pwd->pw_name, username) )
{
fputs(newhash, fp);
found = true;
}
else
fputs(pwd->pw_passwd, fp);
fputc(':', fp);
@ -191,17 +218,25 @@ int main(int argc, char* argv[])
unlink("/etc/passwd.new");
err(1, "/etc/passwd.new");
}
free(copy);
}
if ( errno != 0 )
free(line);
if ( ferror(in) )
{
unlink("/etc/passwd.new");
err(1, "getpwent");
err(1, "/etc/passwd");
}
if ( fclose(fp) == EOF )
fclose(in);
if ( ferror(fp) || fclose(fp) == EOF )
{
unlink("/etc/passwd.new");
err(1, "/etc/passwd.new");
}
if ( !found )
{
unlink("/etc/passwd.new");
errx(1, "user %s is not directly in /etc/passwd", username);
}
if ( rename("/etc/passwd.new", "/etc/passwd") < 0 )
{
unlink("/etc/passwd.new");