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 /* Ensure memory is set to value c without compiler optimization getting
64 * into way that could happen with memset(3). */
65 static int xmemset_s(void *v
, size_t sz
, const int c
)
67 volatile unsigned char *p
= v
;
76 /* try to read password from gshadow */
77 static char *get_gshadow_pwd(const char *groupname
)
82 sgrp
= getsgnam(groupname
);
83 return sgrp
? xstrdup(sgrp
->sg_passwd
) : NULL
;
89 if (groupname
== NULL
|| *groupname
== '\0')
92 f
= fopen(_PATH_GSHADOW
, "r");
96 while (fgets(buf
, sizeof buf
, f
)) {
97 char *cp
= strchr(buf
, ':');
99 /* any junk in gshadow? */
102 if (strcmp(buf
, groupname
) == 0) {
103 if (cp
- buf
>= BUFSIZ
)
104 /* only group name on line */
107 if ((cp
= strchr(pwd
, ':')) && pwd
== cp
+ 1)
116 return pwd
? xstrdup(pwd
) : NULL
;
117 #endif /* HAVE_GETSGNAM */
120 static int allow_setgid(const struct passwd
*pe
, const struct group
*ge
)
127 /* root may do anything */
129 if (ge
->gr_gid
== pe
->pw_gid
)
130 /* You can switch back to your default group */
134 while (*look
&& (notfound
= strcmp(*look
++, pe
->pw_name
))) ;
137 /* member of group => OK */
140 /* Ask for password. Often there is no password in /etc/group, so
141 * contrary to login et al. we let an empty password mean the same
142 * as in /etc/passwd */
144 /* check /etc/gshadow */
145 if (!(pwd
= get_gshadow_pwd(ge
->gr_name
)))
148 if (pwd
&& *pwd
&& (xpwd
= xgetpass(stdin
, _("Password: ")))) {
149 char *cbuf
= crypt(xpwd
, pwd
);
151 xmemset_s(xpwd
, strlen(xpwd
), 0);
154 warn(_("crypt failed"));
155 else if (strcmp(pwd
, cbuf
) == 0)
159 /* default to denial */
163 static void __attribute__((__noreturn__
)) usage(FILE *out
)
165 fprintf(out
, USAGE_HEADER
);
166 fprintf(out
, _(" %s <group>\n"), program_invocation_short_name
);
168 fputs(USAGE_SEPARATOR
, out
);
169 fputs(_("Log in to a new group.\n"), out
);
171 fprintf(out
, USAGE_OPTIONS
);
172 fprintf(out
, USAGE_HELP
);
173 fprintf(out
, USAGE_VERSION
);
174 fprintf(out
, USAGE_MAN_TAIL("newgrp(1)"));
175 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
178 int main(int argc
, char *argv
[])
180 struct passwd
*pw_entry
;
181 struct group
*gr_entry
;
184 static const struct option longopts
[] = {
185 {"version", no_argument
, NULL
, 'V'},
186 {"help", no_argument
, NULL
, 'h'},
190 setlocale(LC_ALL
, "");
191 bindtextdomain(PACKAGE
, LOCALEDIR
);
193 atexit(close_stdout
);
195 while ((ch
= getopt_long(argc
, argv
, "Vh", longopts
, NULL
)) != -1)
198 printf(UTIL_LINUX_VERSION
);
206 if (!(pw_entry
= getpwuid(getuid())))
207 err(EXIT_FAILURE
, _("who are you?"));
210 if (setgid(pw_entry
->pw_gid
) < 0)
211 err(EXIT_FAILURE
, _("setgid failed"));
214 if (!(gr_entry
= getgrnam(argv
[1]))) {
216 err(EXIT_FAILURE
, _("no such group"));
218 errx(EXIT_FAILURE
, _("no such group"));
220 if (!allow_setgid(pw_entry
, gr_entry
))
221 errx(EXIT_FAILURE
, _("permission denied"));
222 if (setgid(gr_entry
->gr_gid
) < 0)
223 err(EXIT_FAILURE
, _("setgid failed"));
226 if (setuid(getuid()) < 0)
227 err(EXIT_FAILURE
, _("setuid failed"));
230 shell
= (pw_entry
->pw_shell
&& *pw_entry
->pw_shell
?
231 pw_entry
->pw_shell
: _PATH_BSHELL
);
232 execl(shell
, shell
, (char *)0);
233 warn(_("failed to execute %s"), shell
);