Add include and comment support to passwd(5) and group(5).
This commit is contained in:
parent
da86ca1873
commit
c57ff050e9
2
Makefile
2
Makefile
|
@ -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
|
||||
|
|
|
@ -478,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 \
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue