2007-10-07 13:44:02 +02:00
|
|
|
/*
|
2021-12-05 16:35:27 +01:00
|
|
|
* SPDX-FileCopyrightText: 1990 - 1994, Julianne Frances Haugh
|
|
|
|
* SPDX-FileCopyrightText: 1996 - 2000, Marek Michałkiewicz
|
|
|
|
* SPDX-FileCopyrightText: 2001 - 2006, Tomasz Kłoczko
|
|
|
|
* SPDX-FileCopyrightText: 2007 - 2008, Nicolas François
|
2007-10-07 13:44:02 +02:00
|
|
|
*
|
2021-12-05 16:35:27 +01:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
2007-11-11 00:46:11 +01:00
|
|
|
#ident "$Id$"
|
2007-10-07 13:47:01 +02:00
|
|
|
|
2007-10-07 13:44:02 +02:00
|
|
|
#include <errno.h>
|
|
|
|
#include <grp.h>
|
|
|
|
#include <pwd.h>
|
2007-10-07 13:47:01 +02:00
|
|
|
#include <stdio.h>
|
2009-04-23 13:17:22 +02:00
|
|
|
#include <assert.h>
|
2023-02-04 22:41:18 +01:00
|
|
|
|
|
|
|
#include "alloc.h"
|
2007-10-07 13:44:02 +02:00
|
|
|
#include "defines.h"
|
|
|
|
#include "getdef.h"
|
2007-10-07 13:47:01 +02:00
|
|
|
#include "prototypes.h"
|
* src/newgrp.c, src/chfn.c, src/groupmems.c, src/usermod.c,
src/userdel.c, src/chpasswd.c, src/grpck.c, src/gpasswd.c,
src/groupdel.c, src/chgpasswd.c, src/vipw.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/faillog.c,
src/sulogin.c, src/chsh.c, src/pwconv.c: Added splint annotations.
* src/userdel.c, src/pwconv.c, src/lastlog.c, src/grpck.c,
src/vipw.c, src/groupmod.c, src/passwd.c, src/pwck.c, src/login.c,
src/sulogin.c, src/usermod.c: Use return instead of exit at the
end of main().
* src/gpasswd.c, src/passwd.c, src/faillog.c: Use the exitcodes.h
exit codes.
* src/chpasswd.c: Added missing ||.
* src/nologin.c: Do not include exitcodes.h.
* src/nologin.c: Added brackets.
* src/nologin.c: Avoid assignments in comparisons.
2009-04-30 23:39:38 +02:00
|
|
|
/*@-exitarg@*/
|
2007-10-07 13:47:22 +02:00
|
|
|
#include "exitcodes.h"
|
2021-11-29 00:37:53 +01:00
|
|
|
#include "shadowlog.h"
|
* src/newgrp.c, src/chfn.c, src/groupmems.c, src/usermod.c,
src/userdel.c, src/chpasswd.c, src/grpck.c, src/gpasswd.c,
src/groupdel.c, src/chgpasswd.c, src/vipw.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/faillog.c,
src/sulogin.c, src/chsh.c, src/pwconv.c: Added splint annotations.
* src/userdel.c, src/pwconv.c, src/lastlog.c, src/grpck.c,
src/vipw.c, src/groupmod.c, src/passwd.c, src/pwck.c, src/login.c,
src/sulogin.c, src/usermod.c: Use return instead of exit at the
end of main().
* src/gpasswd.c, src/passwd.c, src/faillog.c: Use the exitcodes.h
exit codes.
* src/chpasswd.c: Added missing ||.
* src/nologin.c: Do not include exitcodes.h.
* src/nologin.c: Added brackets.
* src/nologin.c: Avoid assignments in comparisons.
2009-04-30 23:39:38 +02:00
|
|
|
|
2007-10-07 13:47:01 +02:00
|
|
|
/*
|
|
|
|
* Global variables
|
|
|
|
*/
|
* src/newgrp.c, src/userdel.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/pwconv.c, src/chpasswd.c, src/logoutd.c,
src/chfn.c, src/groupmems.c, src/usermod.c, src/pwunconv.c,
src/expiry.c, src/groupdel.c, src/chgpasswd.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c, src/chage.c,
src/groupadd.c, src/login.c, src/grpconv.c, src/groups.c,
src/grpunconv.c, src/chsh.c: Prog changed to a constant string.
2010-08-22 21:36:09 +02:00
|
|
|
const char *Prog;
|
* src/newgrp.c, src/userdel.c, src/grpck.c, src/gpasswd.c,
src/newusers.c, src/pwconv.c, src/chpasswd.c, src/logoutd.c,
src/chfn.c, src/groupmems.c, src/usermod.c, src/pwunconv.c,
src/expiry.c, src/groupdel.c, src/chgpasswd.c, src/useradd.c,
src/su.c, src/groupmod.c, src/passwd.c, src/pwck.c,
src/groupadd.c, src/chage.c, src/login.c, src/grpconv.c,
src/groups.c, src/grpunconv.c, src/chsh.c: Prog is now global (not
static to the file) so that it can be used by the helper functions
of libmisc.
* lib/prototypes.h: Added extern char *Prog.
* libmisc/find_new_gid.c, libmisc/find_new_uid.c: Indicate the
program name with the warning.
2008-09-06 14:51:53 +02:00
|
|
|
|
2007-10-07 13:47:22 +02:00
|
|
|
extern char **newenvp;
|
2007-10-07 13:44:02 +02:00
|
|
|
|
|
|
|
#ifdef HAVE_SETGROUPS
|
|
|
|
static int ngroups;
|
2009-04-23 22:37:00 +02:00
|
|
|
static /*@null@*/ /*@only@*/GETGROUPS_T *grouplist;
|
2007-10-07 13:44:02 +02:00
|
|
|
#endif
|
|
|
|
|
2008-06-09 20:23:23 +02:00
|
|
|
static bool is_newgrp;
|
2007-10-07 13:44:02 +02:00
|
|
|
|
2008-04-17 00:04:46 +02:00
|
|
|
#ifdef WITH_AUDIT
|
2009-04-23 22:37:00 +02:00
|
|
|
static char audit_buf[80];
|
2008-04-17 00:04:46 +02:00
|
|
|
#endif
|
|
|
|
|
2007-10-07 13:44:02 +02:00
|
|
|
/* local function prototypes */
|
2007-10-07 13:44:59 +02:00
|
|
|
static void usage (void);
|
2008-01-02 00:35:55 +01:00
|
|
|
static void check_perms (const struct group *grp,
|
|
|
|
struct passwd *pwd,
|
|
|
|
const char *groupname);
|
2008-01-06 13:31:06 +01:00
|
|
|
static void syslog_sg (const char *name, const char *group);
|
2007-10-07 13:44:02 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* usage - print command usage message
|
|
|
|
*/
|
2007-10-07 13:44:59 +02:00
|
|
|
static void usage (void)
|
2007-10-07 13:44:02 +02:00
|
|
|
{
|
2008-06-09 20:23:23 +02:00
|
|
|
if (is_newgrp) {
|
2009-04-23 22:37:00 +02:00
|
|
|
(void) fputs (_("Usage: newgrp [-] [group]\n"), stderr);
|
2008-06-09 20:23:23 +02:00
|
|
|
} else {
|
2009-04-23 22:37:00 +02:00
|
|
|
(void) fputs (_("Usage: sg group [[-c] command]\n"), stderr);
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
|
|
|
|
2017-08-14 11:38:46 +02:00
|
|
|
static bool ingroup(const char *name, struct group *gr)
|
|
|
|
{
|
|
|
|
char **look;
|
|
|
|
bool notfound = true;
|
|
|
|
|
|
|
|
look = gr->gr_mem;
|
|
|
|
while (*look && notfound)
|
|
|
|
notfound = strcmp (*look++, name);
|
|
|
|
|
|
|
|
return !notfound;
|
|
|
|
}
|
|
|
|
|
2007-10-07 13:46:34 +02:00
|
|
|
/*
|
2017-08-14 11:38:46 +02:00
|
|
|
* find_matching_group - search all groups of a gr's group id for
|
2007-10-07 13:46:34 +02:00
|
|
|
* membership of a given username
|
2017-08-14 11:38:46 +02:00
|
|
|
* but check gr itself first
|
2007-10-07 13:46:34 +02:00
|
|
|
*/
|
2017-08-14 11:38:46 +02:00
|
|
|
static /*@null@*/struct group *find_matching_group (const char *name, struct group *gr)
|
2007-10-07 13:46:34 +02:00
|
|
|
{
|
2017-08-14 11:38:46 +02:00
|
|
|
gid_t gid = gr->gr_gid;
|
|
|
|
|
|
|
|
if (ingroup(name, gr))
|
|
|
|
return gr;
|
2007-10-07 13:46:34 +02:00
|
|
|
|
|
|
|
setgrent ();
|
|
|
|
while ((gr = getgrent ()) != NULL) {
|
|
|
|
if (gr->gr_gid != gid) {
|
|
|
|
continue;
|
|
|
|
}
|
2007-10-07 13:47:01 +02:00
|
|
|
|
2007-10-07 13:46:34 +02:00
|
|
|
/*
|
|
|
|
* A group with matching GID was found.
|
|
|
|
* Test for membership of 'name'.
|
|
|
|
*/
|
2017-08-14 11:38:46 +02:00
|
|
|
if (ingroup(name, gr))
|
2007-10-07 13:46:34 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
endgrent ();
|
|
|
|
return gr;
|
|
|
|
}
|
|
|
|
|
2008-01-02 00:35:55 +01:00
|
|
|
/*
|
|
|
|
* check_perms - check if the user is allowed to switch to this group
|
|
|
|
*
|
|
|
|
* If needed, the user will be authenticated.
|
|
|
|
*
|
|
|
|
* It will not return if the user could not be authenticated.
|
|
|
|
*/
|
|
|
|
static void check_perms (const struct group *grp,
|
|
|
|
struct passwd *pwd,
|
|
|
|
const char *groupname)
|
|
|
|
{
|
2008-06-09 20:23:23 +02:00
|
|
|
bool needspasswd = false;
|
2008-01-02 00:35:55 +01:00
|
|
|
struct spwd *spwd;
|
|
|
|
char *cp;
|
|
|
|
const char *cpasswd;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* see if she is a member of this group (i.e. in the list of
|
|
|
|
* members of the group, or if the group is her primary group).
|
|
|
|
*
|
|
|
|
* If she isn't a member, she needs to provide the group password.
|
|
|
|
* If there is no group password, she will be denied access
|
|
|
|
* anyway.
|
|
|
|
*
|
|
|
|
*/
|
2008-06-09 20:23:23 +02:00
|
|
|
if ( (grp->gr_gid != pwd->pw_gid)
|
|
|
|
&& !is_on_list (grp->gr_mem, pwd->pw_name)) {
|
|
|
|
needspasswd = true;
|
|
|
|
}
|
2008-01-02 00:35:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If she does not have either a shadowed password, or a regular
|
|
|
|
* password, and the group has a password, she needs to give the
|
|
|
|
* group password.
|
|
|
|
*/
|
|
|
|
spwd = xgetspnam (pwd->pw_name);
|
2008-06-09 20:23:23 +02:00
|
|
|
if (NULL != spwd) {
|
Fix covscan RESOURCE_LEAK
Error: RESOURCE_LEAK (CWE-772): [#def1]
shadow-4.8.1/lib/commonio.c:320: alloc_fn: Storage is returned from allocation function "fopen_set_perms".
shadow-4.8.1/lib/commonio.c:320: var_assign: Assigning: "bkfp" = storage returned from "fopen_set_perms(backup, "w", &sb)".
shadow-4.8.1/lib/commonio.c:329: noescape: Resource "bkfp" is not freed or pointed-to in "putc".
shadow-4.8.1/lib/commonio.c:334: noescape: Resource "bkfp" is not freed or pointed-to in "fflush".
shadow-4.8.1/lib/commonio.c:339: noescape: Resource "bkfp" is not freed or pointed-to in "fileno".
shadow-4.8.1/lib/commonio.c:342: leaked_storage: Variable "bkfp" going out of scope leaks the storage it points to.
340| || (fclose (bkfp) != 0)) {
341| /* FIXME: unlink the backup file? */
342|-> return -1;
343| }
344|
Error: RESOURCE_LEAK (CWE-772): [#def2]
shadow-4.8.1/libmisc/addgrps.c:69: alloc_fn: Storage is returned from allocation function "malloc".
shadow-4.8.1/libmisc/addgrps.c:69: var_assign: Assigning: "grouplist" = storage returned from "malloc(i * 4UL)".
shadow-4.8.1/libmisc/addgrps.c:73: noescape: Resource "grouplist" is not freed or pointed-to in "getgroups". [Note: The source code implementation of the function has been overridden by a builtin model.]
shadow-4.8.1/libmisc/addgrps.c:126: leaked_storage: Variable "grouplist" going out of scope leaks the storage it points to.
124| }
125|
126|-> return 0;
127| }
128| #else /* HAVE_SETGROUPS && !USE_PAM */
Error: RESOURCE_LEAK (CWE-772): [#def3]
shadow-4.8.1/libmisc/chowntty.c:62: alloc_fn: Storage is returned from allocation function "getgr_nam_gid".
shadow-4.8.1/libmisc/chowntty.c:62: var_assign: Assigning: "grent" = storage returned from "getgr_nam_gid(getdef_str("TTYGROUP"))".
shadow-4.8.1/libmisc/chowntty.c:98: leaked_storage: Variable "grent" going out of scope leaks the storage it points to.
96| */
97| #endif
98|-> }
99|
Error: RESOURCE_LEAK (CWE-772): [#def4]
shadow-4.8.1/libmisc/copydir.c:742: open_fn: Returning handle opened by "open". [Note: The source code implementation of the function has been overridden by a user model.]
shadow-4.8.1/libmisc/copydir.c:742: var_assign: Assigning: "ifd" = handle returned from "open(src, 0)".
shadow-4.8.1/libmisc/copydir.c:748: leaked_handle: Handle variable "ifd" going out of scope leaks the handle.
746| #ifdef WITH_SELINUX
747| if (set_selinux_file_context (dst, NULL) != 0) {
748|-> return -1;
749| }
750| #endif /* WITH_SELINUX */
Error: RESOURCE_LEAK (CWE-772): [#def5]
shadow-4.8.1/libmisc/copydir.c:751: open_fn: Returning handle opened by "open". [Note: The source code implementation of the function has been overridden by a user model.]
shadow-4.8.1/libmisc/copydir.c:751: var_assign: Assigning: "ofd" = handle returned from "open(dst, 577, statp->st_mode & 0xfffU)".
shadow-4.8.1/libmisc/copydir.c:752: noescape: Resource "ofd" is not freed or pointed-to in "fchown_if_needed".
shadow-4.8.1/libmisc/copydir.c:775: leaked_handle: Handle variable "ofd" going out of scope leaks the handle.
773| ) {
774| (void) close (ifd);
775|-> return -1;
776| }
777|
Error: RESOURCE_LEAK (CWE-772): [#def7]
shadow-4.8.1/libmisc/idmapping.c:188: alloc_fn: Storage is returned from allocation function "xmalloc".
shadow-4.8.1/libmisc/idmapping.c:188: var_assign: Assigning: "buf" = storage returned from "xmalloc(bufsize)".
shadow-4.8.1/libmisc/idmapping.c:188: var_assign: Assigning: "pos" = "buf".
shadow-4.8.1/libmisc/idmapping.c:213: noescape: Resource "buf" is not freed or pointed-to in "write".
shadow-4.8.1/libmisc/idmapping.c:219: leaked_storage: Variable "pos" going out of scope leaks the storage it points to.
shadow-4.8.1/libmisc/idmapping.c:219: leaked_storage: Variable "buf" going out of scope leaks the storage it points to.
217| }
218| close(fd);
219|-> }
Error: RESOURCE_LEAK (CWE-772): [#def8]
shadow-4.8.1/libmisc/list.c:211: alloc_fn: Storage is returned from allocation function "xstrdup".
shadow-4.8.1/libmisc/list.c:211: var_assign: Assigning: "members" = storage returned from "xstrdup(comma)".
shadow-4.8.1/libmisc/list.c:217: var_assign: Assigning: "cp" = "members".
shadow-4.8.1/libmisc/list.c:218: noescape: Resource "cp" is not freed or pointed-to in "strchr".
shadow-4.8.1/libmisc/list.c:244: leaked_storage: Variable "cp" going out of scope leaks the storage it points to.
shadow-4.8.1/libmisc/list.c:244: leaked_storage: Variable "members" going out of scope leaks the storage it points to.
242| if ('\0' == *members) {
243| *array = (char *) 0;
244|-> return array;
245| }
246|
Error: RESOURCE_LEAK (CWE-772): [#def11]
shadow-4.8.1/libmisc/myname.c:61: alloc_fn: Storage is returned from allocation function "xgetpwnam".
shadow-4.8.1/libmisc/myname.c:61: var_assign: Assigning: "pw" = storage returned from "xgetpwnam(cp)".
shadow-4.8.1/libmisc/myname.c:67: leaked_storage: Variable "pw" going out of scope leaks the storage it points to.
65| }
66|
67|-> return xgetpwuid (ruid);
68| }
69|
Error: RESOURCE_LEAK (CWE-772): [#def12]
shadow-4.8.1/libmisc/user_busy.c:260: alloc_fn: Storage is returned from allocation function "opendir".
shadow-4.8.1/libmisc/user_busy.c:260: var_assign: Assigning: "task_dir" = storage returned from "opendir(task_path)".
shadow-4.8.1/libmisc/user_busy.c:262: noescape: Resource "task_dir" is not freed or pointed-to in "readdir".
shadow-4.8.1/libmisc/user_busy.c:278: leaked_storage: Variable "task_dir" going out of scope leaks the storage it points to.
276| _("%s: user %s is currently used by process %d\n"),
277| Prog, name, pid);
278|-> return 1;
279| }
280| }
Error: RESOURCE_LEAK (CWE-772): [#def20]
shadow-4.8.1/src/newgrp.c:162: alloc_fn: Storage is returned from allocation function "xgetspnam".
shadow-4.8.1/src/newgrp.c:162: var_assign: Assigning: "spwd" = storage returned from "xgetspnam(pwd->pw_name)".
shadow-4.8.1/src/newgrp.c:234: leaked_storage: Variable "spwd" going out of scope leaks the storage it points to.
232| }
233|
234|-> return;
235|
236| failure:
Error: RESOURCE_LEAK (CWE-772): [#def21]
shadow-4.8.1/src/passwd.c:530: alloc_fn: Storage is returned from allocation function "xstrdup".
shadow-4.8.1/src/passwd.c:530: var_assign: Assigning: "cp" = storage returned from "xstrdup(crypt_passwd)".
shadow-4.8.1/src/passwd.c:551: noescape: Resource "cp" is not freed or pointed-to in "strlen".
shadow-4.8.1/src/passwd.c:554: noescape: Resource "cp" is not freed or pointed-to in "strcat". [Note: The source code implementation of the function has been overridden by a builtin model.]
shadow-4.8.1/src/passwd.c:555: overwrite_var: Overwriting "cp" in "cp = newpw" leaks the storage that "cp" points to.
553| strcpy (newpw, "!");
554| strcat (newpw, cp);
555|-> cp = newpw;
556| }
557| return cp;
2021-06-14 12:39:48 +02:00
|
|
|
pwd->pw_passwd = xstrdup (spwd->sp_pwdp);
|
2021-11-10 12:02:04 +01:00
|
|
|
spw_free (spwd);
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2008-01-02 00:35:55 +01:00
|
|
|
|
2008-06-09 20:23:23 +02:00
|
|
|
if ((pwd->pw_passwd[0] == '\0') && (grp->gr_passwd[0] != '\0')) {
|
|
|
|
needspasswd = true;
|
|
|
|
}
|
2008-01-02 00:35:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now I see about letting her into the group she requested. If she
|
|
|
|
* is the root user, I'll let her in without having to prompt for
|
|
|
|
* the password. Otherwise I ask for a password if she flunked one
|
|
|
|
* of the tests above.
|
|
|
|
*/
|
2008-06-09 20:23:23 +02:00
|
|
|
if ((getuid () != 0) && needspasswd) {
|
2008-01-02 00:35:55 +01:00
|
|
|
/*
|
|
|
|
* get the password from her, and set the salt for
|
|
|
|
* the decryption from the group file.
|
|
|
|
*/
|
2022-09-27 21:21:35 +02:00
|
|
|
cp = agetpass (_("Password: "));
|
2008-06-09 20:23:23 +02:00
|
|
|
if (NULL == cp) {
|
2008-01-02 00:35:55 +01:00
|
|
|
goto failure;
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2008-01-02 00:35:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* encrypt the key she gave us using the salt from the
|
|
|
|
* password in the group file. The result of this encryption
|
|
|
|
* must match the previously encrypted value in the file.
|
|
|
|
*/
|
|
|
|
cpasswd = pw_encrypt (cp, grp->gr_passwd);
|
2022-09-27 21:21:35 +02:00
|
|
|
erase_pass (cp);
|
2008-01-02 00:35:55 +01:00
|
|
|
|
2013-08-03 23:07:06 +02:00
|
|
|
if (NULL == cpasswd) {
|
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: failed to crypt password with previous salt: %s\n"),
|
|
|
|
Prog, strerror (errno));
|
|
|
|
SYSLOG ((LOG_INFO,
|
|
|
|
"Failed to crypt password with previous salt of group '%s'",
|
|
|
|
groupname));
|
|
|
|
goto failure;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grp->gr_passwd[0] == '\0' ||
|
2008-01-02 00:35:55 +01:00
|
|
|
strcmp (cpasswd, grp->gr_passwd) != 0) {
|
2008-03-07 21:21:15 +01:00
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
snprintf (audit_buf, sizeof(audit_buf),
|
2008-06-13 22:21:24 +02:00
|
|
|
"authentication new-gid=%lu",
|
|
|
|
(unsigned long) grp->gr_gid);
|
2008-03-07 21:21:15 +01:00
|
|
|
audit_logger (AUDIT_GRP_AUTH, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
audit_buf, NULL, getuid (), 0);
|
2008-03-07 21:21:15 +01:00
|
|
|
#endif
|
2008-01-02 00:35:55 +01:00
|
|
|
SYSLOG ((LOG_INFO,
|
* src/chfn.c, src/chsh.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/grpck.c, src/login.c, src/logoutd.c,
src/newgrp.c, src/newusers.c, src/passwd.c, src/pwck.c,
src/suauth.c, src/useradd.c, src/userdel.c, src/usermod.c,
src/vipw.c: Complete the switch from the `' quotation style to ''.
Do it also in SYSLOG messages. Quote some parameters. All this
permits to merge some messages.
2008-08-06 17:51:52 +02:00
|
|
|
"Invalid password for group '%s' from '%s'",
|
2008-01-02 00:35:55 +01:00
|
|
|
groupname, pwd->pw_name));
|
2009-04-23 22:37:00 +02:00
|
|
|
(void) sleep (1);
|
|
|
|
(void) fputs (_("Invalid password.\n"), stderr);
|
2008-01-02 00:35:55 +01:00
|
|
|
goto failure;
|
|
|
|
}
|
2008-03-07 21:21:15 +01:00
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
snprintf (audit_buf, sizeof(audit_buf),
|
2008-06-13 22:21:24 +02:00
|
|
|
"authentication new-gid=%lu",
|
|
|
|
(unsigned long) grp->gr_gid);
|
2008-03-07 21:21:15 +01:00
|
|
|
audit_logger (AUDIT_GRP_AUTH, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
audit_buf, NULL, getuid (), 1);
|
2008-03-07 21:21:15 +01:00
|
|
|
#endif
|
2008-01-02 00:35:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
failure:
|
|
|
|
/* The closelog is probably unnecessary, but it does no
|
|
|
|
* harm. -- JWP
|
|
|
|
*/
|
|
|
|
closelog ();
|
|
|
|
#ifdef WITH_AUDIT
|
2008-02-14 19:51:37 +01:00
|
|
|
if (groupname) {
|
|
|
|
snprintf (audit_buf, sizeof(audit_buf),
|
|
|
|
"changing new-group=%s", groupname);
|
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
audit_buf, NULL, getuid (), 0);
|
2008-02-14 19:51:37 +01:00
|
|
|
} else {
|
2008-06-13 22:21:24 +02:00
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
"changing", NULL, getuid (), 0);
|
2008-02-14 19:51:37 +01:00
|
|
|
}
|
2008-01-02 00:35:55 +01:00
|
|
|
#endif
|
2009-04-23 22:37:00 +02:00
|
|
|
exit (EXIT_FAILURE);
|
2008-01-02 00:35:55 +01:00
|
|
|
}
|
|
|
|
|
2008-01-02 00:54:51 +01:00
|
|
|
/*
|
|
|
|
* syslog_sg - log the change of group to syslog
|
|
|
|
*
|
2017-10-22 22:28:57 +02:00
|
|
|
* The logout will also be logged when the user will quit the
|
2008-01-02 00:54:51 +01:00
|
|
|
* sg/newgrp session.
|
|
|
|
*/
|
2008-01-06 13:31:06 +01:00
|
|
|
static void syslog_sg (const char *name, const char *group)
|
2008-01-02 00:54:51 +01:00
|
|
|
{
|
2008-01-06 13:31:06 +01:00
|
|
|
const char *loginname = getlogin ();
|
|
|
|
const char *tty = ttyname (0);
|
2015-08-06 07:11:06 +02:00
|
|
|
char *free_login = NULL, *free_tty = NULL;
|
2008-01-02 00:54:51 +01:00
|
|
|
|
2008-06-09 20:23:23 +02:00
|
|
|
if (loginname != NULL) {
|
2015-08-06 07:11:06 +02:00
|
|
|
free_login = xstrdup (loginname);
|
|
|
|
loginname = free_login;
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
|
|
|
if (tty != NULL) {
|
2015-08-06 07:11:06 +02:00
|
|
|
free_tty = xstrdup (tty);
|
|
|
|
tty = free_tty;
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2008-01-02 00:54:51 +01:00
|
|
|
|
2008-06-09 20:23:23 +02:00
|
|
|
if (loginname == NULL) {
|
2008-01-02 00:54:51 +01:00
|
|
|
loginname = "???";
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
|
|
|
if (tty == NULL) {
|
2008-01-02 00:54:51 +01:00
|
|
|
tty = "???";
|
2008-06-09 20:23:23 +02:00
|
|
|
} else if (strncmp (tty, "/dev/", 5) == 0) {
|
2008-01-02 00:54:51 +01:00
|
|
|
tty += 5;
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2008-01-02 00:54:51 +01:00
|
|
|
SYSLOG ((LOG_INFO,
|
* src/chfn.c, src/chsh.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/grpck.c, src/login.c, src/logoutd.c,
src/newgrp.c, src/newusers.c, src/passwd.c, src/pwck.c,
src/suauth.c, src/useradd.c, src/userdel.c, src/usermod.c,
src/vipw.c: Complete the switch from the `' quotation style to ''.
Do it also in SYSLOG messages. Quote some parameters. All this
permits to merge some messages.
2008-08-06 17:51:52 +02:00
|
|
|
"user '%s' (login '%s' on %s) switched to group '%s'",
|
2008-01-02 00:54:51 +01:00
|
|
|
name, loginname, tty, group));
|
|
|
|
#ifdef USE_PAM
|
|
|
|
/*
|
|
|
|
* We want to fork and exec the new shell in the child, leaving the
|
|
|
|
* parent waiting to log the session close.
|
|
|
|
*
|
|
|
|
* The parent must ignore signals generated from the console
|
|
|
|
* (SIGINT, SIGQUIT, SIGHUP) which might make the parent terminate
|
|
|
|
* before its child. When bash is exec'ed as the subshell, it
|
|
|
|
* generates a new process group id for itself, and consequently
|
|
|
|
* only SIGHUP, which is sent to all process groups in the session,
|
|
|
|
* can reach the parent. However, since arbitrary programs can be
|
|
|
|
* specified as login shells, there is no such guarantee in general.
|
|
|
|
* For the same reason, we must also ignore stop signals generated
|
|
|
|
* from the console (SIGTSTP, SIGTTIN, and SIGTTOU) in order to
|
|
|
|
* avoid any possibility of the parent being stopped when it
|
|
|
|
* receives SIGCHLD from the terminating subshell. -- JWP
|
|
|
|
*/
|
|
|
|
{
|
* src/newgrp.c: Limit the scope of variable pid.
* src/login_nopam.c: Limit the scope of variables end, lineno, i,
str_len.
* src/logoutd.c: Limit the scope of variable c.
* src/vipw.c: Re-indent.
* src/vipw.c: Close the file after the creation of the backup.
* src/useradd.c (set_default): Close input file on failure.
* src/useradd.c: Limit the scope of variables spool, file, fd, gr,
gid, mode.
* src/passwd.c: Limit the scope of variables last and ok.
* src/chage.c: Fix typo (non breaking space).
* src/login.c: Limit the scope of variables erasechar killchar, c,
failed.
* src/groups.c: Limit the scope of variable ngroups, pri_grp, i.
* src/id.c: Limit the scope of variable i.
2010-03-23 12:26:34 +01:00
|
|
|
pid_t child;
|
2008-01-02 00:54:51 +01:00
|
|
|
|
2008-06-13 22:21:24 +02:00
|
|
|
/* Ignore these signals. The signal handlers will later be
|
|
|
|
* restored to the default handlers. */
|
|
|
|
(void) signal (SIGINT, SIG_IGN);
|
|
|
|
(void) signal (SIGQUIT, SIG_IGN);
|
|
|
|
(void) signal (SIGHUP, SIG_IGN);
|
|
|
|
(void) signal (SIGTSTP, SIG_IGN);
|
|
|
|
(void) signal (SIGTTIN, SIG_IGN);
|
|
|
|
(void) signal (SIGTTOU, SIG_IGN);
|
2023-04-26 13:59:51 +02:00
|
|
|
/* set SIGCHLD to default for waitpid */
|
|
|
|
(void) signal(SIGCHLD, SIG_DFL);
|
|
|
|
|
2008-01-02 00:54:51 +01:00
|
|
|
child = fork ();
|
2008-06-13 22:21:24 +02:00
|
|
|
if ((pid_t)-1 == child) {
|
2008-01-02 00:54:51 +01:00
|
|
|
/* error in fork() */
|
2008-03-07 21:21:15 +01:00
|
|
|
fprintf (stderr, _("%s: failure forking: %s\n"),
|
2008-01-02 00:54:51 +01:00
|
|
|
is_newgrp ? "newgrp" : "sg", strerror (errno));
|
|
|
|
#ifdef WITH_AUDIT
|
2008-02-14 19:35:51 +01:00
|
|
|
if (group) {
|
|
|
|
snprintf (audit_buf, sizeof(audit_buf),
|
|
|
|
"changing new-group=%s", group);
|
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
audit_buf, NULL, getuid (), 0);
|
2008-02-14 19:35:51 +01:00
|
|
|
} else {
|
2008-06-13 22:21:24 +02:00
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
"changing", NULL, getuid (), 0);
|
2008-02-14 19:35:51 +01:00
|
|
|
}
|
2008-01-02 00:54:51 +01:00
|
|
|
#endif
|
2009-04-23 22:37:00 +02:00
|
|
|
exit (EXIT_FAILURE);
|
2008-06-09 20:23:23 +02:00
|
|
|
} else if (child != 0) {
|
2008-01-02 00:54:51 +01:00
|
|
|
/* parent - wait for child to finish, then log session close */
|
|
|
|
int cst = 0;
|
2008-01-22 00:33:43 +01:00
|
|
|
gid_t gid = getgid();
|
|
|
|
struct group *grp = getgrgid (gid);
|
* src/newgrp.c: Limit the scope of variable pid.
* src/login_nopam.c: Limit the scope of variables end, lineno, i,
str_len.
* src/logoutd.c: Limit the scope of variable c.
* src/vipw.c: Re-indent.
* src/vipw.c: Close the file after the creation of the backup.
* src/useradd.c (set_default): Close input file on failure.
* src/useradd.c: Limit the scope of variables spool, file, fd, gr,
gid, mode.
* src/passwd.c: Limit the scope of variables last and ok.
* src/chage.c: Fix typo (non breaking space).
* src/login.c: Limit the scope of variables erasechar killchar, c,
failed.
* src/groups.c: Limit the scope of variable ngroups, pri_grp, i.
* src/id.c: Limit the scope of variable i.
2010-03-23 12:26:34 +01:00
|
|
|
pid_t pid;
|
2008-01-02 00:54:51 +01:00
|
|
|
|
|
|
|
do {
|
|
|
|
errno = 0;
|
|
|
|
pid = waitpid (child, &cst, WUNTRACED);
|
2008-06-09 20:23:23 +02:00
|
|
|
if ((pid == child) && (WIFSTOPPED (cst) != 0)) {
|
2010-03-23 14:05:06 +01:00
|
|
|
/* The child (shell) was suspended.
|
|
|
|
* Suspend sg/newgrp. */
|
|
|
|
kill (getpid (), SIGSTOP);
|
2008-01-02 00:54:51 +01:00
|
|
|
/* wake child when resumed */
|
|
|
|
kill (child, SIGCONT);
|
|
|
|
}
|
2008-06-09 20:23:23 +02:00
|
|
|
} while ( ((pid == child) && (WIFSTOPPED (cst) != 0))
|
|
|
|
|| ((pid != child) && (errno == EINTR)));
|
2008-01-02 00:54:51 +01:00
|
|
|
/* local, no need for xgetgrgid */
|
2008-01-22 00:33:43 +01:00
|
|
|
if (NULL != grp) {
|
|
|
|
SYSLOG ((LOG_INFO,
|
* src/chfn.c, src/chsh.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/grpck.c, src/login.c, src/logoutd.c,
src/newgrp.c, src/newusers.c, src/passwd.c, src/pwck.c,
src/suauth.c, src/useradd.c, src/userdel.c, src/usermod.c,
src/vipw.c: Complete the switch from the `' quotation style to ''.
Do it also in SYSLOG messages. Quote some parameters. All this
permits to merge some messages.
2008-08-06 17:51:52 +02:00
|
|
|
"user '%s' (login '%s' on %s) returned to group '%s'",
|
2008-01-22 00:33:43 +01:00
|
|
|
name, loginname, tty, grp->gr_name));
|
|
|
|
} else {
|
|
|
|
SYSLOG ((LOG_INFO,
|
* src/chfn.c, src/chsh.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/grpck.c, src/login.c, src/logoutd.c,
src/newgrp.c, src/newusers.c, src/passwd.c, src/pwck.c,
src/suauth.c, src/useradd.c, src/userdel.c, src/usermod.c,
src/vipw.c: Complete the switch from the `' quotation style to ''.
Do it also in SYSLOG messages. Quote some parameters. All this
permits to merge some messages.
2008-08-06 17:51:52 +02:00
|
|
|
"user '%s' (login '%s' on %s) returned to group '%lu'",
|
2008-06-13 22:21:24 +02:00
|
|
|
name, loginname, tty,
|
|
|
|
(unsigned long) gid));
|
2008-01-22 00:33:43 +01:00
|
|
|
/* Either the user's passwd entry has a
|
|
|
|
* GID that does not match with any group,
|
|
|
|
* or the group was deleted while the user
|
|
|
|
* was in a newgrp session.*/
|
|
|
|
SYSLOG ((LOG_WARN,
|
* src/chfn.c, src/chsh.c, src/groupdel.c, src/groupmems.c,
src/groupmod.c, src/grpck.c, src/login.c, src/logoutd.c,
src/newgrp.c, src/newusers.c, src/passwd.c, src/pwck.c,
src/suauth.c, src/useradd.c, src/userdel.c, src/usermod.c,
src/vipw.c: Complete the switch from the `' quotation style to ''.
Do it also in SYSLOG messages. Quote some parameters. All this
permits to merge some messages.
2008-08-06 17:51:52 +02:00
|
|
|
"unknown GID '%lu' used by user '%s'",
|
2008-06-13 22:21:24 +02:00
|
|
|
(unsigned long) gid, name));
|
2008-01-22 00:33:43 +01:00
|
|
|
}
|
2008-01-02 00:54:51 +01:00
|
|
|
closelog ();
|
2009-05-22 13:10:02 +02:00
|
|
|
exit ((0 != WIFEXITED (cst)) ? WEXITSTATUS (cst)
|
|
|
|
: WTERMSIG (cst) + 128);
|
2008-01-02 00:54:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* child - restore signals to their default state */
|
2008-06-13 22:21:24 +02:00
|
|
|
(void) signal (SIGINT, SIG_DFL);
|
|
|
|
(void) signal (SIGQUIT, SIG_DFL);
|
|
|
|
(void) signal (SIGHUP, SIG_DFL);
|
|
|
|
(void) signal (SIGTSTP, SIG_DFL);
|
|
|
|
(void) signal (SIGTTIN, SIG_DFL);
|
|
|
|
(void) signal (SIGTTOU, SIG_DFL);
|
2008-01-02 00:54:51 +01:00
|
|
|
}
|
|
|
|
#endif /* USE_PAM */
|
2015-08-06 07:11:06 +02:00
|
|
|
free(free_login);
|
|
|
|
free(free_tty);
|
2008-01-02 00:54:51 +01:00
|
|
|
}
|
|
|
|
|
2007-10-07 13:44:02 +02:00
|
|
|
/*
|
|
|
|
* newgrp - change the invokers current real and effective group id
|
|
|
|
*/
|
2007-10-07 13:44:59 +02:00
|
|
|
int main (int argc, char **argv)
|
2007-10-07 13:44:02 +02:00
|
|
|
{
|
2008-06-09 20:23:23 +02:00
|
|
|
bool initflag = false;
|
2007-10-07 13:44:59 +02:00
|
|
|
int i;
|
2017-05-22 13:42:35 +02:00
|
|
|
bool is_member = false;
|
2008-06-09 20:23:23 +02:00
|
|
|
bool cflag = false;
|
2007-10-07 13:47:22 +02:00
|
|
|
int err = 0;
|
2007-10-07 13:44:02 +02:00
|
|
|
gid_t gid;
|
|
|
|
char *cp;
|
2022-01-03 12:17:22 +01:00
|
|
|
const char *progbase;
|
2008-01-02 00:35:55 +01:00
|
|
|
const char *name, *prog;
|
2007-10-07 13:44:02 +02:00
|
|
|
char *group = NULL;
|
2007-10-07 13:44:59 +02:00
|
|
|
char *command = NULL;
|
|
|
|
char **envp = environ;
|
2007-10-07 13:44:02 +02:00
|
|
|
struct passwd *pwd;
|
2009-04-23 22:37:00 +02:00
|
|
|
/*@null@*/struct group *grp;
|
2007-10-07 13:44:59 +02:00
|
|
|
|
2007-10-07 13:44:02 +02:00
|
|
|
#ifdef SHADOWGRP
|
|
|
|
struct sgrp *sgrp;
|
|
|
|
#endif
|
|
|
|
|
2007-10-07 13:47:11 +02:00
|
|
|
#ifdef WITH_AUDIT
|
|
|
|
audit_help_open ();
|
|
|
|
#endif
|
2008-06-09 20:23:23 +02:00
|
|
|
(void) setlocale (LC_ALL, "");
|
|
|
|
(void) bindtextdomain (PACKAGE, LOCALEDIR);
|
|
|
|
(void) textdomain (PACKAGE);
|
2007-10-07 13:44:59 +02:00
|
|
|
|
2007-10-07 13:44:02 +02:00
|
|
|
/*
|
2022-12-30 12:51:29 +01:00
|
|
|
* Save my name for error messages and save my real gid in case of
|
2007-10-07 13:44:59 +02:00
|
|
|
* errors. If there is an error i have to exec a new login shell for
|
|
|
|
* the user since her old shell won't have fork'd to create the
|
|
|
|
* process. Skip over the program name to the next command line
|
|
|
|
* argument.
|
|
|
|
*
|
|
|
|
* This historical comment, and the code itself, suggest that the
|
|
|
|
* behavior of the system/shell on which it was written differed
|
|
|
|
* significantly from the one I am using. If this process was
|
|
|
|
* started from a shell (including the login shell), it was fork'ed
|
|
|
|
* and exec'ed as a child by that shell. In order to get the user
|
|
|
|
* back to that shell, it is only necessary to exit from this
|
|
|
|
* process which terminates the child of the fork. The parent shell,
|
|
|
|
* which is blocked waiting for a signal, will then receive a
|
|
|
|
* SIGCHLD and will continue; any changes made to the process
|
|
|
|
* persona or the environment after the fork never occurred in the
|
|
|
|
* parent process.
|
|
|
|
*
|
|
|
|
* Bottom line: we want to save the name and real gid for messages,
|
|
|
|
* but we do not need to restore the previous process persona and we
|
|
|
|
* don't need to re-exec anything. -- JWP
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
2023-07-21 14:55:19 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure that "Prog" is always either "newgrp" or "sg" to avoid
|
|
|
|
* injecting arbitrary strings into our stderr/stdout, as this can
|
|
|
|
* be an exploit vector.
|
|
|
|
*/
|
|
|
|
is_newgrp = (strcmp (Basename (argv[0]), "newgrp") == 0);
|
|
|
|
Prog = is_newgrp ? "newgrp" : "sg";
|
|
|
|
|
2021-11-29 00:37:53 +01:00
|
|
|
log_set_progname(Prog);
|
|
|
|
log_set_logfd(stderr);
|
2023-07-21 14:55:19 +02:00
|
|
|
OPENLOG (Prog);
|
2007-10-07 13:44:59 +02:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2007-10-07 13:44:02 +02:00
|
|
|
|
2007-10-07 13:44:59 +02:00
|
|
|
initenv ();
|
2007-10-07 13:44:02 +02:00
|
|
|
|
2007-10-07 13:44:59 +02:00
|
|
|
pwd = get_my_pwent ();
|
2008-06-09 20:23:23 +02:00
|
|
|
if (NULL == pwd) {
|
2008-08-30 20:27:07 +02:00
|
|
|
fprintf (stderr, _("%s: Cannot determine your user name.\n"),
|
|
|
|
Prog);
|
2007-10-07 13:47:11 +02:00
|
|
|
#ifdef WITH_AUDIT
|
2008-06-13 22:21:24 +02:00
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
"changing", NULL, getuid (), 0);
|
2007-10-07 13:47:11 +02:00
|
|
|
#endif
|
2008-08-30 20:27:07 +02:00
|
|
|
SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
|
2008-06-13 22:21:24 +02:00
|
|
|
(unsigned long) getuid ()));
|
2007-10-07 13:44:59 +02:00
|
|
|
closelog ();
|
2009-04-23 22:37:00 +02:00
|
|
|
exit (EXIT_FAILURE);
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
|
|
|
name = pwd->pw_name;
|
|
|
|
|
|
|
|
/*
|
2007-10-07 13:44:59 +02:00
|
|
|
* Parse the command line. There are two accepted flags. The first
|
|
|
|
* is "-", which for newgrp means to re-create the entire
|
|
|
|
* environment as though a login had been performed, and "-c", which
|
|
|
|
* for sg causes a command string to be executed.
|
2007-10-07 13:44:02 +02:00
|
|
|
*
|
2007-10-07 13:44:59 +02:00
|
|
|
* The next argument, if present, must be the new group name. Any
|
|
|
|
* remaining remaining arguments will be used to execute a command
|
|
|
|
* as the named group. If the group name isn't present, I just use
|
|
|
|
* the login group ID of the current user.
|
2007-10-07 13:44:02 +02:00
|
|
|
*
|
|
|
|
* The valid syntax are
|
2007-10-07 13:45:23 +02:00
|
|
|
* newgrp [-] [groupid]
|
|
|
|
* newgrp [-l] [groupid]
|
|
|
|
* sg [-]
|
|
|
|
* sg [-] groupid [[-c command]
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
2008-06-09 20:23:23 +02:00
|
|
|
if ( (argc > 0)
|
|
|
|
&& ( (strcmp (argv[0], "-") == 0)
|
|
|
|
|| (strcmp (argv[0], "-l") == 0))) {
|
2007-10-07 13:44:59 +02:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2008-06-09 20:23:23 +02:00
|
|
|
initflag = true;
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
|
|
|
if (!is_newgrp) {
|
2021-09-13 18:23:17 +02:00
|
|
|
/*
|
2007-10-07 13:44:02 +02:00
|
|
|
* Do the command line for everything that is
|
|
|
|
* not "newgrp".
|
|
|
|
*/
|
2008-06-09 20:23:23 +02:00
|
|
|
if ((argc > 0) && (argv[0][0] != '-')) {
|
2007-10-07 13:44:02 +02:00
|
|
|
group = argv[0];
|
2007-10-07 13:44:59 +02:00
|
|
|
argc--;
|
|
|
|
argv++;
|
2007-10-07 13:44:02 +02:00
|
|
|
} else {
|
|
|
|
usage ();
|
2007-10-07 13:44:59 +02:00
|
|
|
closelog ();
|
2009-04-23 22:37:00 +02:00
|
|
|
exit (EXIT_FAILURE);
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
|
|
|
if (argc > 0) {
|
2007-10-07 13:44:08 +02:00
|
|
|
|
2007-10-07 13:44:59 +02:00
|
|
|
/*
|
|
|
|
* skip -c if specified so both forms work:
|
|
|
|
* "sg group -c command" (as in the man page) or
|
|
|
|
* "sg group command" (as in the usage message).
|
|
|
|
*/
|
2008-06-09 20:23:23 +02:00
|
|
|
if ((argc > 1) && (strcmp (argv[0], "-c") == 0)) {
|
2007-10-07 13:44:08 +02:00
|
|
|
command = argv[1];
|
2008-06-09 20:23:23 +02:00
|
|
|
} else {
|
2007-10-07 13:44:08 +02:00
|
|
|
command = argv[0];
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
|
|
|
cflag = true;
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
2007-10-07 13:44:59 +02:00
|
|
|
* Do the command line for "newgrp". It's just making sure
|
|
|
|
* there aren't any flags and getting the new group name.
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
2008-06-09 20:23:23 +02:00
|
|
|
if ((argc > 0) && (argv[0][0] == '-')) {
|
2007-10-07 13:44:02 +02:00
|
|
|
usage ();
|
|
|
|
goto failure;
|
2023-02-01 02:50:14 +01:00
|
|
|
} else if (argv[0] != NULL) {
|
2007-10-07 13:44:02 +02:00
|
|
|
group = argv[0];
|
|
|
|
} else {
|
|
|
|
/*
|
2021-09-13 18:23:17 +02:00
|
|
|
* get the group file entry for her login group id.
|
2007-10-07 13:44:02 +02:00
|
|
|
* the entry must exist, simply to be annoying.
|
2007-10-07 13:44:59 +02:00
|
|
|
*
|
|
|
|
* Perhaps in the past, but the default behavior now depends on the
|
|
|
|
* group entry, so it had better exist. -- JWP
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
2008-01-02 00:07:55 +01:00
|
|
|
grp = xgetgrgid (pwd->pw_gid);
|
|
|
|
if (NULL == grp) {
|
2008-08-30 20:28:24 +02:00
|
|
|
fprintf (stderr,
|
|
|
|
_("%s: GID '%lu' does not exist\n"),
|
|
|
|
Prog, (unsigned long) pwd->pw_gid);
|
|
|
|
SYSLOG ((LOG_CRIT, "GID '%lu' does not exist",
|
|
|
|
(unsigned long) pwd->pw_gid));
|
2007-10-07 13:44:02 +02:00
|
|
|
goto failure;
|
2008-06-09 20:23:23 +02:00
|
|
|
} else {
|
2007-10-07 13:44:59 +02:00
|
|
|
group = grp->gr_name;
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef HAVE_SETGROUPS
|
|
|
|
/*
|
2007-10-07 13:44:59 +02:00
|
|
|
* get the current users groupset. The new group will be added to
|
|
|
|
* the concurrent groupset if there is room, otherwise you get a
|
|
|
|
* nasty message but at least your real and effective group id's are
|
|
|
|
* set.
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
|
|
|
/* don't use getgroups(0, 0) - it doesn't work on some systems */
|
|
|
|
i = 16;
|
|
|
|
for (;;) {
|
Simplify allocation APIs
If we consider simple objects as arrays of size 1, we can considerably
simplify these APIs, merging the *ARRAY and the non-array variants.
That will produce more readable code, since lines will be shorter (by
not having ARRAY in the macro names, as all macros will consistently
handle arrays), and the allocated size will be also more explicit.
The syntax will now be of the form:
p = MALLOC(42, foo_t); // allocate 42 elements of type foo_t.
p = MALLOC(1, bar_t); // allocate 1 element of type foo_t.
The _array() allocation functions should _never_ be called directly, and
instead these macros should be used.
The non-array functions (e.g., malloc(3)) still have their place, but
are limited to allocating structures with flexible array members. For
any other uses, the macros should be used.
Thus, we don't use any array or ARRAY variants in any code any more, and
they are only used as implementation details of these macros.
Link: <https://software.codidact.com/posts/285898/288023#answer-288023>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
2023-04-05 21:17:38 +02:00
|
|
|
grouplist = XMALLOC(i, GETGROUPS_T);
|
2007-10-07 13:44:59 +02:00
|
|
|
ngroups = getgroups (i, grouplist);
|
2008-06-09 20:23:23 +02:00
|
|
|
if (i > ngroups && !(ngroups == -1 && errno == EINVAL)) {
|
2007-10-07 13:44:02 +02:00
|
|
|
break;
|
2008-06-09 20:23:23 +02:00
|
|
|
}
|
2007-10-07 13:44:02 +02:00
|
|
|
/* not enough room, so try allocating a larger buffer */
|
2007-10-07 13:44:59 +02:00
|
|
|
free (grouplist);
|
2007-10-07 13:44:02 +02:00
|
|
|
i *= 2;
|
|
|
|
}
|
|
|
|
if (ngroups < 0) {
|
2007-10-07 13:44:59 +02:00
|
|
|
perror ("getgroups");
|
2007-10-07 13:47:11 +02:00
|
|
|
#ifdef WITH_AUDIT
|
2008-02-14 19:35:51 +01:00
|
|
|
if (group) {
|
|
|
|
snprintf (audit_buf, sizeof(audit_buf),
|
|
|
|
"changing new-group=%s", group);
|
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
audit_buf, NULL, getuid (), 0);
|
2008-02-14 19:35:51 +01:00
|
|
|
} else {
|
|
|
|
audit_logger (AUDIT_CHGRP_ID, Prog,
|
2023-02-01 13:50:48 +01:00
|
|
|
"changing", NULL, getuid (), 0);
|
2008-02-14 19:35:51 +01:00
|
|
|
}
|
2007-10-07 13:47:11 +02:00
|
|
|
#endif
|
2009-04-23 22:37:00 +02:00
|
|
|
exit (EXIT_FAILURE);
|
2007-10-07 13:44:02 +02:00
|
|
|
}
|
2007-10-07 13:44:59 +02:00
|
|
|
#endif /* HAVE_SETGROUPS */
|
2007-10-07 13:44:02 +02:00
|
|
|
|
|
|
|
/*
|
2007-10-07 13:44:59 +02:00
|
|
|
* now we put her in the new group. The password file entry for her
|
|
|
|
* current user id has been gotten. If there was no optional group
|
|
|
|
* argument she will have her real and effective group id set to the
|
2021-09-13 18:23:17 +02:00
|
|
|
* set to the value from her password file entry.
|
2007-10-07 13:44:59 +02:00
|
|
|
*
|
|
|
|
* If run as newgrp, or as sg with no command, this process exec's
|
2021-09-13 18:23:17 +02:00
|
|
|
* an interactive subshell with the effective GID of the new group.
|
2007-10-07 13:44:59 +02:00
|
|
|
* If run as sg with a command, that command is exec'ed in this
|
|
|
|
* subshell. When this process terminates, either because the user
|
|
|
|
* exits, or the command completes, the parent of this process
|
2007-10-07 13:46:25 +02:00
|
|
|
* resumes with the current GID.
|
2007-10-07 13:44:59 +02:00
|
|
|
*
|
|
|
|
* If a group is explicitly specified on the command line, the
|
2021-09-13 18:23:17 +02:00
|
|
|
* interactive shell or command is run with that effective GID.
|
2007-10-07 13:44:59 +02:00
|
|
|
* Access will be denied if no entry for that group can be found in
|
|
|
|
* /etc/group. If the current user name appears in the members list
|
|
|
|
* for that group, access will be granted immediately; if not, the
|
|
|
|
* user will be challenged for that group's password. If the
|
|
|
|
* password response is incorrect, if the specified group does not
|
|
|
|
* have a password, or if that group has been locked by gpasswd -R,
|
|
|
|
* access will be denied. This is true even if the group specified
|
2007-10-07 13:46:25 +02:00
|
|
|
* has the user's login GID (as shown in /etc/passwd). If no group
|
2007-10-07 13:44:59 +02:00
|
|
|
* is explicitly specified on the command line, the effect is
|
2007-10-07 13:46:25 +02:00
|
|
|
* exactly the same as if a group name matching the user's login GID
|
2007-10-07 13:44:59 +02:00
|
|
|
* had been explicitly specified. Root, however, is never
|
|
|
|
* challenged for passwords, and is always allowed access.
|
|
|
|
*
|
|
|
|
* The previous behavior was to allow access to the login group if
|
|
|
|
* no explicit group was specified, irrespective of the group
|
|
|
|
* control file(s). This behavior is usually not desirable. A user
|
|
|
|
* wishing to return to the login group has only to exit back to the
|
|
|
|
* login shell. Generating yet more shell levels in order to
|
|
|
|
* provide a convenient "return" to the default group has the
|
|
|
|
* undesirable side effects of confusing the user, scrambling the
|
|
|
|
* history file, and consuming system resources. The default now is
|
|
|
|
* to lock out such behavior. A sys admin can allow it by explicitly
|
|
|
|
* including the user's name in the member list of the user's login
|
|
|
|
* group. -- JWP
|
2007-10-07 13:44:02 +02:00
|
|
|
*/
|
2008-01-02 00:07:55 +01:00
|
|
|
grp = getgrnam (group); /* local, no need for xgetgrnam */
|
|
|
|
if (NULL == grp) {
|
2008-08-30 20:27:07 +02:00
|
|