mirror of
https://codeberg.org/landley/toybox.git
synced 2026-01-26 14:13:25 +00:00
Redo lib/password.c to remove shadow.h.
Implement internal common plumbing to modify colon separated files. Doesn't handle "pam" but the design of pam is incompatible with static linking.
This commit is contained in:
parent
f614f4b930
commit
6c30b35342
@ -356,7 +356,9 @@ char *escape_url(char *str, char *and);
|
||||
char *unescape_url(char *str, int do_cut);
|
||||
|
||||
// password.c
|
||||
int get_salt(char *salt, char * algo);
|
||||
int get_salt(char *salt, char *algo, int rand);
|
||||
int read_password(char *buff, int buflen, char *mesg);
|
||||
int update_password(char *filename, char *username, char *entry, int pos);
|
||||
|
||||
// commas.c
|
||||
void comma_args(struct arg_list *al, void *data, char *err,
|
||||
@ -423,6 +425,3 @@ pid_t __attribute__((returns_twice)) xvforkwrap(pid_t pid);
|
||||
|
||||
#define minof(a, b) ({typeof(a) aa = (a); typeof(b) bb = (b); aa<bb ? aa : bb;})
|
||||
#define maxof(a, b) ({typeof(a) aa = (a); typeof(b) bb = (b); aa>bb ? aa : bb;})
|
||||
|
||||
// Functions in need of further review/cleanup
|
||||
#include "lib/pending.h"
|
||||
|
||||
159
lib/password.c
159
lib/password.c
@ -1,45 +1,48 @@
|
||||
/* password.c - password read/update helper functions.
|
||||
*
|
||||
* Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
|
||||
*
|
||||
* TODO: cleanup
|
||||
*/
|
||||
|
||||
#include "toys.h"
|
||||
|
||||
// generate $id$salt$hash given a password and algorithm. Generates salt if NULL
|
||||
//char *toy_crypt(char *pass, char *salt, char *algo)
|
||||
// generate ID prefix and random salt for given encryption algorithm.
|
||||
int get_salt(char *salt, char *algo)
|
||||
int get_salt(char *salt, char *algo, int rand)
|
||||
{
|
||||
struct {
|
||||
char *type, id, len;
|
||||
} al[] = {{"des", 0, 2}, {"md5", 1, 8}, {"sha256", 5, 16}, {"sha512", 6, 16}};
|
||||
int i;
|
||||
char *s;
|
||||
int i, len;
|
||||
|
||||
for (i = 0; i < ARRAY_LEN(al); i++) {
|
||||
if (!strcmp(algo, al[i].type)) {
|
||||
int len = al[i].len;
|
||||
char *s = salt;
|
||||
|
||||
if (al[i].id) s += sprintf(s, "$%c$", '0'+al[i].id);
|
||||
|
||||
// Read appropriate number of random bytes for salt
|
||||
xgetrandom(libbuf, ((len*6)+7)/8);
|
||||
|
||||
// Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
|
||||
for (i = 0; i<len; i++) {
|
||||
int bitpos = i*6, bits = bitpos/8;
|
||||
|
||||
bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
|
||||
bits += 46;
|
||||
if (bits > 57) bits += 7;
|
||||
if (bits > 90) bits += 6;
|
||||
|
||||
s[i] = bits;
|
||||
}
|
||||
salt[len] = 0;
|
||||
|
||||
return s-salt;
|
||||
for (s = al[i].type, len = 0; algo[len]; len++) {
|
||||
while (ispunct(algo[len])) len++;
|
||||
if (tolower(algo[len]) != tolower(*s++)) break;
|
||||
}
|
||||
if (algo[len]) continue;
|
||||
|
||||
len = al[i].len;
|
||||
s = salt + (al[i].id ? sprintf(salt, "$%c$", '0'+al[i].id) : 0);
|
||||
|
||||
// Read appropriate number of random bytes for salt
|
||||
if (rand) xgetrandom(libbuf, ((len*6)+7)/8);
|
||||
|
||||
// Grab 6 bit chunks and convert to characters in ./0-9a-zA-Z
|
||||
for (i = 0; i<len; i++) {
|
||||
int bitpos = i*6, bits = bitpos/8;
|
||||
|
||||
bits = ((libbuf[i]+(libbuf[i+1]<<8)) >> (bitpos&7)) & 0x3f;
|
||||
bits += 46;
|
||||
if (bits > 57) bits += 7;
|
||||
if (bits > 90) bits += 6;
|
||||
|
||||
s[i] = bits;
|
||||
}
|
||||
s[len] = 0;
|
||||
|
||||
return s-salt;
|
||||
}
|
||||
|
||||
return -1;
|
||||
@ -79,79 +82,91 @@ int read_password(char *buf, int buflen, char *mesg)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* update colon-separated text files ala /etc/{passwd,shadow,group,gshadow}
|
||||
* username = string match for first entry in line
|
||||
* entry = new entry (NULL deletes matching line from file)
|
||||
* pos = which entry to replace with "entry" (0 is first)
|
||||
*/
|
||||
// filename+ = new copy being written, filename- = backup of old version
|
||||
// update colon-separated text files ala /etc/{passwd,shadow,group,gshadow}
|
||||
// returns 1 for success, 0 for failure
|
||||
|
||||
// username = string match for first entry in line
|
||||
// entry = new entry (NULL deletes matching line, contains : adds/replaces line)
|
||||
// pos = if no : in "entry", which field to replace (0 is first)
|
||||
// filename+ = new copy being written, filename- = backup of old version
|
||||
|
||||
int update_password(char *filename, char *username, char *entry, int pos)
|
||||
{
|
||||
char *filenamesfx = xmprintf("%s-", filename), *line = 0, *start, *end;
|
||||
FILE *ofp, *nfp;
|
||||
int ret = 0, found = 0, len = strlen(username)*!strchr(username, ':'), ii;
|
||||
char *ff = xmprintf("%s-", filename), *line = 0, *start, *end, *out, *oo;
|
||||
FILE *ofp;
|
||||
int len = strlen(username)*!strchr(username,':'), rc = 0, ret = 0, found = 0,
|
||||
nfd;
|
||||
struct flock lock = {.l_type = F_WRLCK};
|
||||
struct stat st;
|
||||
long long ll = 0;
|
||||
|
||||
// Open old filename ("r" won't let us lock), get blocking lock
|
||||
if (!(ofp = fopen(filename, "w+")) || 0>fcntl(fileno(ofp), F_SETLK, &lock)) {
|
||||
perror_msg("%s", filename);
|
||||
// Open old filename ("r" won't let us lock) and get blocking lock
|
||||
if (!(ofp = fopen(filename, "w+")) || 0>fcntl(fileno(ofp), F_SETLK, &lock)\
|
||||
|| fstat(fileno(ofp), &st))
|
||||
{
|
||||
perror_msg_raw(filename);
|
||||
goto free_storage;
|
||||
}
|
||||
|
||||
// Delete old backup, link new backup. (Failure here isn't fatal.)
|
||||
unlink(filenamesfx);
|
||||
if (0>link(filename, filenamesfx)) perror_msg("%s", filenamesfx);
|
||||
unlink(ff);
|
||||
if (0>link(filename, ff)) perror_msg_raw(ff);
|
||||
|
||||
// Open new file to copy entries to
|
||||
filenamesfx[strlen(filenamesfx)-1] = '+';
|
||||
if (!(nfp = fopen(filenamesfx, "w+"))) {
|
||||
perror_msg("%s", filenamesfx);
|
||||
ff[strlen(ff)-1] = '+';
|
||||
if (-1 == (nfd = xcreate(ff, O_CREAT|O_EXCL|O_WRONLY, st.st_mode))) {
|
||||
perror_msg_raw(ff);
|
||||
goto free_storage;
|
||||
}
|
||||
|
||||
// Loop through lines
|
||||
while (getline(&line, (void *)&ll, ofp)) {
|
||||
for (; getline(&line, (void *)&ll, ofp)!=-1; memset(line, 0, strlen(line))) {
|
||||
// find matching line
|
||||
start = end = line;
|
||||
if (strncmp(chomp(line), username, len) || line[len]!=':') {
|
||||
oo = 0;
|
||||
start = end = chomp(line);
|
||||
if (strncmp(line, username, len) || !(line[len] && line[len]!=':'))
|
||||
out = line;
|
||||
else {
|
||||
found++;
|
||||
if (!entry) continue;
|
||||
|
||||
// Find start and end of span to replace
|
||||
for (ii = pos;;) {
|
||||
while (*end != ':') {
|
||||
if (!*end) break;
|
||||
end++;
|
||||
// Delete or replace whole line?
|
||||
if (!entry) out = 0;
|
||||
else if (strchr(entry, ':')) out = entry;
|
||||
|
||||
// Replace entry at pos
|
||||
else {
|
||||
for (;; pos--, start = ++end) {
|
||||
while (*end && *end != ':') end++;
|
||||
if (!pos || !*end) break;
|
||||
}
|
||||
if (ii) {
|
||||
start = ++end;
|
||||
ii--;
|
||||
} else break;
|
||||
if (pos>=0) out = line;
|
||||
else oo = out = xmprintf("%*s%s%s\n", (int)(start-line),line,entry,end);
|
||||
}
|
||||
if (ii) start = end = line;
|
||||
}
|
||||
|
||||
// Write with replacement (if any)
|
||||
fprintf(nfp, "%*s%s%s\n", (int)(start-line), line,
|
||||
(start==line) ? "" : entry, end);
|
||||
memset(line, 0, strlen(line));
|
||||
if (out) {
|
||||
rc = dprintf(nfd, "%s\n", out);
|
||||
free(out);
|
||||
if (rc<0) {
|
||||
perror_msg_raw(ff);
|
||||
goto free_storage;
|
||||
}
|
||||
free(oo);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fflush(nfp);
|
||||
fsync(fileno(nfp));
|
||||
fclose(nfp); // automatically unlocks
|
||||
if (!found && entry && strchr(entry, ':')) dprintf(nfd, "%s\n", entry);
|
||||
fsync(nfd);
|
||||
close(nfd); // automatically unlocks
|
||||
|
||||
if (!found || rename(filenamesfx, filename)) {
|
||||
if (found) perror_msg("%s -> %s", filenamesfx, filename);
|
||||
else if (entry) fprintf(nfp, "%s\n", entry);
|
||||
unlink(filenamesfx);
|
||||
} else ret = 1;
|
||||
if (!found || rename(ff, filename)) {
|
||||
if (found) perror_msg("%s -> %s", ff, filename);
|
||||
else if (entry) error_msg("No %s in %s", username, filename);
|
||||
} else ret = 1, *ff = 0;
|
||||
|
||||
free_storage:
|
||||
if (ofp) fclose(ofp);
|
||||
free(filenamesfx);
|
||||
if (ff && *ff) unlink(ff);
|
||||
free(ff);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -1,6 +0,0 @@
|
||||
// pending.h - header for pending.c
|
||||
|
||||
// password.c
|
||||
#define MAX_SALT_LEN 20 //3 for id, 16 for key, 1 for '\0'
|
||||
int read_password(char *buff, int buflen, char *mesg);
|
||||
int update_password(char *filename, char *username, char *encrypted, int pos);
|
||||
@ -1,4 +1,4 @@
|
||||
/* passwd.c - Program to update user password.
|
||||
/* passwd.c - update user password.
|
||||
*
|
||||
* Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com>
|
||||
* Modified 2012 Jason Kyungwan Han <asura321@gmail.com>
|
||||
@ -13,9 +13,9 @@ config PASSWD
|
||||
help
|
||||
usage: passwd [-a ALGO] [-dlu] [USER]
|
||||
|
||||
Update user's authentication tokens. Defaults to current user.
|
||||
Update user's login password. Defaults to current user.
|
||||
|
||||
-a ALGO Encryption method (des, md5, sha256, sha512) default: des
|
||||
-a ALGO Encryption method (des, md5, sha256, sha512) default: md5
|
||||
-d Set password to ''
|
||||
-l Lock (disable) account
|
||||
-u Unlock (enable) account
|
||||
@ -53,17 +53,17 @@ static void weak_check(char *new, char *old, char *user)
|
||||
|
||||
void passwd_main(void)
|
||||
{
|
||||
uid_t myuid;
|
||||
uid_t myuid = getuid();
|
||||
struct passwd *pw = 0;
|
||||
struct spwd *sp;
|
||||
char *pass, *name, *encrypted = 0, salt[32];
|
||||
|
||||
// If we're root or not -lud, load specified user. Exit if not allowed.
|
||||
if (!(myuid = getuid()) || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) {
|
||||
if (!myuid || !(toys.optflags&(FLAG_l|FLAG_u|FLAG_d))) {
|
||||
if (*toys.optargs) pw = xgetpwnam(*toys.optargs);
|
||||
else pw = xgetpwuid(myuid);
|
||||
}
|
||||
if (!pw || (myuid && (myuid != pw->pw_uid))) error_exit("Not root");
|
||||
if (!pw || (myuid && myuid != pw->pw_uid)) error_exit("Not root");
|
||||
|
||||
// Get password from /etc/passwd or /etc/shadow
|
||||
// TODO: why still support non-shadow passwords...?
|
||||
@ -83,7 +83,7 @@ void passwd_main(void)
|
||||
*(encrypted = toybuf) = 0;
|
||||
} else {
|
||||
if (!TT.a) TT.a = "des";
|
||||
if (get_salt(salt, TT.a)<0) error_exit("bad -a '%s'", TT.a);
|
||||
if (get_salt(salt, TT.a, 1)<0) error_exit("bad -a '%s'", TT.a);
|
||||
|
||||
printf("Changing password for %s\n", name);
|
||||
if (myuid) {
|
||||
|
||||
@ -14,11 +14,10 @@ config MKPASSWD
|
||||
help
|
||||
usage: mkpasswd [-P FD] [-m TYPE] [-S SALT] [PASSWORD] [SALT]
|
||||
|
||||
Crypt PASSWORD using crypt(3)
|
||||
Encrypt PASSWORD using crypt(3), with either random or provided SALT.
|
||||
|
||||
-P FD Read password from file descriptor FD
|
||||
-m TYPE Encryption method (des, md5, sha256, or sha512; default is des)
|
||||
-S SALT
|
||||
*/
|
||||
|
||||
#define FOR_mkpasswd
|
||||
@ -31,24 +30,26 @@ GLOBALS(
|
||||
|
||||
void mkpasswd_main(void)
|
||||
{
|
||||
char salt[MAX_SALT_LEN] = {0,};
|
||||
char salt[32] = {0,};
|
||||
int i;
|
||||
|
||||
if (!TT.m) TT.m = "des";
|
||||
if (toys.optc == 2) {
|
||||
if (TT.S) error_exit("duplicate salt");
|
||||
TT.S = toys.optargs[1];
|
||||
}
|
||||
|
||||
if (-1 == (i = get_salt(salt, TT.m))) error_exit("bad -m");
|
||||
if (-1 == (i = get_salt(salt, TT.m ? : "des", !TT.S))) error_exit("bad -m");
|
||||
if (TT.S) {
|
||||
char *s = TT.S;
|
||||
char *mirv = strrchr(salt, '$'), *s = TT.S;
|
||||
|
||||
// In C locale, isalnum() means [A-Za-Z0-0]
|
||||
if (mirv) mirv++;
|
||||
else mirv = salt;
|
||||
|
||||
// In C locale, isalnum() means [a-zA-Z0-9]
|
||||
while (isalnum(*s) || *s == '.' || *s == '/') s++;
|
||||
if (*s) error_exit("salt not in [./A-Za-z0-9]");
|
||||
|
||||
snprintf(salt+i, sizeof(salt)-i, "%s", TT.S);
|
||||
if (*s || s-TT.S!=strlen(mirv))
|
||||
error_exit("bad SALT (need [a-zA-Z0-9] len %d)", (int)strlen(mirv));
|
||||
strcpy(mirv, TT.S);
|
||||
}
|
||||
|
||||
// Because read_password() doesn't have an fd argument
|
||||
@ -73,5 +74,5 @@ void mkpasswd_main(void)
|
||||
}
|
||||
|
||||
// encrypt & print the password
|
||||
xprintf("%s\n",crypt(*toys.optargs ? *toys.optargs : toybuf, salt));
|
||||
xprintf("%s\n", crypt(*toys.optargs ? *toys.optargs : toybuf, salt));
|
||||
}
|
||||
|
||||
@ -4,17 +4,18 @@
|
||||
*
|
||||
* See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/chsh.html
|
||||
|
||||
USE_CHSH(NEWTOY(chsh, "s:", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
|
||||
USE_CHSH(NEWTOY(chsh, ">1R:s:a", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
|
||||
|
||||
config CHSH
|
||||
bool "chsh"
|
||||
default n
|
||||
help
|
||||
usage: chsh [-s SHELL] [USER]
|
||||
usage: chsh [-s SHELL] [-R CHROOT_DIR] [USER]
|
||||
|
||||
Change user's login shell.
|
||||
|
||||
-s Use SHELL instead of prompting
|
||||
-R Act on CHROOT_DIR instead of host
|
||||
|
||||
Non-root users can only change their own shell to one listed in /etc/shells.
|
||||
*/
|
||||
@ -23,7 +24,7 @@ config CHSH
|
||||
#include "toys.h"
|
||||
|
||||
GLOBALS(
|
||||
char *s;
|
||||
char *s, *R;
|
||||
)
|
||||
|
||||
void chsh_main()
|
||||
@ -36,18 +37,14 @@ void chsh_main()
|
||||
// Get uid user information, may be discarded later
|
||||
|
||||
if ((user = *toys.optargs)) {
|
||||
passwd_info = xgetpwnam(user);
|
||||
if (geteuid() && strcmp(passwd_info->pw_name, user))
|
||||
error_exit("Permission denied\n");
|
||||
} else {
|
||||
passwd_info = xgetpwuid(getuid());
|
||||
user = passwd_info->pw_name;
|
||||
}
|
||||
if (strcmp((passwd_info = xgetpwnam(user))->pw_name, user))
|
||||
if (geteuid()) errno = EPERM, error_exit(0);
|
||||
} else user = (passwd_info = xgetpwuid(getuid()))->pw_name;
|
||||
|
||||
// Get a password, encrypt it, wipe it, and check it
|
||||
if (mlock(toybuf, sizeof(toybuf))) perror_exit("mlock");
|
||||
if (!(shadow_info = getspnam(passwd_info->pw_name))) perror_exit("getspnam");
|
||||
if (read_password(toybuf, sizeof(toybuf), "Password: ")) perror_exit("woaj"); //xexit();
|
||||
if (read_password(toybuf, sizeof(toybuf), "Password: ")) *toybuf = 0;
|
||||
if (!(encrypted = crypt(toybuf, shadow_info->sp_pwdp))) perror_exit("crypt");
|
||||
memset(toybuf, 0, sizeof(toybuf));
|
||||
munlock(toybuf, sizeof(toybuf)); // prevents memset from "optimizing" away.
|
||||
@ -57,21 +54,16 @@ void chsh_main()
|
||||
file = xfopen("/etc/shells", "r");
|
||||
if (toys.optflags) shell = TT.s;
|
||||
else {
|
||||
xprintf("Changing the login shell for %s\n"
|
||||
"Enter the new value, or press ENTER for default\n"
|
||||
" Login shell [%s]: ", user, passwd_info->pw_shell);
|
||||
xprintf("Login shell for %s [%s]:", user, passwd_info->pw_shell);
|
||||
if (!(shell = xgetline(stdin))) xexit();
|
||||
if (!*shell) xexit();
|
||||
}
|
||||
|
||||
// Verify supplied shell in /etc/shells, or get default shell
|
||||
if (strlen(shell))
|
||||
while ((line = xgetline(file)) && strcmp(shell, line)) free(line);
|
||||
if (*shell) while ((line = xgetline(file)) && strcmp(shell, line)) free(line);
|
||||
else do line = xgetline(file); while (line && *line != '/');
|
||||
if (!line) error_exit("Shell not found in '/etc/shells'");
|
||||
|
||||
// Update /etc/passwd
|
||||
passwd_info->pw_shell = line;
|
||||
if (-1 == update_password("/etc/passwd", user, NULL)) perror_exit("Failed to remove passwd entry");
|
||||
file = xfopen("/etc/passwd", "a");
|
||||
if (putpwent(passwd_info, file)) perror_exit("putwent");
|
||||
if (!update_password("/etc/passwd", user, line,6)) perror_exit("/etc/passwd");
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*
|
||||
* See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/groupadd.html
|
||||
|
||||
USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_GROUPADD(NEWTOY(groupadd, "<1>2R:g#<0>2147483647S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_GROUPADD(OLDTOY(addgroup, groupadd, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
|
||||
config GROUPADD
|
||||
@ -14,20 +14,19 @@ config GROUPADD
|
||||
help
|
||||
usage: groupadd [-S] [-g GID] [USER] GROUP
|
||||
|
||||
Add a group or add a user to a group
|
||||
Add a user to a group, or create a new group.
|
||||
|
||||
-g GID Group id
|
||||
-S Create a system group
|
||||
-g GID Group id
|
||||
-R Operate within chroot
|
||||
-S Create a system group
|
||||
*/
|
||||
|
||||
#define FOR_groupadd
|
||||
#include "toys.h"
|
||||
|
||||
#define GROUP_PATH "/etc/group"
|
||||
#define SECURE_GROUP_PATH "/etc/gshadow"
|
||||
|
||||
GLOBALS(
|
||||
long gid;
|
||||
long g;
|
||||
char *R;
|
||||
)
|
||||
|
||||
/* Add a new group to the system, if GID is given then that is validated
|
||||
@ -35,67 +34,58 @@ GLOBALS(
|
||||
* SYSTEM IDs are considered in the range 100 ... 999
|
||||
* update_group(), updates the entries in /etc/group, /etc/gshadow files
|
||||
*/
|
||||
static void new_group()
|
||||
{
|
||||
char *entry = NULL;
|
||||
|
||||
if (FLAG(g)) {
|
||||
if (TT.gid > INT_MAX) error_exit("gid should be less than '%d' ", INT_MAX);
|
||||
if (getgrgid(TT.gid)) error_exit("group '%ld' is in use", TT.gid);
|
||||
} else {
|
||||
if (FLAG(S)) TT.gid = CFG_TOYBOX_UID_SYS;
|
||||
else TT.gid = CFG_TOYBOX_UID_USR;
|
||||
//find unused gid
|
||||
while (getgrgid(TT.gid)) TT.gid++;
|
||||
}
|
||||
|
||||
entry = xmprintf("%s:%s:%ld:", *toys.optargs, "x", TT.gid);
|
||||
update_password(GROUP_PATH, *toys.optargs, entry);
|
||||
free(entry);
|
||||
entry = xmprintf("%s:%s::", *toys.optargs, "!");
|
||||
update_password(SECURE_GROUP_PATH, *toys.optargs, entry);
|
||||
free(entry);
|
||||
}
|
||||
|
||||
void groupadd_main(void)
|
||||
{
|
||||
struct group *grp = NULL;
|
||||
char *entry = NULL;
|
||||
struct group *grp = 0;
|
||||
char *entry = 0, *s, *gfile = "/etc/group", *gsfile = "/etc/gshadow";
|
||||
int i, len;
|
||||
|
||||
if (toys.optflags && toys.optc == 2)
|
||||
help_exit("options, user and group can't be together");
|
||||
|
||||
if (toys.optc == 2) { //add user to group
|
||||
//toys.optargs[0]- user, toys.optargs[1] - group
|
||||
xgetpwnam(*toys.optargs);
|
||||
if (!(grp = getgrnam(toys.optargs[1])))
|
||||
error_exit("group '%s' does not exist", toys.optargs[1]);
|
||||
if (!grp->gr_mem) entry = xmprintf("%s", *toys.optargs);
|
||||
else {
|
||||
int i;
|
||||
|
||||
for (i = 0; grp->gr_mem[i]; i++)
|
||||
if (!strcmp(grp->gr_mem[i], *toys.optargs)) return;
|
||||
|
||||
entry = xstrdup("");
|
||||
for (i=0; grp->gr_mem[i]; i++) {
|
||||
entry = xrealloc(entry, strlen(entry) + strlen(grp->gr_mem[i]) + 2);
|
||||
strcat(entry, grp->gr_mem[i]);
|
||||
strcat(entry, ",");
|
||||
}
|
||||
entry = xrealloc(entry, strlen(entry) + strlen(*toys.optargs) + 1);
|
||||
strcat(entry, *toys.optargs);
|
||||
}
|
||||
update_password(GROUP_PATH, grp->gr_name, entry);
|
||||
update_password(SECURE_GROUP_PATH, grp->gr_name, entry);
|
||||
free(entry);
|
||||
} else { //new group to be created
|
||||
char *s = *toys.optargs;
|
||||
|
||||
/* investigate the group to be created */
|
||||
if (getgrnam(s)) error_exit("'%s' in use", s);
|
||||
if (s[strcspn(s, ":/\n")] || strlen(s) > LOGIN_NAME_MAX)
|
||||
error_exit("bad name");
|
||||
new_group();
|
||||
if (TT.R) {
|
||||
gfile = xmprintf("%s%s", TT.R, gfile);
|
||||
gsfile = xmprintf("%s%s", TT.R, gsfile);
|
||||
}
|
||||
|
||||
// Add user to group?
|
||||
if (toys.optc == 2) {
|
||||
if (FLAG(g)|FLAG(S)) help_exit("No -gS with USER+GROUP");
|
||||
if (!(grp = getgrnam(s = toys.optargs[1]))) error_exit("no group '%s'", s);
|
||||
len = strlen(s)+1;
|
||||
xgetpwnam(s = *toys.optargs);
|
||||
|
||||
// Is this user already in this group?
|
||||
for (i = 0; grp->gr_mem[i]; i++) {
|
||||
if (!strcmp(grp->gr_mem[i], s)) return;
|
||||
len += strlen(grp->gr_mem[i])+1;
|
||||
}
|
||||
s = entry = xmalloc(len);
|
||||
for (i = 0;; i++) {
|
||||
if (i) *s++ = ',';
|
||||
if (!grp->gr_mem[i]) {
|
||||
strcpy(s, toys.optargs[1]);
|
||||
break;
|
||||
}
|
||||
s = stpcpy(s, grp->gr_mem[i]);
|
||||
}
|
||||
update_password(gfile, grp->gr_name, entry, 3);
|
||||
update_password(gsfile, grp->gr_name, entry, 3);
|
||||
free(entry);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// create new group
|
||||
if (getgrnam(s = *toys.optargs)) error_exit("'%s' in use", s);
|
||||
if (s[strcspn(s, ":/\n")] || strlen(s)>256) error_exit("bad '%s'", s);
|
||||
|
||||
// Find next unused GID or confirm selected GID isn't in use
|
||||
if (!FLAG(g)) {
|
||||
TT.g = FLAG(S) ? CFG_TOYBOX_UID_SYS : CFG_TOYBOX_UID_USR;
|
||||
while (getgrgid(TT.g)) TT.g++;
|
||||
} else if (getgrgid(TT.g)) error_exit("group '%ld' in use", TT.g);
|
||||
|
||||
sprintf(toybuf, "%s:x:%ld:", s, TT.g);
|
||||
update_password(gfile, s, toybuf, 0);
|
||||
sprintf(toybuf, "%s:!::", s);
|
||||
update_password(gsfile, s, toybuf, 0);
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
*
|
||||
* See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/groupdel.html
|
||||
|
||||
USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_GROUPDEL(NEWTOY(groupdel, "<1>2?", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
USE_GROUPDEL(OLDTOY(delgroup, groupdel, TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
|
||||
|
||||
config GROUPDEL
|
||||
@ -55,7 +55,7 @@ void groupdel_main(void)
|
||||
if (CFG_TOYBOX_FREE) endpwent();
|
||||
}
|
||||
|
||||
update_password("/etc/group", grp->gr_name, entry);
|
||||
update_password("/etc/gshadow", grp->gr_name, entry);
|
||||
update_password("/etc/group", grp->gr_name, entry, 3);
|
||||
update_password("/etc/gshadow", grp->gr_name, entry, 3);
|
||||
if (CFG_TOYBOX_FREE) free(entry);
|
||||
}
|
||||
|
||||
@ -39,6 +39,7 @@ GLOBALS(
|
||||
long gid;
|
||||
)
|
||||
|
||||
// TODO user exists error
|
||||
void useradd_main(void)
|
||||
{
|
||||
char *s = *toys.optargs, *entry;
|
||||
@ -119,7 +120,7 @@ void useradd_main(void)
|
||||
entry = xmprintf("%s:%s:%ld:%ld:%s:%s:%s", pwd.pw_name, pwd.pw_passwd,
|
||||
(long)pwd.pw_uid, (long)pwd.pw_gid, pwd.pw_gecos, pwd.pw_dir,
|
||||
pwd.pw_shell);
|
||||
if (update_password("/etc/passwd", pwd.pw_name, entry)) error_exit("updating passwd file failed");
|
||||
update_password("/etc/passwd", pwd.pw_name, entry, 0);
|
||||
free(entry);
|
||||
|
||||
if (toys.optflags & FLAG_S)
|
||||
@ -127,7 +128,7 @@ void useradd_main(void)
|
||||
(unsigned)(time(NULL))/(24*60*60)); //passwd is not set initially
|
||||
else entry = xmprintf("%s:!!:%u:0:99999:7:::", pwd.pw_name,
|
||||
(unsigned)(time(0))/(24*60*60)); //passwd is not set initially
|
||||
update_password("/etc/shadow", pwd.pw_name, entry);
|
||||
update_password("/etc/shadow", pwd.pw_name, entry, 0);
|
||||
free(entry);
|
||||
|
||||
// create home dir & copy skel dir to home
|
||||
|
||||
@ -92,8 +92,8 @@ void userdel_main(void)
|
||||
{
|
||||
struct passwd *pwd = xgetpwnam(*toys.optargs);
|
||||
|
||||
update_password("/etc/passwd", pwd->pw_name, NULL);
|
||||
update_password("/etc/shadow", pwd->pw_name, NULL);
|
||||
update_password("/etc/passwd", pwd->pw_name, 0, 0);
|
||||
update_password("/etc/shadow", pwd->pw_name, 0, 0);
|
||||
|
||||
// delete the group named USER, and remove user from group.
|
||||
// could update_password() be used for this?
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user