]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/newgrp.c
misc: consolidate version printing and close_stdout()
[thirdparty/util-linux.git] / login-utils / newgrp.c
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 */
4
5 /* 1999-02-22 Arkadiusz Miƛkiewicz <misiek@pld.ORG.PL>
6 * - added Native Language Support
7 */
8
9 #include <errno.h>
10 #include <getopt.h>
11 #include <grp.h>
12 #include <pwd.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <termios.h>
17 #include <unistd.h>
18
19 #ifdef HAVE_CRYPT_H
20 # include <crypt.h>
21 #endif
22
23 #ifdef HAVE_GETSGNAM
24 # include <gshadow.h>
25 #endif
26
27 #include "c.h"
28 #include "closestream.h"
29 #include "nls.h"
30 #include "pathnames.h"
31 #include "xalloc.h"
32
33 static 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)
57 err(EXIT_FAILURE, _("getline() failed"));
58 if (0 < len && *(pass + len - 1) == '\n')
59 *(pass + len - 1) = '\0';
60 return pass;
61 }
62
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)
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 }
76 #endif
77
78 /* try to read password from gshadow */
79 static char *get_gshadow_pwd(const char *groupname)
80 {
81 #ifdef HAVE_GETSGNAM
82 struct sgrp *sgrp;
83
84 sgrp = getsgnam(groupname);
85 return sgrp ? xstrdup(sgrp->sg_passwd) : NULL;
86 #else
87 char buf[BUFSIZ];
88 char *pwd = NULL;
89 FILE *f;
90
91 if (groupname == NULL || *groupname == '\0')
92 return NULL;
93
94 f = fopen(_PATH_GSHADOW, "r");
95 if (!f)
96 return NULL;
97
98 while (fgets(buf, sizeof buf, f)) {
99 char *cp = strchr(buf, ':');
100 if (!cp)
101 /* any junk in gshadow? */
102 continue;
103 *cp = '\0';
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;
112 else if (cp)
113 *cp = '\0';
114 break;
115 }
116 }
117 fclose(f);
118 return pwd ? xstrdup(pwd) : NULL;
119 #endif /* HAVE_GETSGNAM */
120 }
121
122 static int allow_setgid(const struct passwd *pe, const struct group *ge)
123 {
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
150 if (pwd && *pwd && (xpwd = xgetpass(stdin, _("Password: ")))) {
151 char *cbuf = crypt(xpwd, pwd);
152
153 #ifdef HAVE_EXPLICIT_BZERO
154 explicit_bzero(xpwd, strlen(xpwd));
155 #else
156 xmemset_s(xpwd, strlen(xpwd), 0);
157 #endif
158 free(xpwd);
159 if (!cbuf)
160 warn(_("crypt failed"));
161 else if (strcmp(pwd, cbuf) == 0)
162 return TRUE;
163 }
164
165 /* default to denial */
166 return FALSE;
167 }
168
169 static void __attribute__((__noreturn__)) usage(void)
170 {
171 FILE *out = stdout;
172 fputs(USAGE_HEADER, out);
173 fprintf(out, _(" %s <group>\n"), program_invocation_short_name);
174
175 fputs(USAGE_SEPARATOR, out);
176 fputs(_("Log in to a new group.\n"), out);
177
178 fputs(USAGE_OPTIONS, out);
179 printf(USAGE_HELP_OPTIONS(16));
180 printf(USAGE_MAN_TAIL("newgrp(1)"));
181 exit(EXIT_SUCCESS);
182 }
183
184 int main(int argc, char *argv[])
185 {
186 struct passwd *pw_entry;
187 struct group *gr_entry;
188 char *shell;
189 int ch;
190 static const struct option longopts[] = {
191 {"version", no_argument, NULL, 'V'},
192 {"help", no_argument, NULL, 'h'},
193 {NULL, 0, NULL, 0}
194 };
195
196 setlocale(LC_ALL, "");
197 bindtextdomain(PACKAGE, LOCALEDIR);
198 textdomain(PACKAGE);
199 close_stdout_atexit();
200
201 while ((ch = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
202 switch (ch) {
203 case 'V':
204 print_version(EXIT_SUCCESS);
205 case 'h':
206 usage();
207 default:
208 errtryhelp(EXIT_FAILURE);
209 }
210
211 if (!(pw_entry = getpwuid(getuid())))
212 err(EXIT_FAILURE, _("who are you?"));
213
214 if (argc < 2) {
215 if (setgid(pw_entry->pw_gid) < 0)
216 err(EXIT_FAILURE, _("setgid failed"));
217 } else {
218 errno = 0;
219 if (!(gr_entry = getgrnam(argv[1]))) {
220 if (errno)
221 err(EXIT_FAILURE, _("no such group"));
222 else
223 errx(EXIT_FAILURE, _("no such group"));
224 }
225 if (!allow_setgid(pw_entry, gr_entry))
226 errx(EXIT_FAILURE, _("permission denied"));
227 if (setgid(gr_entry->gr_gid) < 0)
228 err(EXIT_FAILURE, _("setgid failed"));
229 }
230
231 if (setuid(getuid()) < 0)
232 err(EXIT_FAILURE, _("setuid failed"));
233
234 fflush(NULL);
235 shell = (pw_entry->pw_shell && *pw_entry->pw_shell ?
236 pw_entry->pw_shell : _PATH_BSHELL);
237 execl(shell, shell, (char *)0);
238 errexec(shell);
239 }