]> git.ipfire.org Git - thirdparty/util-linux.git/blame - login-utils/newgrp.c
misc: cosmetics, remove argument from usage(FILE*)
[thirdparty/util-linux.git] / login-utils / newgrp.c
CommitLineData
b7cfaaf8
SK
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 */
6dbe3af9 4
b50945d4 5/* 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
7eda085c
KZ
6 * - added Native Language Support
7 */
8
b7cfaaf8
SK
9#include <errno.h>
10#include <getopt.h>
6dbe3af9 11#include <grp.h>
b7cfaaf8 12#include <pwd.h>
6dbe3af9 13#include <stdio.h>
66ee8158 14#include <stdlib.h>
b7cfaaf8 15#include <string.h>
8f663a67 16#include <termios.h>
b7cfaaf8 17#include <unistd.h>
ad564ead 18
0aeb57ac 19#ifdef HAVE_CRYPT_H
b7cfaaf8 20# include <crypt.h>
0aeb57ac
FG
21#endif
22
c829aebc
SK
23#ifdef HAVE_GETSGNAM
24# include <gshadow.h>
25#endif
26
ad564ead 27#include "c.h"
439cdf1e 28#include "closestream.h"
7eda085c 29#include "nls.h"
b7cfaaf8 30#include "pathnames.h"
5fb01f43 31#include "xalloc.h"
6dbe3af9 32
8f663a67
SK
33static char *xgetpass(FILE *input, const char *prompt)
34{
35 char *pass = NULL;
36 struct termios saved, no_echo;
37 const int fd = fileno(input);
38 size_t dummy = 0;
39 ssize_t len;
40
41 fputs(prompt, stdout);
42 if (isatty(fd)) {
43 /* disable echo */
44 tcgetattr(fd, &saved);
45 no_echo = 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"));
50 }
51 len = getline(&pass, &dummy, input);
52 if (isatty(fd))
53 /* restore terminal */
54 if (tcsetattr(fd, TCSANOW, &saved))
55 err(EXIT_FAILURE, _("could not set terminal attributes"));
56 if (len < 0)
ee7ea5c8 57 err(EXIT_FAILURE, _("getline() failed"));
8f663a67
SK
58 if (0 < len && *(pass + len - 1) == '\n')
59 *(pass + len - 1) = '\0';
60 return pass;
61}
62
87583438 63#ifndef HAVE_EXPLICIT_BZERO
8f663a67
SK
64/* Ensure memory is set to value c without compiler optimization getting
65 * into way that could happen with memset(3). */
bbbf2aa8 66static int xmemset_s(void *v, size_t sz, const int c)
8f663a67
SK
67{
68 volatile unsigned char *p = v;
69
70 if (v == NULL)
71 return EINVAL;
72 while (sz--)
73 *p++ = c;
74 return 0;
75}
87583438 76#endif
8f663a67 77
66a9411e 78/* try to read password from gshadow */
1fd15f04 79static char *get_gshadow_pwd(const char *groupname)
66a9411e 80{
c829aebc
SK
81#ifdef HAVE_GETSGNAM
82 struct sgrp *sgrp;
83
84 sgrp = getsgnam(groupname);
85 return sgrp ? xstrdup(sgrp->sg_passwd) : NULL;
86#else
66a9411e
KZ
87 char buf[BUFSIZ];
88 char *pwd = NULL;
1f19513b 89 FILE *f;
66a9411e 90
1f19513b
KZ
91 if (groupname == NULL || *groupname == '\0')
92 return NULL;
93
94 f = fopen(_PATH_GSHADOW, "r");
95 if (!f)
66a9411e
KZ
96 return NULL;
97
b7cfaaf8
SK
98 while (fgets(buf, sizeof buf, f)) {
99 char *cp = strchr(buf, ':');
66a9411e 100 if (!cp)
b7cfaaf8
SK
101 /* any junk in gshadow? */
102 continue;
66a9411e 103 *cp = '\0';
b7cfaaf8
SK
104 if (strcmp(buf, groupname) == 0) {
105 if (cp - buf >= BUFSIZ)
106 /* only group name on line */
107 break;
108 pwd = cp + 1;
109 if ((cp = strchr(pwd, ':')) && pwd == cp + 1)
110 /* empty password */
111 pwd = NULL;
66a9411e
KZ
112 else if (cp)
113 *cp = '\0';
114 break;
115 }
116 }
117 fclose(f);
5fb01f43 118 return pwd ? xstrdup(pwd) : NULL;
c829aebc 119#endif /* HAVE_GETSGNAM */
66a9411e
KZ
120}
121
1fd15f04 122static int allow_setgid(const struct passwd *pe, const struct group *ge)
6dbe3af9 123{
b7cfaaf8
SK
124 char **look;
125 int notfound = 1;
126 char *pwd, *xpwd;
127
128 if (getuid() == 0)
129 /* root may do anything */
130 return TRUE;
131 if (ge->gr_gid == pe->pw_gid)
132 /* You can switch back to your default group */
133 return TRUE;
134
135 look = ge->gr_mem;
136 while (*look && (notfound = strcmp(*look++, pe->pw_name))) ;
137
138 if (!notfound)
139 /* member of group => OK */
140 return TRUE;
141
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 */
145
146 /* check /etc/gshadow */
147 if (!(pwd = get_gshadow_pwd(ge->gr_name)))
148 pwd = ge->gr_passwd;
149
8f663a67 150 if (pwd && *pwd && (xpwd = xgetpass(stdin, _("Password: ")))) {
19a1ca6c
KZ
151 char *cbuf = crypt(xpwd, pwd);
152
87583438
SK
153#ifdef HAVE_EXPLICIT_BZERO
154 explicit_bzero(xpwd, strlen(xpwd));
155#else
bbbf2aa8 156 xmemset_s(xpwd, strlen(xpwd), 0);
87583438 157#endif
8f663a67 158 free(xpwd);
19a1ca6c 159 if (!cbuf)
453fc716 160 warn(_("crypt failed"));
19a1ca6c 161 else if (strcmp(pwd, cbuf) == 0)
b7cfaaf8 162 return TRUE;
19a1ca6c 163 }
b7cfaaf8
SK
164
165 /* default to denial */
166 return FALSE;
6dbe3af9
KZ
167}
168
86be6a32 169static void __attribute__((__noreturn__)) usage(void)
e947e273 170{
86be6a32
RM
171 FILE *out = stdout;
172 fputs(USAGE_HEADER, out);
b7cfaaf8 173 fprintf(out, _(" %s <group>\n"), program_invocation_short_name);
451dbcfa
BS
174
175 fputs(USAGE_SEPARATOR, out);
176 fputs(_("Log in to a new group.\n"), out);
177
86be6a32
RM
178 fputs(USAGE_OPTIONS, out);
179 fputs(USAGE_HELP,out);
180 fputs(USAGE_VERSION,out);
b7cfaaf8 181 fprintf(out, USAGE_MAN_TAIL("newgrp(1)"));
86be6a32 182 exit(EXIT_SUCCESS);
e947e273
SK
183}
184
b7cfaaf8 185int main(int argc, char *argv[])
6dbe3af9 186{
b7cfaaf8
SK
187 struct passwd *pw_entry;
188 struct group *gr_entry;
189 char *shell;
94757ece 190 int ch;
b7cfaaf8
SK
191 static const struct option longopts[] = {
192 {"version", no_argument, NULL, 'V'},
193 {"help", no_argument, NULL, 'h'},
194 {NULL, 0, NULL, 0}
195 };
196
197 setlocale(LC_ALL, "");
198 bindtextdomain(PACKAGE, LOCALEDIR);
199 textdomain(PACKAGE);
439cdf1e 200 atexit(close_stdout);
b7cfaaf8
SK
201
202 while ((ch = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
203 switch (ch) {
204 case 'V':
205 printf(UTIL_LINUX_VERSION);
206 return EXIT_SUCCESS;
207 case 'h':
86be6a32 208 usage();
b7cfaaf8 209 default:
677ec86c 210 errtryhelp(EXIT_FAILURE);
b7cfaaf8 211 }
e947e273 212
b7cfaaf8
SK
213 if (!(pw_entry = getpwuid(getuid())))
214 err(EXIT_FAILURE, _("who are you?"));
215
b7cfaaf8
SK
216 if (argc < 2) {
217 if (setgid(pw_entry->pw_gid) < 0)
218 err(EXIT_FAILURE, _("setgid failed"));
6dbe3af9 219 } else {
b7cfaaf8
SK
220 errno = 0;
221 if (!(gr_entry = getgrnam(argv[1]))) {
222 if (errno)
223 err(EXIT_FAILURE, _("no such group"));
224 else
b7cfaaf8 225 errx(EXIT_FAILURE, _("no such group"));
b7cfaaf8 226 }
477135df
SK
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"));
6dbe3af9 231 }
6dbe3af9 232
b7cfaaf8
SK
233 if (setuid(getuid()) < 0)
234 err(EXIT_FAILURE, _("setuid failed"));
6dbe3af9 235
51c52acf
SK
236 fflush(NULL);
237 shell = (pw_entry->pw_shell && *pw_entry->pw_shell ?
238 pw_entry->pw_shell : _PATH_BSHELL);
b7cfaaf8 239 execl(shell, shell, (char *)0);
07ff972e 240 warn(_("failed to execute %s"), shell);
b7cfaaf8 241 fflush(stderr);
1fa30199 242
b7cfaaf8 243 return EXIT_FAILURE;
6dbe3af9 244}