1 /* setgrp.c - by Michael Haardt. Set the gid if possible
2 * Added a bit more error recovery/reporting - poe
3 * Vesa Roukonen added code for asking password */
5 /* 1999-02-22 Arkadiusz MiĆkiewicz <misiek@pld.ORG.PL>
6 * - added Native Language Support
28 #include "closestream.h"
30 #include "pathnames.h"
33 static char *xgetpass(FILE *input
, const char *prompt
)
36 struct termios saved
, no_echo
;
37 const int fd
= fileno(input
);
41 fputs(prompt
, stdout
);
44 tcgetattr(fd
, &saved
);
46 no_echo
.c_lflag
&= ~ECHO
;
47 no_echo
.c_lflag
|= ECHONL
;
48 if (tcsetattr(fd
, TCSANOW
, &no_echo
))
49 err(EXIT_FAILURE
, _("could not set terminal attributes"));
51 len
= getline(&pass
, &dummy
, input
);
53 /* restore terminal */
54 if (tcsetattr(fd
, TCSANOW
, &saved
))
55 err(EXIT_FAILURE
, _("could not set terminal attributes"));
57 err(EXIT_FAILURE
, _("getline() failed"));
58 if (0 < len
&& *(pass
+ len
- 1) == '\n')
59 *(pass
+ len
- 1) = '\0';
63 #ifndef HAVE_EXPLICIT_BZERO
64 /* Ensure memory is set to value c without compiler optimization getting
65 * into way that could happen with memset(3). */
66 static int xmemset_s(void *v
, size_t sz
, const int c
)
68 volatile unsigned char *p
= v
;
78 /* try to read password from gshadow */
79 static char *get_gshadow_pwd(const char *groupname
)
84 sgrp
= getsgnam(groupname
);
85 return sgrp
? xstrdup(sgrp
->sg_passwd
) : NULL
;
91 if (groupname
== NULL
|| *groupname
== '\0')
94 f
= fopen(_PATH_GSHADOW
, "r");
98 while (fgets(buf
, sizeof buf
, f
)) {
99 char *cp
= strchr(buf
, ':');
101 /* any junk in gshadow? */
104 if (strcmp(buf
, groupname
) == 0) {
105 if (cp
- buf
>= BUFSIZ
)
106 /* only group name on line */
109 if ((cp
= strchr(pwd
, ':')) && pwd
== cp
+ 1)
118 return pwd
? xstrdup(pwd
) : NULL
;
119 #endif /* HAVE_GETSGNAM */
122 static int allow_setgid(const struct passwd
*pe
, const struct group
*ge
)
126 char *pwd
, *xpwd
, *spwd
;
129 /* root may do anything */
131 if (ge
->gr_gid
== pe
->pw_gid
)
132 /* You can switch back to your default group */
136 while (*look
&& (notfound
= strcmp(*look
++, pe
->pw_name
))) ;
139 /* member of group => OK */
142 /* Ask for password. Often there is no password in /etc/group, so
143 * contrary to login et al. we let an empty password mean the same
144 * as in /etc/passwd */
146 /* check /etc/gshadow */
147 spwd
= get_gshadow_pwd(ge
->gr_name
);
148 pwd
= spwd
? spwd
: ge
->gr_passwd
;
150 if (pwd
&& *pwd
&& (xpwd
= xgetpass(stdin
, _("Password: ")))) {
151 char *cbuf
= crypt(xpwd
, pwd
);
153 #ifdef HAVE_EXPLICIT_BZERO
154 explicit_bzero(xpwd
, strlen(xpwd
));
156 xmemset_s(xpwd
, strlen(xpwd
), 0);
160 warn(_("crypt failed"));
161 else if (strcmp(pwd
, cbuf
) == 0)
167 /* default to denial */
171 static void __attribute__((__noreturn__
)) usage(void)
174 fputs(USAGE_HEADER
, out
);
175 fprintf(out
, _(" %s <group>\n"), program_invocation_short_name
);
177 fputs(USAGE_SEPARATOR
, out
);
178 fputs(_("Log in to a new group.\n"), out
);
180 fputs(USAGE_OPTIONS
, out
);
181 fprintf(out
, USAGE_HELP_OPTIONS(16));
182 fprintf(out
, USAGE_MAN_TAIL("newgrp(1)"));
186 int main(int argc
, char *argv
[])
188 struct passwd
*pw_entry
;
189 struct group
*gr_entry
;
192 static const struct option longopts
[] = {
193 {"version", no_argument
, NULL
, 'V'},
194 {"help", no_argument
, NULL
, 'h'},
198 setlocale(LC_ALL
, "");
199 bindtextdomain(PACKAGE
, LOCALEDIR
);
201 close_stdout_atexit();
203 while ((ch
= getopt_long(argc
, argv
, "Vh", longopts
, NULL
)) != -1)
206 print_version(EXIT_SUCCESS
);
210 errtryhelp(EXIT_FAILURE
);
213 if (!(pw_entry
= getpwuid(getuid())))
214 err(EXIT_FAILURE
, _("who are you?"));
217 if (setgid(pw_entry
->pw_gid
) < 0)
218 err(EXIT_FAILURE
, _("setgid failed"));
221 if (!(gr_entry
= getgrnam(argv
[1]))) {
223 err(EXIT_FAILURE
, _("no such group"));
225 errx(EXIT_FAILURE
, _("no such group"));
227 if (!allow_setgid(pw_entry
, gr_entry
))
228 errx(EXIT_FAILURE
, _("permission denied"));
229 if (setgid(gr_entry
->gr_gid
) < 0)
230 err(EXIT_FAILURE
, _("setgid failed"));
233 if (setuid(getuid()) < 0)
234 err(EXIT_FAILURE
, _("setuid failed"));
237 shell
= (pw_entry
->pw_shell
&& *pw_entry
->pw_shell
?
238 pw_entry
->pw_shell
: _PATH_BSHELL
);
239 execl(shell
, shell
, (char *)NULL
);