]> git.ipfire.org Git - thirdparty/util-linux.git/blob - login-utils/newgrp.c
Merge branch 'PR/ipcs-fix-counters' of github.com:karelzak/util-linux-work
[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, *spwd;
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 spwd = get_gshadow_pwd(ge->gr_name);
148 pwd = spwd ? spwd : 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 free(spwd);
166
167 /* default to denial */
168 return FALSE;
169 }
170
171 static void __attribute__((__noreturn__)) usage(void)
172 {
173 FILE *out = stdout;
174 fputs(USAGE_HEADER, out);
175 fprintf(out, _(" %s <group>\n"), program_invocation_short_name);
176
177 fputs(USAGE_SEPARATOR, out);
178 fputs(_("Log in to a new group.\n"), out);
179
180 fputs(USAGE_OPTIONS, out);
181 fprintf(out, USAGE_HELP_OPTIONS(16));
182 fprintf(out, USAGE_MAN_TAIL("newgrp(1)"));
183 exit(EXIT_SUCCESS);
184 }
185
186 int main(int argc, char *argv[])
187 {
188 struct passwd *pw_entry;
189 struct group *gr_entry;
190 char *shell;
191 int ch;
192 static const struct option longopts[] = {
193 {"version", no_argument, NULL, 'V'},
194 {"help", no_argument, NULL, 'h'},
195 {NULL, 0, NULL, 0}
196 };
197
198 setlocale(LC_ALL, "");
199 bindtextdomain(PACKAGE, LOCALEDIR);
200 textdomain(PACKAGE);
201 close_stdout_atexit();
202
203 while ((ch = getopt_long(argc, argv, "Vh", longopts, NULL)) != -1)
204 switch (ch) {
205 case 'V':
206 print_version(EXIT_SUCCESS);
207 case 'h':
208 usage();
209 default:
210 errtryhelp(EXIT_FAILURE);
211 }
212
213 if (!(pw_entry = getpwuid(getuid())))
214 err(EXIT_FAILURE, _("who are you?"));
215
216 if (argc < 2) {
217 if (setgid(pw_entry->pw_gid) < 0)
218 err(EXIT_FAILURE, _("setgid failed"));
219 } else {
220 errno = 0;
221 if (!(gr_entry = getgrnam(argv[1]))) {
222 if (errno)
223 err(EXIT_FAILURE, _("no such group"));
224 else
225 errx(EXIT_FAILURE, _("no such group"));
226 }
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"));
231 }
232
233 if (setuid(getuid()) < 0)
234 err(EXIT_FAILURE, _("setuid failed"));
235
236 fflush(NULL);
237 shell = (pw_entry->pw_shell && *pw_entry->pw_shell ?
238 pw_entry->pw_shell : _PATH_BSHELL);
239 execl(shell, shell, (char *)NULL);
240 errexec(shell);
241 }