2
* Copyright 1990 - 1994, Julianne Frances Haugh
2
* Copyright (c) 1990 - 1994, Julianne Frances Haugh
3
* Copyright (c) 1996 - 2000, Marek Michałkiewicz
4
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
5
* Copyright (c) 2007 - 2008, Nicolas François
3
6
* All rights reserved.
5
8
* Redistribution and use in source and binary forms, with or without
10
13
* 2. Redistributions in binary form must reproduce the above copyright
11
14
* notice, this list of conditions and the following disclaimer in the
12
15
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of Julianne F. Haugh nor the names of its contributors
14
* may be used to endorse or promote products derived from this software
15
* without specific prior written permission.
16
* 3. The name of the copyright holders or contributors may not be used to
17
* endorse or promote products derived from this software without
18
* specific prior written permission.
17
* THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
20
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
33
#include <config.h>
32
#ident "$Id: newgrp.c 1876 2008-03-07 20:21:15Z nekral-guest $"
35
#ident "$Id: newgrp.c 2348 2008-09-06 12:51:53Z nekral-guest $"
146
163
* the password. Otherwise I ask for a password if she flunked one
147
164
* of the tests above.
149
if (getuid () != 0 && needspasswd) {
166
if ((getuid () != 0) && needspasswd) {
151
168
* get the password from her, and set the salt for
152
169
* the decryption from the group file.
154
171
cp = getpass (_("Password: "));
159
177
* encrypt the key she gave us using the salt from the
167
185
strcmp (cpasswd, grp->gr_passwd) != 0) {
168
186
#ifdef WITH_AUDIT
169
187
snprintf (audit_buf, sizeof(audit_buf),
170
"authentication new-gid=%d", grp->gr_gid);
188
"authentication new-gid=%lu",
189
(unsigned long) grp->gr_gid);
171
190
audit_logger (AUDIT_GRP_AUTH, Prog,
172
audit_buf, NULL, getuid (), 0);
192
(unsigned int) getuid (), 0);
174
194
SYSLOG ((LOG_INFO,
175
"Invalid password for group `%s' from `%s'",
195
"Invalid password for group '%s' from '%s'",
176
196
groupname, pwd->pw_name));
178
198
fputs (_("Invalid password.\n"), stderr);
181
201
#ifdef WITH_AUDIT
182
202
snprintf (audit_buf, sizeof(audit_buf),
183
"authentication new-gid=%d", grp->gr_gid);
203
"authentication new-gid=%lu",
204
(unsigned long) grp->gr_gid);
184
205
audit_logger (AUDIT_GRP_AUTH, Prog,
185
audit_buf, NULL, getuid (), 1);
207
(unsigned int) getuid (), 1);
198
220
snprintf (audit_buf, sizeof(audit_buf),
199
221
"changing new-group=%s", groupname);
200
222
audit_logger (AUDIT_CHGRP_ID, Prog,
201
audit_buf, NULL, getuid (), 0);
224
(unsigned int) getuid (), 0);
203
audit_logger (AUDIT_CHGRP_ID, Prog, "changing",
226
audit_logger (AUDIT_CHGRP_ID, Prog,
228
(unsigned int) getuid (), 0);
219
243
const char *loginname = getlogin ();
220
244
const char *tty = ttyname (0);
222
if (loginname != NULL)
246
if (loginname != NULL) {
223
247
loginname = xstrdup (loginname);
225
250
tty = xstrdup (tty);
227
if (loginname == NULL)
253
if (loginname == NULL) {
228
254
loginname = "???";
231
else if (strncmp (tty, "/dev/", 5) == 0)
258
} else if (strncmp (tty, "/dev/", 5) == 0) {
233
261
SYSLOG ((LOG_INFO,
234
"user `%s' (login `%s' on %s) switched to group `%s'",
262
"user '%s' (login '%s' on %s) switched to group '%s'",
235
263
name, loginname, tty, group));
254
282
pid_t child, pid;
256
signal (SIGINT, SIG_IGN);
257
signal (SIGQUIT, SIG_IGN);
258
signal (SIGHUP, SIG_IGN);
259
signal (SIGTSTP, SIG_IGN);
260
signal (SIGTTIN, SIG_IGN);
261
signal (SIGTTOU, SIG_IGN);
284
/* Ignore these signals. The signal handlers will later be
285
* restored to the default handlers. */
286
(void) signal (SIGINT, SIG_IGN);
287
(void) signal (SIGQUIT, SIG_IGN);
288
(void) signal (SIGHUP, SIG_IGN);
289
(void) signal (SIGTSTP, SIG_IGN);
290
(void) signal (SIGTTIN, SIG_IGN);
291
(void) signal (SIGTTOU, SIG_IGN);
293
if ((pid_t)-1 == child) {
264
294
/* error in fork() */
265
295
fprintf (stderr, _("%s: failure forking: %s\n"),
266
296
is_newgrp ? "newgrp" : "sg", strerror (errno));
269
299
snprintf (audit_buf, sizeof(audit_buf),
270
300
"changing new-group=%s", group);
271
301
audit_logger (AUDIT_CHGRP_ID, Prog,
272
audit_buf, NULL, getuid (), 0);
303
(unsigned int) getuid (), 0);
274
audit_logger (AUDIT_CHGRP_ID, Prog, "changing",
305
audit_logger (AUDIT_CHGRP_ID, Prog,
307
(unsigned int) getuid (), 0);
311
} else if (child != 0) {
280
312
/* parent - wait for child to finish, then log session close */
282
314
gid_t gid = getgid();
287
319
pid = waitpid (child, &cst, WUNTRACED);
288
if (pid == child && WIFSTOPPED (cst)) {
320
if ((pid == child) && (WIFSTOPPED (cst) != 0)) {
289
321
/* stop when child stops */
322
kill (getpid (), WSTOPSIG(cst));
291
323
/* wake child when resumed */
292
324
kill (child, SIGCONT);
294
} while ((pid == child && WIFSTOPPED (cst)) ||
295
(pid != child && errno == EINTR));
326
} while ( ((pid == child) && (WIFSTOPPED (cst) != 0))
327
|| ((pid != child) && (errno == EINTR)));
296
328
/* local, no need for xgetgrgid */
297
329
if (NULL != grp) {
298
330
SYSLOG ((LOG_INFO,
299
"user `%s' (login `%s' on %s) returned to group `%s'",
331
"user '%s' (login '%s' on %s) returned to group '%s'",
300
332
name, loginname, tty, grp->gr_name));
302
334
SYSLOG ((LOG_INFO,
303
"user `%s' (login `%s' on %s) returned to group `%d'",
304
name, loginname, tty, gid));
335
"user '%s' (login '%s' on %s) returned to group '%lu'",
336
name, loginname, tty,
337
(unsigned long) gid));
305
338
/* Either the user's passwd entry has a
306
339
* GID that does not match with any group,
307
340
* or the group was deleted while the user
308
341
* was in a newgrp session.*/
309
342
SYSLOG ((LOG_WARN,
310
"unknown GID `%u' used by user `%s'",
343
"unknown GID '%lu' used by user '%s'",
344
(unsigned long) gid, name));
317
350
/* child - restore signals to their default state */
318
signal (SIGINT, SIG_DFL);
319
signal (SIGQUIT, SIG_DFL);
320
signal (SIGHUP, SIG_DFL);
321
signal (SIGTSTP, SIG_DFL);
322
signal (SIGTTIN, SIG_DFL);
323
signal (SIGTTOU, SIG_DFL);
351
(void) signal (SIGINT, SIG_DFL);
352
(void) signal (SIGQUIT, SIG_DFL);
353
(void) signal (SIGHUP, SIG_DFL);
354
(void) signal (SIGTSTP, SIG_DFL);
355
(void) signal (SIGTTIN, SIG_DFL);
356
(void) signal (SIGTTOU, SIG_DFL);
325
358
#endif /* USE_PAM */
392
423
pwd = get_my_pwent ();
394
fprintf (stderr, _("unknown UID: %u\n"), getuid ());
425
fprintf (stderr, _("%s: Cannot determine your user name.\n"),
395
427
#ifdef WITH_AUDIT
396
audit_logger (AUDIT_CHGRP_ID, Prog, "changing", NULL,
428
audit_logger (AUDIT_CHGRP_ID, Prog,
430
(unsigned int) getuid (), 0);
399
SYSLOG ((LOG_WARN, "unknown UID %u", getuid ()));
432
SYSLOG ((LOG_WARN, "Cannot determine the user name of the caller (UID %lu)",
433
(unsigned long) getuid ()));
420
454
* sg [-] groupid [[-c command]
422
if (argc > 0 && (!strcmp (argv[0], "-") || !strcmp (argv[0], "-l"))) {
457
&& ( (strcmp (argv[0], "-") == 0)
458
|| (strcmp (argv[0], "-l") == 0))) {
427
463
if (!is_newgrp) {
429
465
* Do the command line for everything that is
432
if (argc > 0 && argv[0][0] != '-') {
468
if ((argc > 0) && (argv[0][0] != '-')) {
445
481
* "sg group -c command" (as in the man page) or
446
482
* "sg group command" (as in the usage message).
448
if (argc > 1 && strcmp (argv[0], "-c") == 0)
484
if ((argc > 1) && (strcmp (argv[0], "-c") == 0)) {
449
485
command = argv[1];
451
487
command = argv[0];
456
493
* Do the command line for "newgrp". It's just making sure
457
494
* there aren't any flags and getting the new group name.
459
if (argc > 0 && argv[0][0] == '-') {
496
if ((argc > 0) && (argv[0][0] == '-')) {
462
499
} else if (argv[0] != (char *) 0) {
472
509
grp = xgetgrgid (pwd->pw_gid);
473
510
if (NULL == grp) {
474
fprintf (stderr, _("unknown GID: %lu\n"),
475
(unsigned long) pwd->pw_gid);
476
SYSLOG ((LOG_CRIT, "unknown GID: %lu",
477
(unsigned long) pwd->pw_gid));
512
_("%s: GID '%lu' does not exist\n"),
513
Prog, (unsigned long) pwd->pw_gid);
514
SYSLOG ((LOG_CRIT, "GID '%lu' does not exist",
515
(unsigned long) pwd->pw_gid));
480
518
group = grp->gr_name;
506
546
snprintf (audit_buf, sizeof(audit_buf),
507
547
"changing new-group=%s", group);
508
548
audit_logger (AUDIT_CHGRP_ID, Prog,
509
audit_buf, NULL, getuid (), 0);
550
(unsigned int) getuid (), 0);
511
552
audit_logger (AUDIT_CHGRP_ID, Prog,
512
"changing", NULL, getuid (), 0);
554
(unsigned int) getuid (), 0);
613
655
for (i = 0; i < ngroups; i++) {
614
if (gid == grouplist[i])
656
if (gid == grouplist[i]) {
617
660
if (i == ngroups) {
618
661
if (ngroups >= sysconf (_SC_NGROUPS_MAX)) {
619
662
fputs (_("too many groups\n"), stderr);
621
664
grouplist[ngroups++] = gid;
622
if (setgroups (ngroups, grouplist)) {
665
if (setgroups (ngroups, grouplist) != 0) {
623
666
perror ("setgroups");
631
674
* to the real UID. For root, this also sets the real GID to the
677
if (setgid (gid) != 0) {
635
678
perror ("setgid");
636
679
#ifdef WITH_AUDIT
637
680
snprintf (audit_buf, sizeof(audit_buf),
638
"changing new-gid=%d", gid);
681
"changing new-gid=%lu", (unsigned long) gid);
639
682
audit_logger (AUDIT_CHGRP_ID, Prog,
640
audit_buf, NULL, getuid (), 0);
684
(unsigned int) getuid (), 0);
645
if (setuid (getuid ())) {
689
if (setuid (getuid ()) != 0) {
646
690
perror ("setuid");
647
691
#ifdef WITH_AUDIT
648
692
snprintf (audit_buf, sizeof(audit_buf),
649
"changing new-gid=%d", gid);
693
"changing new-gid=%lu", (unsigned long) gid);
650
694
audit_logger (AUDIT_CHGRP_ID, Prog,
651
audit_buf, NULL, getuid (), 0);
696
(unsigned int) getuid (), 0);
662
707
execl ("/bin/sh", "sh", "-c", command, (char *) 0);
663
708
#ifdef WITH_AUDIT
664
709
snprintf (audit_buf, sizeof(audit_buf),
665
"changing new-gid=%d", gid);
710
"changing new-gid=%lu", (unsigned long) gid);
666
711
audit_logger (AUDIT_CHGRP_ID, Prog,
667
audit_buf, NULL, getuid (), 0);
713
(unsigned int) getuid (), 0);
669
715
perror ("/bin/sh");
670
716
exit (errno == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
687
733
* problem, try using $SHELL as a workaround; also please notify me
688
734
* at jparmele@wildbear.com -- JWP
690
if (!initflag && (cp = getenv ("SHELL")))
736
cp = getenv ("SHELL");
737
if (!initflag && (NULL != cp)) {
692
else if (pwd->pw_shell && pwd->pw_shell[0])
739
} else if ((NULL != pwd->pw_shell) && ('\0' != pwd->pw_shell[0])) {
693
740
prog = pwd->pw_shell;
695
742
prog = "/bin/sh";
698
* Now i try to find the basename of the login shell. This will
746
* Now I try to find the basename of the login shell. This will
699
747
* become argv[0] of the spawned command.
701
749
cp = Basename ((char *) prog);
729
addenv (*envp++, NULL);
777
while (NULL != *envp) {
778
addenv (*envp, NULL);
732
783
#ifdef WITH_AUDIT
733
snprintf (audit_buf, sizeof(audit_buf), "changing new-gid=%d", gid);
734
audit_logger (AUDIT_CHGRP_ID, Prog, audit_buf, NULL, getuid (), 1);
784
snprintf (audit_buf, sizeof(audit_buf), "changing new-gid=%lu",
785
(unsigned long) gid);
786
audit_logger (AUDIT_CHGRP_ID, Prog,
788
(unsigned int) getuid (), 1);
737
791
* Exec the login shell and go away. We are trying to get back to
756
810
#ifdef WITH_AUDIT
758
812
snprintf (audit_buf, sizeof(audit_buf),
759
813
"changing new-group=%s", group);
760
814
audit_logger (AUDIT_CHGRP_ID, Prog,
761
audit_buf, NULL, getuid (), 0);
816
(unsigned int) getuid (), 0);
763
818
audit_logger (AUDIT_CHGRP_ID, Prog,
764
"changing", NULL, getuid (), 0);
820
(unsigned int) getuid (), 0);