Blame


1 09a12e37 2016-09-08 martijn /*
2 79c9b1b2 2016-09-08 martijn * Copyright (c) 2016 Martijn van Duren <vias@imperialat.at>
3 09a12e37 2016-09-08 martijn * Copyright (c) 2015 Ted Unangst <tedu@openbsd.org>
4 09a12e37 2016-09-08 martijn *
5 09a12e37 2016-09-08 martijn * Permission to use, copy, modify, and distribute this software for any
6 09a12e37 2016-09-08 martijn * purpose with or without fee is hereby granted, provided that the above
7 09a12e37 2016-09-08 martijn * copyright notice and this permission notice appear in all copies.
8 09a12e37 2016-09-08 martijn *
9 09a12e37 2016-09-08 martijn * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 09a12e37 2016-09-08 martijn * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 09a12e37 2016-09-08 martijn * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 09a12e37 2016-09-08 martijn * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 09a12e37 2016-09-08 martijn * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 09a12e37 2016-09-08 martijn * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 09a12e37 2016-09-08 martijn * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 09a12e37 2016-09-08 martijn */
17 09a12e37 2016-09-08 martijn
18 09a12e37 2016-09-08 martijn #include <sys/types.h>
19 09a12e37 2016-09-08 martijn #include <sys/stat.h>
20 09a12e37 2016-09-08 martijn #include <sys/wait.h>
21 09a12e37 2016-09-08 martijn #include <sys/ioctl.h>
22 09a12e37 2016-09-08 martijn
23 09a12e37 2016-09-08 martijn #include <fcntl.h>
24 09a12e37 2016-09-08 martijn #include <limits.h>
25 09a12e37 2016-09-08 martijn #include <libgen.h>
26 09a12e37 2016-09-08 martijn #include <login_cap.h>
27 09a12e37 2016-09-08 martijn #include <bsd_auth.h>
28 09a12e37 2016-09-08 martijn #include <readpassphrase.h>
29 b2396b2c 2018-11-13 martijn #include <signal.h>
30 09a12e37 2016-09-08 martijn #include <string.h>
31 09a12e37 2016-09-08 martijn #include <stdio.h>
32 09a12e37 2016-09-08 martijn #include <stdlib.h>
33 09a12e37 2016-09-08 martijn #include <err.h>
34 09a12e37 2016-09-08 martijn #include <unistd.h>
35 09a12e37 2016-09-08 martijn #include <pwd.h>
36 09a12e37 2016-09-08 martijn #include <grp.h>
37 09a12e37 2016-09-08 martijn #include <syslog.h>
38 09a12e37 2016-09-08 martijn #include <errno.h>
39 09a12e37 2016-09-08 martijn
40 09a12e37 2016-09-08 martijn #include "vias.h"
41 09a12e37 2016-09-08 martijn
42 09a12e37 2016-09-08 martijn static void __dead
43 09a12e37 2016-09-08 martijn usage(void)
44 09a12e37 2016-09-08 martijn {
45 09a12e37 2016-09-08 martijn fprintf(stderr, "usage: vias [-a style] [-C config] "
46 09a12e37 2016-09-08 martijn "file [editor args]\n");
47 09a12e37 2016-09-08 martijn exit(1);
48 09a12e37 2016-09-08 martijn }
49 09a12e37 2016-09-08 martijn
50 09a12e37 2016-09-08 martijn size_t
51 09a12e37 2016-09-08 martijn arraylen(const char **arr)
52 09a12e37 2016-09-08 martijn {
53 09a12e37 2016-09-08 martijn size_t cnt = 0;
54 09a12e37 2016-09-08 martijn
55 09a12e37 2016-09-08 martijn while (*arr) {
56 09a12e37 2016-09-08 martijn cnt++;
57 09a12e37 2016-09-08 martijn arr++;
58 09a12e37 2016-09-08 martijn }
59 09a12e37 2016-09-08 martijn return cnt;
60 09a12e37 2016-09-08 martijn }
61 09a12e37 2016-09-08 martijn
62 09a12e37 2016-09-08 martijn static int
63 09a12e37 2016-09-08 martijn parseuid(const char *s, uid_t *uid)
64 09a12e37 2016-09-08 martijn {
65 09a12e37 2016-09-08 martijn struct passwd *pw;
66 09a12e37 2016-09-08 martijn const char *errstr;
67 09a12e37 2016-09-08 martijn
68 09a12e37 2016-09-08 martijn if ((pw = getpwnam(s)) != NULL) {
69 09a12e37 2016-09-08 martijn *uid = pw->pw_uid;
70 09a12e37 2016-09-08 martijn return 0;
71 09a12e37 2016-09-08 martijn }
72 09a12e37 2016-09-08 martijn *uid = strtonum(s, 0, UID_MAX, &errstr);
73 09a12e37 2016-09-08 martijn if (errstr)
74 09a12e37 2016-09-08 martijn return -1;
75 09a12e37 2016-09-08 martijn return 0;
76 09a12e37 2016-09-08 martijn }
77 09a12e37 2016-09-08 martijn
78 09a12e37 2016-09-08 martijn static int
79 09a12e37 2016-09-08 martijn uidcheck(const char *s, uid_t desired)
80 09a12e37 2016-09-08 martijn {
81 09a12e37 2016-09-08 martijn uid_t uid;
82 09a12e37 2016-09-08 martijn
83 09a12e37 2016-09-08 martijn if (parseuid(s, &uid) != 0)
84 09a12e37 2016-09-08 martijn return -1;
85 09a12e37 2016-09-08 martijn if (uid != desired)
86 09a12e37 2016-09-08 martijn return -1;
87 09a12e37 2016-09-08 martijn return 0;
88 09a12e37 2016-09-08 martijn }
89 09a12e37 2016-09-08 martijn
90 09a12e37 2016-09-08 martijn static int
91 09a12e37 2016-09-08 martijn parsegid(const char *s, gid_t *gid)
92 09a12e37 2016-09-08 martijn {
93 09a12e37 2016-09-08 martijn struct group *gr;
94 09a12e37 2016-09-08 martijn const char *errstr;
95 09a12e37 2016-09-08 martijn
96 09a12e37 2016-09-08 martijn if ((gr = getgrnam(s)) != NULL) {
97 09a12e37 2016-09-08 martijn *gid = gr->gr_gid;
98 09a12e37 2016-09-08 martijn return 0;
99 09a12e37 2016-09-08 martijn }
100 09a12e37 2016-09-08 martijn *gid = strtonum(s, 0, GID_MAX, &errstr);
101 09a12e37 2016-09-08 martijn if (errstr)
102 09a12e37 2016-09-08 martijn return -1;
103 09a12e37 2016-09-08 martijn return 0;
104 09a12e37 2016-09-08 martijn }
105 09a12e37 2016-09-08 martijn
106 09a12e37 2016-09-08 martijn static int
107 09a12e37 2016-09-08 martijn open_nosym(const char *file)
108 09a12e37 2016-09-08 martijn {
109 09a12e37 2016-09-08 martijn static int dep = 0;
110 09a12e37 2016-09-08 martijn struct stat sb;
111 09a12e37 2016-09-08 martijn char dir[PATH_MAX];
112 09a12e37 2016-09-08 martijn int fd, pfd;
113 09a12e37 2016-09-08 martijn
114 09a12e37 2016-09-08 martijn dep++;
115 09a12e37 2016-09-08 martijn (void) strlcpy(dir, dirname(file), sizeof(dir));
116 09a12e37 2016-09-08 martijn
117 09a12e37 2016-09-08 martijn if (dir[1] == '\0') {
118 09a12e37 2016-09-08 martijn dep--;
119 09a12e37 2016-09-08 martijn if ((pfd = open("/", O_CLOEXEC)) == -1)
120 09a12e37 2016-09-08 martijn return -1;
121 09a12e37 2016-09-08 martijn } else {
122 09a12e37 2016-09-08 martijn pfd = open_nosym(dir);
123 09a12e37 2016-09-08 martijn dep--;
124 09a12e37 2016-09-08 martijn if (pfd == -1)
125 09a12e37 2016-09-08 martijn return -1;
126 09a12e37 2016-09-08 martijn }
127 09a12e37 2016-09-08 martijn
128 09a12e37 2016-09-08 martijn do {
129 09a12e37 2016-09-08 martijn if (dep) {
130 09a12e37 2016-09-08 martijn fd = openat(pfd, basename(file),
131 09a12e37 2016-09-08 martijn O_NOFOLLOW | O_CLOEXEC);
132 09a12e37 2016-09-08 martijn } else {
133 09a12e37 2016-09-08 martijn fd = openat(pfd, basename(file),
134 09a12e37 2016-09-08 martijn O_RDWR | O_NOFOLLOW | O_CLOEXEC | O_CREAT, 0777);
135 09a12e37 2016-09-08 martijn }
136 09a12e37 2016-09-08 martijn } while (fd == -1 && errno == EINTR);
137 09a12e37 2016-09-08 martijn close(pfd);
138 09a12e37 2016-09-08 martijn if (fd == -1)
139 09a12e37 2016-09-08 martijn return -1;
140 09a12e37 2016-09-08 martijn
141 09a12e37 2016-09-08 martijn if (fstat(fd, &sb) == -1)
142 09a12e37 2016-09-08 martijn err(1, "fstat");
143 09a12e37 2016-09-08 martijn /*
144 09a12e37 2016-09-08 martijn * This should already have been checked in parse.y.
145 09a12e37 2016-09-08 martijn * It's only here to test for race-conditions
146 09a12e37 2016-09-08 martijn */
147 09a12e37 2016-09-08 martijn if (S_ISLNK(sb.st_mode))
148 09a12e37 2016-09-08 martijn errx(1, "Symbolic links not allowed");
149 09a12e37 2016-09-08 martijn if (dep && !S_ISDIR(sb.st_mode))
150 09a12e37 2016-09-08 martijn errc(1, ENOTDIR, NULL);
151 09a12e37 2016-09-08 martijn if (!dep && !S_ISREG(sb.st_mode))
152 09a12e37 2016-09-08 martijn errx(1, "File is not a regular file");
153 09a12e37 2016-09-08 martijn
154 09a12e37 2016-09-08 martijn return fd;
155 09a12e37 2016-09-08 martijn }
156 09a12e37 2016-09-08 martijn
157 09a12e37 2016-09-08 martijn static int
158 09a12e37 2016-09-08 martijn match(uid_t uid, gid_t *groups, int ngroups, const char *file, struct rule *r)
159 09a12e37 2016-09-08 martijn {
160 09a12e37 2016-09-08 martijn int i;
161 09a12e37 2016-09-08 martijn int flen;
162 09a12e37 2016-09-08 martijn
163 09a12e37 2016-09-08 martijn if (r->ident[0] == ':') {
164 09a12e37 2016-09-08 martijn gid_t rgid;
165 09a12e37 2016-09-08 martijn if (parsegid(r->ident + 1, &rgid) == -1)
166 09a12e37 2016-09-08 martijn return 0;
167 09a12e37 2016-09-08 martijn for (i = 0; i < ngroups; i++) {
168 09a12e37 2016-09-08 martijn if (rgid == groups[i])
169 09a12e37 2016-09-08 martijn break;
170 09a12e37 2016-09-08 martijn }
171 09a12e37 2016-09-08 martijn if (i == ngroups)
172 09a12e37 2016-09-08 martijn return 0;
173 09a12e37 2016-09-08 martijn } else {
174 09a12e37 2016-09-08 martijn if (uidcheck(r->ident, uid) != 0)
175 09a12e37 2016-09-08 martijn return 0;
176 09a12e37 2016-09-08 martijn }
177 09a12e37 2016-09-08 martijn if (r->files != NULL) {
178 09a12e37 2016-09-08 martijn for (i = 0; r->files[i] != NULL; i++) {
179 09a12e37 2016-09-08 martijn flen = strlen(r->files[i]);
180 09a12e37 2016-09-08 martijn /* Allow access to the entire directory tree */
181 09a12e37 2016-09-08 martijn if (r->files[i][flen-1] == '/') {
182 09a12e37 2016-09-08 martijn if (!strncmp(r->files[i], file, flen))
183 09a12e37 2016-09-08 martijn break;
184 09a12e37 2016-09-08 martijn } else {
185 09a12e37 2016-09-08 martijn if (!strcmp(r->files[i], file))
186 09a12e37 2016-09-08 martijn break;
187 09a12e37 2016-09-08 martijn }
188 09a12e37 2016-09-08 martijn }
189 09a12e37 2016-09-08 martijn if (r->files[i] == NULL)
190 09a12e37 2016-09-08 martijn return 0;
191 09a12e37 2016-09-08 martijn }
192 09a12e37 2016-09-08 martijn return 1;
193 09a12e37 2016-09-08 martijn }
194 09a12e37 2016-09-08 martijn
195 09a12e37 2016-09-08 martijn static int
196 09a12e37 2016-09-08 martijn permit(uid_t uid, gid_t *groups, int ngroups, struct rule **lastr,
197 09a12e37 2016-09-08 martijn const char *file)
198 09a12e37 2016-09-08 martijn {
199 09a12e37 2016-09-08 martijn int i;
200 09a12e37 2016-09-08 martijn int fd = -1, pfd = -1;
201 09a12e37 2016-09-08 martijn uid_t suid = -1;
202 09a12e37 2016-09-08 martijn struct rule *r;
203 09a12e37 2016-09-08 martijn char *rfile;
204 09a12e37 2016-09-08 martijn
205 09a12e37 2016-09-08 martijn if ((rfile = realpath(file, NULL)) == NULL)
206 09a12e37 2016-09-08 martijn err(1, "Unable to open %s", file);
207 09a12e37 2016-09-08 martijn
208 09a12e37 2016-09-08 martijn *lastr = NULL;
209 09a12e37 2016-09-08 martijn for (i = 0; i < nrules; i++) {
210 09a12e37 2016-09-08 martijn r = rules[i];
211 09a12e37 2016-09-08 martijn if (match(uid, groups, ngroups, rfile, r)) {
212 09a12e37 2016-09-08 martijn /* Try to open the file, so we know the rule is really permitted */
213 09a12e37 2016-09-08 martijn if (r->target) {
214 09a12e37 2016-09-08 martijn if (parseuid(r->target, &suid) == -1)
215 09a12e37 2016-09-08 martijn err(1, "getpwnam");
216 09a12e37 2016-09-08 martijn if (seteuid(suid) == -1)
217 09a12e37 2016-09-08 martijn err(1, "seteuid");
218 09a12e37 2016-09-08 martijn }
219 09a12e37 2016-09-08 martijn if ((fd = open_nosym(rfile)) != -1) {
220 09a12e37 2016-09-08 martijn if (pfd != -1)
221 09a12e37 2016-09-08 martijn if (close(pfd) == -1)
222 09a12e37 2016-09-08 martijn err(1, "close");
223 09a12e37 2016-09-08 martijn pfd = fd;
224 09a12e37 2016-09-08 martijn *lastr = rules[i];
225 09a12e37 2016-09-08 martijn } else if (errno != EPERM) {
226 09a12e37 2016-09-08 martijn err(1, "open %s", file);
227 09a12e37 2016-09-08 martijn }
228 09a12e37 2016-09-08 martijn if (r->target && seteuid(0))
229 09a12e37 2016-09-08 martijn err(1, "seteuid");
230 09a12e37 2016-09-08 martijn }
231 09a12e37 2016-09-08 martijn }
232 09a12e37 2016-09-08 martijn if (*lastr == NULL || (*lastr)->action != PERMIT) {
233 95866557 2017-09-25 martijn if (fd != -1 && close(fd) == -1)
234 76b35bc9 2017-09-25 martijn err(1, "close");
235 09a12e37 2016-09-08 martijn return -1;
236 09a12e37 2016-09-08 martijn }
237 09a12e37 2016-09-08 martijn
238 09a12e37 2016-09-08 martijn return fd;
239 09a12e37 2016-09-08 martijn }
240 09a12e37 2016-09-08 martijn
241 09a12e37 2016-09-08 martijn static void
242 09a12e37 2016-09-08 martijn parseconfig(const char *filename, int checkperms)
243 09a12e37 2016-09-08 martijn {
244 09a12e37 2016-09-08 martijn extern FILE *yyfp;
245 09a12e37 2016-09-08 martijn extern int yyparse(void);
246 09a12e37 2016-09-08 martijn struct stat sb;
247 09a12e37 2016-09-08 martijn
248 09a12e37 2016-09-08 martijn yyfp = fopen(filename, "r");
249 09a12e37 2016-09-08 martijn if (!yyfp)
250 09a12e37 2016-09-08 martijn err(1, checkperms ? "vias is not enabled, %s" :
251 09a12e37 2016-09-08 martijn "could not open config file %s", filename);
252 09a12e37 2016-09-08 martijn
253 09a12e37 2016-09-08 martijn if (checkperms) {
254 09a12e37 2016-09-08 martijn if (fstat(fileno(yyfp), &sb) != 0)
255 09a12e37 2016-09-08 martijn err(1, "fstat(\"%s\")", filename);
256 09a12e37 2016-09-08 martijn if ((sb.st_mode & (S_IWGRP|S_IWOTH)) != 0)
257 09a12e37 2016-09-08 martijn errx(1, "%s is writable by group or other", filename);
258 09a12e37 2016-09-08 martijn if (sb.st_uid != 0)
259 09a12e37 2016-09-08 martijn errx(1, "%s is not owned by root", filename);
260 09a12e37 2016-09-08 martijn }
261 09a12e37 2016-09-08 martijn
262 09a12e37 2016-09-08 martijn yyparse();
263 09a12e37 2016-09-08 martijn fclose(yyfp);
264 09a12e37 2016-09-08 martijn if (parse_errors)
265 09a12e37 2016-09-08 martijn exit(1);
266 09a12e37 2016-09-08 martijn }
267 09a12e37 2016-09-08 martijn
268 09a12e37 2016-09-08 martijn static void __dead
269 09a12e37 2016-09-08 martijn checkconfig(const char *confpath, uid_t uid, gid_t *groups, int ngroups,
270 09a12e37 2016-09-08 martijn const char *file)
271 09a12e37 2016-09-08 martijn {
272 09a12e37 2016-09-08 martijn struct rule *rule;
273 09a12e37 2016-09-08 martijn
274 09a12e37 2016-09-08 martijn parseconfig(confpath, 0);
275 09a12e37 2016-09-08 martijn if (!file)
276 09a12e37 2016-09-08 martijn exit(0);
277 09a12e37 2016-09-08 martijn
278 09a12e37 2016-09-08 martijn if (permit(uid, groups, ngroups, &rule, file) != -1) {
279 09a12e37 2016-09-08 martijn printf("permit%s\n", (rule->options & NOPASS) ? " nopass" : "");
280 09a12e37 2016-09-08 martijn exit(0);
281 09a12e37 2016-09-08 martijn }
282 09a12e37 2016-09-08 martijn printf("deny\n");
283 09a12e37 2016-09-08 martijn exit(1);
284 09a12e37 2016-09-08 martijn }
285 09a12e37 2016-09-08 martijn
286 09a12e37 2016-09-08 martijn static void
287 09a12e37 2016-09-08 martijn authuser(char *myname, char *login_style, int persist)
288 09a12e37 2016-09-08 martijn {
289 09a12e37 2016-09-08 martijn char *challenge = NULL, *response, rbuf[1024], cbuf[128];
290 09a12e37 2016-09-08 martijn auth_session_t *as;
291 09a12e37 2016-09-08 martijn int fd = -1;
292 09a12e37 2016-09-08 martijn
293 09a12e37 2016-09-08 martijn if (persist)
294 09a12e37 2016-09-08 martijn fd = open("/dev/tty", O_RDWR);
295 09a12e37 2016-09-08 martijn if (fd != -1) {
296 09a12e37 2016-09-08 martijn if (ioctl(fd, TIOCCHKVERAUTH) == 0)
297 09a12e37 2016-09-08 martijn goto good;
298 09a12e37 2016-09-08 martijn }
299 09a12e37 2016-09-08 martijn
300 09a12e37 2016-09-08 martijn if (!(as = auth_userchallenge(myname, login_style, "auth-doas",
301 09a12e37 2016-09-08 martijn &challenge)))
302 09a12e37 2016-09-08 martijn errx(1, "Authorization failed");
303 09a12e37 2016-09-08 martijn if (!challenge) {
304 09a12e37 2016-09-08 martijn char host[HOST_NAME_MAX + 1];
305 09a12e37 2016-09-08 martijn if (gethostname(host, sizeof(host)))
306 09a12e37 2016-09-08 martijn snprintf(host, sizeof(host), "?");
307 09a12e37 2016-09-08 martijn snprintf(cbuf, sizeof(cbuf),
308 09a12e37 2016-09-08 martijn "\rvias (%.32s@%.32s) password: ", myname, host);
309 09a12e37 2016-09-08 martijn challenge = cbuf;
310 09a12e37 2016-09-08 martijn }
311 09a12e37 2016-09-08 martijn response = readpassphrase(challenge, rbuf, sizeof(rbuf),
312 09a12e37 2016-09-08 martijn RPP_REQUIRE_TTY);
313 09a12e37 2016-09-08 martijn if (response == NULL && errno == ENOTTY) {
314 09a12e37 2016-09-08 martijn syslog(LOG_AUTHPRIV | LOG_NOTICE,
315 09a12e37 2016-09-08 martijn "tty required for %s", myname);
316 09a12e37 2016-09-08 martijn errx(1, "a tty is required");
317 09a12e37 2016-09-08 martijn }
318 09a12e37 2016-09-08 martijn if (!auth_userresponse(as, response, 0)) {
319 3a96e431 2019-01-17 martijn explicit_bzero(rbuf, sizeof(rbuf));
320 09a12e37 2016-09-08 martijn syslog(LOG_AUTHPRIV | LOG_NOTICE,
321 09a12e37 2016-09-08 martijn "failed auth for %s", myname);
322 09a12e37 2016-09-08 martijn errc(1, EPERM, NULL);
323 09a12e37 2016-09-08 martijn }
324 09a12e37 2016-09-08 martijn explicit_bzero(rbuf, sizeof(rbuf));
325 09a12e37 2016-09-08 martijn good:
326 09a12e37 2016-09-08 martijn if (fd != -1) {
327 09a12e37 2016-09-08 martijn int secs = 5 * 60;
328 09a12e37 2016-09-08 martijn ioctl(fd, TIOCSETVERAUTH, &secs);
329 09a12e37 2016-09-08 martijn close(fd);
330 09a12e37 2016-09-08 martijn }
331 09a12e37 2016-09-08 martijn }
332 09a12e37 2016-09-08 martijn static int
333 09a12e37 2016-09-08 martijn fcpy(int dfd, int sfd)
334 09a12e37 2016-09-08 martijn {
335 09a12e37 2016-09-08 martijn unsigned char buf[4096];
336 09a12e37 2016-09-08 martijn int r;
337 09a12e37 2016-09-08 martijn
338 09a12e37 2016-09-08 martijn do {
339 09a12e37 2016-09-08 martijn while ((r = read(sfd, buf, sizeof(buf))) > 0) {
340 09a12e37 2016-09-08 martijn if (write(dfd, buf, r) != r)
341 09a12e37 2016-09-08 martijn return 0;
342 09a12e37 2016-09-08 martijn }
343 09a12e37 2016-09-08 martijn } while (r == -1 && errno == EINTR);
344 09a12e37 2016-09-08 martijn if (r == -1)
345 09a12e37 2016-09-08 martijn return 0;
346 09a12e37 2016-09-08 martijn return 1;
347 09a12e37 2016-09-08 martijn }
348 09a12e37 2016-09-08 martijn
349 09a12e37 2016-09-08 martijn int
350 09a12e37 2016-09-08 martijn main(int argc, char **argv)
351 09a12e37 2016-09-08 martijn {
352 09a12e37 2016-09-08 martijn const char *confpath = NULL;
353 09a12e37 2016-09-08 martijn char tmpfile[] = "/tmp/vias.XXXXXX";
354 09a12e37 2016-09-08 martijn char myname[_PW_NAME_LEN + 1];
355 09a12e37 2016-09-08 martijn struct passwd *pw;
356 09a12e37 2016-09-08 martijn struct rule *rule;
357 09a12e37 2016-09-08 martijn uid_t uid;
358 09a12e37 2016-09-08 martijn gid_t groups[NGROUPS_MAX + 1];
359 09a12e37 2016-09-08 martijn int ngroups;
360 09a12e37 2016-09-08 martijn int i, ch;
361 09a12e37 2016-09-08 martijn int ofd, tfd;
362 09a12e37 2016-09-08 martijn char cwdpath[PATH_MAX];
363 09a12e37 2016-09-08 martijn const char *cwd;
364 09a12e37 2016-09-08 martijn char *login_style = NULL;
365 09a12e37 2016-09-08 martijn char *file;
366 09a12e37 2016-09-08 martijn char **eargv;
367 09a12e37 2016-09-08 martijn int status;
368 13ffdf3b 2017-09-24 martijn pid_t ret, vipid;
369 09a12e37 2016-09-08 martijn
370 09a12e37 2016-09-08 martijn setprogname("vias");
371 09a12e37 2016-09-08 martijn
372 09a12e37 2016-09-08 martijn closefrom(STDERR_FILENO + 1);
373 09a12e37 2016-09-08 martijn
374 09a12e37 2016-09-08 martijn uid = getuid();
375 09a12e37 2016-09-08 martijn
376 09a12e37 2016-09-08 martijn while ((ch = getopt(argc, argv, "a:C:")) != -1) {
377 09a12e37 2016-09-08 martijn switch (ch) {
378 09a12e37 2016-09-08 martijn case 'a':
379 09a12e37 2016-09-08 martijn login_style = optarg;
380 09a12e37 2016-09-08 martijn break;
381 09a12e37 2016-09-08 martijn case 'C':
382 09a12e37 2016-09-08 martijn confpath = optarg;
383 09a12e37 2016-09-08 martijn break;
384 09a12e37 2016-09-08 martijn default:
385 09a12e37 2016-09-08 martijn usage();
386 09a12e37 2016-09-08 martijn }
387 09a12e37 2016-09-08 martijn }
388 09a12e37 2016-09-08 martijn argv += optind;
389 09a12e37 2016-09-08 martijn argc -= optind;
390 09a12e37 2016-09-08 martijn
391 347af3ca 2017-09-25 martijn if (argc == 0 && confpath == NULL)
392 09a12e37 2016-09-08 martijn usage();
393 09a12e37 2016-09-08 martijn file = argv[0];
394 09a12e37 2016-09-08 martijn argv++;
395 09a12e37 2016-09-08 martijn argc--;
396 09a12e37 2016-09-08 martijn
397 09a12e37 2016-09-08 martijn pw = getpwuid(uid);
398 09a12e37 2016-09-08 martijn if (!pw)
399 09a12e37 2016-09-08 martijn err(1, "getpwuid failed");
400 09a12e37 2016-09-08 martijn if (strlcpy(myname, pw->pw_name, sizeof(myname)) >= sizeof(myname))
401 09a12e37 2016-09-08 martijn errx(1, "pw_name too long");
402 09a12e37 2016-09-08 martijn ngroups = getgroups(NGROUPS_MAX, groups);
403 09a12e37 2016-09-08 martijn if (ngroups == -1)
404 09a12e37 2016-09-08 martijn err(1, "can't get groups");
405 09a12e37 2016-09-08 martijn groups[ngroups++] = getgid();
406 09a12e37 2016-09-08 martijn
407 09a12e37 2016-09-08 martijn if (confpath)
408 09a12e37 2016-09-08 martijn checkconfig(confpath, uid, groups, ngroups, file);
409 09a12e37 2016-09-08 martijn
410 332482f3 2017-09-25 martijn if (geteuid())
411 332482f3 2017-09-25 martijn errx(1, "not installed setuid");
412 332482f3 2017-09-25 martijn
413 09a12e37 2016-09-08 martijn parseconfig("/etc/vias.conf", 1);
414 09a12e37 2016-09-08 martijn
415 73964625 2017-09-24 martijn if (setuid(0) == -1)
416 73964625 2017-09-24 martijn err(1, "setuid");
417 09a12e37 2016-09-08 martijn if ((ofd = permit(uid, groups, ngroups, &rule, file)) == -1) {
418 09a12e37 2016-09-08 martijn syslog(LOG_AUTHPRIV | LOG_NOTICE,
419 09a12e37 2016-09-08 martijn "failed edit for %s: %s", myname, file);
420 08393614 2017-09-25 martijn errc(1, EPERM, "%s", file);
421 09a12e37 2016-09-08 martijn }
422 09a12e37 2016-09-08 martijn
423 73964625 2017-09-24 martijn if (setreuid(uid, 0) == -1)
424 73964625 2017-09-24 martijn err(1, "setreuid failed");
425 73964625 2017-09-24 martijn
426 09a12e37 2016-09-08 martijn if (!(rule->options & NOPASS))
427 09a12e37 2016-09-08 martijn authuser(myname, login_style, rule->options & PERSIST);
428 09a12e37 2016-09-08 martijn
429 09a12e37 2016-09-08 martijn if (pledge("stdio rpath wpath cpath exec proc id", NULL) == -1)
430 09a12e37 2016-09-08 martijn err(1, "pledge");
431 09a12e37 2016-09-08 martijn
432 09a12e37 2016-09-08 martijn if ((setuid(uid)) == -1)
433 09a12e37 2016-09-08 martijn err(1, "setuid failed");
434 09a12e37 2016-09-08 martijn
435 09a12e37 2016-09-08 martijn if (pledge("stdio rpath wpath cpath exec proc", NULL) == -1)
436 09a12e37 2016-09-08 martijn err(1, "pledge");
437 09a12e37 2016-09-08 martijn
438 09a12e37 2016-09-08 martijn if ((tfd = mkstemp(tmpfile)) == -1)
439 09a12e37 2016-09-08 martijn err(1, "mkstemp failed");
440 09a12e37 2016-09-08 martijn
441 09a12e37 2016-09-08 martijn if (pledge("stdio rpath cpath exec proc", NULL) == -1)
442 09a12e37 2016-09-08 martijn err(1, "pledge");
443 09a12e37 2016-09-08 martijn
444 09a12e37 2016-09-08 martijn if (!fcpy(tfd, ofd)) {
445 09a12e37 2016-09-08 martijn unlink(tmpfile);
446 09a12e37 2016-09-08 martijn err(1, "temp copy failed");
447 09a12e37 2016-09-08 martijn }
448 09a12e37 2016-09-08 martijn
449 09a12e37 2016-09-08 martijn if (getcwd(cwdpath, sizeof(cwdpath)) == NULL)
450 09a12e37 2016-09-08 martijn cwd = "(failed)";
451 09a12e37 2016-09-08 martijn else
452 09a12e37 2016-09-08 martijn cwd = cwdpath;
453 09a12e37 2016-09-08 martijn
454 09a12e37 2016-09-08 martijn if (pledge("stdio cpath exec proc", NULL) == -1)
455 09a12e37 2016-09-08 martijn err(1, "pledge");
456 09a12e37 2016-09-08 martijn
457 71897761 2018-09-05 martijn syslog(LOG_AUTHPRIV | LOG_INFO, "%s edited %s from %s",
458 71897761 2018-09-05 martijn myname, file, cwd);
459 09a12e37 2016-09-08 martijn
460 09a12e37 2016-09-08 martijn if ((eargv = reallocarray(NULL, arraylen((const char **) argv) + 2,
461 09a12e37 2016-09-08 martijn sizeof(*eargv))) == NULL) {
462 09a12e37 2016-09-08 martijn unlink(tmpfile);
463 09a12e37 2016-09-08 martijn err(1, NULL);
464 09a12e37 2016-09-08 martijn }
465 09a12e37 2016-09-08 martijn eargv[0] = getenv("EDITOR");
466 09a12e37 2016-09-08 martijn if (eargv[0] == NULL || *(eargv[0]) == '\0')
467 09a12e37 2016-09-08 martijn eargv[0] = "vi";
468 09a12e37 2016-09-08 martijn
469 13ffdf3b 2017-09-24 martijn switch ((vipid = fork())) {
470 09a12e37 2016-09-08 martijn case -1:
471 09a12e37 2016-09-08 martijn unlink(tmpfile);
472 09a12e37 2016-09-08 martijn err(1, "fork failed");
473 09a12e37 2016-09-08 martijn case 0:
474 09a12e37 2016-09-08 martijn if (pledge("stdio exec", NULL) == -1)
475 09a12e37 2016-09-08 martijn err(1, "pledge");
476 09a12e37 2016-09-08 martijn
477 09a12e37 2016-09-08 martijn for (i = 0; argv[i] != NULL; i++)
478 09a12e37 2016-09-08 martijn eargv[i+1] = argv[i];
479 09a12e37 2016-09-08 martijn eargv[i+1] = tmpfile;
480 09a12e37 2016-09-08 martijn eargv[i+2] = NULL;
481 09a12e37 2016-09-08 martijn execvp(eargv[0], eargv);
482 09a12e37 2016-09-08 martijn err(1, "execvp failed");
483 09a12e37 2016-09-08 martijn default:
484 09a12e37 2016-09-08 martijn if (pledge("stdio cpath", NULL) == -1)
485 09a12e37 2016-09-08 martijn err(1, "pledge");
486 09a12e37 2016-09-08 martijn
487 b2396b2c 2018-11-13 martijn (void) signal(SIGINT, SIG_IGN);
488 13ffdf3b 2017-09-24 martijn while ((ret = waitpid(vipid, &status, 0)) == -1 &&
489 13ffdf3b 2017-09-24 martijn errno == EINTR)
490 09a12e37 2016-09-08 martijn ;
491 09a12e37 2016-09-08 martijn if (ret == -1)
492 09a12e37 2016-09-08 martijn err(1, "wait failed: Temporary file saved at %s",
493 09a12e37 2016-09-08 martijn tmpfile);
494 09a12e37 2016-09-08 martijn }
495 09a12e37 2016-09-08 martijn
496 09a12e37 2016-09-08 martijn if (WEXITSTATUS(status) != 0) {
497 09a12e37 2016-09-08 martijn errx(1, "%s exited with status %d: Temporary file saved at %s",
498 09a12e37 2016-09-08 martijn eargv[0], WEXITSTATUS(status), tmpfile);
499 09a12e37 2016-09-08 martijn }
500 09a12e37 2016-09-08 martijn
501 09a12e37 2016-09-08 martijn (void) lseek(tfd, 0, SEEK_SET);
502 09a12e37 2016-09-08 martijn if (ftruncate(ofd, 0) == -1)
503 09a12e37 2016-09-08 martijn err(1, "ftruncate failed: Temporary file saved at %s", tmpfile);
504 09a12e37 2016-09-08 martijn (void) lseek(ofd, 0, SEEK_SET);
505 09a12e37 2016-09-08 martijn if (!fcpy(ofd, tfd))
506 09a12e37 2016-09-08 martijn err(1, "restoring failed: Temporary file saved at %s", tmpfile);
507 09a12e37 2016-09-08 martijn if (unlink(tmpfile) == -1)
508 09a12e37 2016-09-08 martijn err(1, "unlink %s", tmpfile);
509 09a12e37 2016-09-08 martijn return 0;
510 09a12e37 2016-09-08 martijn }