xref: /freebsd-src/contrib/dma/dma-mbox-create.c (revision c6879c6c14eedbd060ba588a3129a6c60ebbe783)
1a9e8641dSBaptiste Daroussin /*
2e56bad4aSBaptiste Daroussin  * Copyright (c) 2010-2014, Simon Schubert <2@0x2c.org>.
3a9e8641dSBaptiste Daroussin  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
4a9e8641dSBaptiste Daroussin  *
5a9e8641dSBaptiste Daroussin  * This code is derived from software contributed to The DragonFly Project
6e56bad4aSBaptiste Daroussin  * by Simon Schubert <2@0x2c.org>.
7a9e8641dSBaptiste Daroussin  *
8a9e8641dSBaptiste Daroussin  * Redistribution and use in source and binary forms, with or without
9a9e8641dSBaptiste Daroussin  * modification, are permitted provided that the following conditions
10a9e8641dSBaptiste Daroussin  * are met:
11a9e8641dSBaptiste Daroussin  *
12a9e8641dSBaptiste Daroussin  * 1. Redistributions of source code must retain the above copyright
13a9e8641dSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer.
14a9e8641dSBaptiste Daroussin  * 2. Redistributions in binary form must reproduce the above copyright
15a9e8641dSBaptiste Daroussin  *    notice, this list of conditions and the following disclaimer in
16a9e8641dSBaptiste Daroussin  *    the documentation and/or other materials provided with the
17a9e8641dSBaptiste Daroussin  *    distribution.
18a9e8641dSBaptiste Daroussin  * 3. Neither the name of The DragonFly Project nor the names of its
19a9e8641dSBaptiste Daroussin  *    contributors may be used to endorse or promote products derived
20a9e8641dSBaptiste Daroussin  *    from this software without specific, prior written permission.
21a9e8641dSBaptiste Daroussin  *
22a9e8641dSBaptiste Daroussin  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23a9e8641dSBaptiste Daroussin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24a9e8641dSBaptiste Daroussin  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25a9e8641dSBaptiste Daroussin  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26a9e8641dSBaptiste Daroussin  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27a9e8641dSBaptiste Daroussin  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28a9e8641dSBaptiste Daroussin  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29a9e8641dSBaptiste Daroussin  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30a9e8641dSBaptiste Daroussin  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31a9e8641dSBaptiste Daroussin  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32a9e8641dSBaptiste Daroussin  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33a9e8641dSBaptiste Daroussin  * SUCH DAMAGE.
34a9e8641dSBaptiste Daroussin  */
35a9e8641dSBaptiste Daroussin 
36a9e8641dSBaptiste Daroussin /*
37a9e8641dSBaptiste Daroussin  * This binary is setuid root.  Use extreme caution when touching
38a9e8641dSBaptiste Daroussin  * user-supplied information.  Keep the root window as small as possible.
39a9e8641dSBaptiste Daroussin  */
40a9e8641dSBaptiste Daroussin 
419716e7d4SConrad Meyer #ifdef __FreeBSD__
429716e7d4SConrad Meyer #define	USE_CAPSICUM	1
439716e7d4SConrad Meyer #endif
449716e7d4SConrad Meyer 
45a9e8641dSBaptiste Daroussin #include <sys/param.h>
469716e7d4SConrad Meyer #if USE_CAPSICUM
479716e7d4SConrad Meyer #include <sys/capsicum.h>
489716e7d4SConrad Meyer #endif
49a9e8641dSBaptiste Daroussin #include <sys/stat.h>
50a9e8641dSBaptiste Daroussin 
519716e7d4SConrad Meyer #include <capsicum_helpers.h>
529716e7d4SConrad Meyer #include <err.h>
53a9e8641dSBaptiste Daroussin #include <errno.h>
54a9e8641dSBaptiste Daroussin #include <fcntl.h>
55a9e8641dSBaptiste Daroussin #include <grp.h>
56a9e8641dSBaptiste Daroussin #include <paths.h>
57a9e8641dSBaptiste Daroussin #include <pwd.h>
58a9e8641dSBaptiste Daroussin #include <stdio.h>
59*b86d1398SJung-uk Kim #include <string.h>
60a9e8641dSBaptiste Daroussin #include <syslog.h>
61a9e8641dSBaptiste Daroussin #include <unistd.h>
62a9e8641dSBaptiste Daroussin 
63a9e8641dSBaptiste Daroussin #include "dma.h"
64a9e8641dSBaptiste Daroussin 
65a9e8641dSBaptiste Daroussin 
66a9e8641dSBaptiste Daroussin static void
logfail(int exitcode,const char * fmt,...)67e56bad4aSBaptiste Daroussin logfail(int exitcode, const char *fmt, ...)
68a9e8641dSBaptiste Daroussin {
69a9e8641dSBaptiste Daroussin 	int oerrno = errno;
70a9e8641dSBaptiste Daroussin 	va_list ap;
71a9e8641dSBaptiste Daroussin 	char outs[1024];
72a9e8641dSBaptiste Daroussin 
73a9e8641dSBaptiste Daroussin 	outs[0] = 0;
74a9e8641dSBaptiste Daroussin 	if (fmt != NULL) {
75a9e8641dSBaptiste Daroussin 		va_start(ap, fmt);
76a9e8641dSBaptiste Daroussin 		vsnprintf(outs, sizeof(outs), fmt, ap);
77a9e8641dSBaptiste Daroussin 		va_end(ap);
78a9e8641dSBaptiste Daroussin 	}
79a9e8641dSBaptiste Daroussin 
80a9e8641dSBaptiste Daroussin 	errno = oerrno;
81a9e8641dSBaptiste Daroussin 	if (*outs != 0)
82a9e8641dSBaptiste Daroussin 		syslog(LOG_ERR, errno ? "%s: %m" : "%s", outs);
83a9e8641dSBaptiste Daroussin 	else
84a9e8641dSBaptiste Daroussin 		syslog(LOG_ERR, errno ? "%m" : "unknown error");
85a9e8641dSBaptiste Daroussin 
86e56bad4aSBaptiste Daroussin 	exit(exitcode);
87a9e8641dSBaptiste Daroussin }
88a9e8641dSBaptiste Daroussin 
89a9e8641dSBaptiste Daroussin /*
90a9e8641dSBaptiste Daroussin  * Create a mbox in /var/mail for a given user, or make sure
91a9e8641dSBaptiste Daroussin  * the permissions are correct for dma.
92a9e8641dSBaptiste Daroussin  */
93a9e8641dSBaptiste Daroussin 
94a9e8641dSBaptiste Daroussin int
main(int argc,char ** argv)95a9e8641dSBaptiste Daroussin main(int argc, char **argv)
96a9e8641dSBaptiste Daroussin {
979716e7d4SConrad Meyer #if USE_CAPSICUM
989716e7d4SConrad Meyer 	cap_rights_t rights;
999716e7d4SConrad Meyer #endif
100a9e8641dSBaptiste Daroussin 	const char *user;
101a9e8641dSBaptiste Daroussin 	struct passwd *pw;
102a9e8641dSBaptiste Daroussin 	struct group *gr;
103a9e8641dSBaptiste Daroussin 	uid_t user_uid;
104a9e8641dSBaptiste Daroussin 	gid_t mail_gid;
105b72aa290SBaptiste Daroussin 	int f, maildirfd;
106a9e8641dSBaptiste Daroussin 
1079716e7d4SConrad Meyer 	/*
1089716e7d4SConrad Meyer 	 * Open log fd now for capability sandbox.
1099716e7d4SConrad Meyer 	 */
1109716e7d4SConrad Meyer 	openlog("dma-mbox-create", LOG_NDELAY, LOG_MAIL);
111a9e8641dSBaptiste Daroussin 
112a9e8641dSBaptiste Daroussin 	errno = 0;
113a9e8641dSBaptiste Daroussin 	gr = getgrnam(DMA_GROUP);
114a9e8641dSBaptiste Daroussin 	if (!gr)
115e56bad4aSBaptiste Daroussin 		logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP);
116a9e8641dSBaptiste Daroussin 
117a9e8641dSBaptiste Daroussin 	mail_gid = gr->gr_gid;
118a9e8641dSBaptiste Daroussin 
119a9e8641dSBaptiste Daroussin 	if (setgid(mail_gid) != 0)
120e56bad4aSBaptiste Daroussin 		logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP);
121a9e8641dSBaptiste Daroussin 	if (getegid() != mail_gid)
122e56bad4aSBaptiste Daroussin 		logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid());
123a9e8641dSBaptiste Daroussin 
124a9e8641dSBaptiste Daroussin 	/*
125a9e8641dSBaptiste Daroussin 	 * We take exactly one argument: the username.
126a9e8641dSBaptiste Daroussin 	 */
127a9e8641dSBaptiste Daroussin 	if (argc != 2) {
128a9e8641dSBaptiste Daroussin 		errno = 0;
129e56bad4aSBaptiste Daroussin 		logfail(EX_USAGE, "no arguments");
130a9e8641dSBaptiste Daroussin 	}
131a9e8641dSBaptiste Daroussin 	user = argv[1];
132a9e8641dSBaptiste Daroussin 
133a9e8641dSBaptiste Daroussin 	syslog(LOG_NOTICE, "creating mbox for `%s'", user);
134a9e8641dSBaptiste Daroussin 
135a9e8641dSBaptiste Daroussin 	/* the username may not contain a pathname separator */
136a9e8641dSBaptiste Daroussin 	if (strchr(user, '/')) {
137a9e8641dSBaptiste Daroussin 		errno = 0;
138e56bad4aSBaptiste Daroussin 		logfail(EX_DATAERR, "path separator in username `%s'", user);
139a9e8641dSBaptiste Daroussin 		exit(1);
140a9e8641dSBaptiste Daroussin 	}
141a9e8641dSBaptiste Daroussin 
142a9e8641dSBaptiste Daroussin 	/* verify the user exists */
143a9e8641dSBaptiste Daroussin 	errno = 0;
144a9e8641dSBaptiste Daroussin 	pw = getpwnam(user);
145a9e8641dSBaptiste Daroussin 	if (!pw)
146e56bad4aSBaptiste Daroussin 		logfail(EX_NOUSER, "cannot find user `%s'", user);
147a9e8641dSBaptiste Daroussin 
148b72aa290SBaptiste Daroussin 	maildirfd = open(_PATH_MAILDIR, O_RDONLY);
149b72aa290SBaptiste Daroussin 	if (maildirfd < 0)
150b72aa290SBaptiste Daroussin 		logfail(EX_NOINPUT, "cannot open maildir %s", _PATH_MAILDIR);
151b72aa290SBaptiste Daroussin 
1529716e7d4SConrad Meyer 	/*
1539716e7d4SConrad Meyer 	 * Cache NLS data, for strerror, for err(3), before entering capability
1549716e7d4SConrad Meyer 	 * mode.
1559716e7d4SConrad Meyer 	 */
1569716e7d4SConrad Meyer 	caph_cache_catpages();
1579716e7d4SConrad Meyer 
1589716e7d4SConrad Meyer 	/*
1599716e7d4SConrad Meyer 	 * Cache local time before entering Capsicum capability sandbox.
1609716e7d4SConrad Meyer 	 */
1619716e7d4SConrad Meyer 	caph_cache_tzdata();
1629716e7d4SConrad Meyer 
1639716e7d4SConrad Meyer #if USE_CAPSICUM
1649716e7d4SConrad Meyer 	cap_rights_init(&rights, CAP_CREATE, CAP_FCHMOD, CAP_FCHOWN,
1659716e7d4SConrad Meyer 	    CAP_LOOKUP, CAP_READ);
1669716e7d4SConrad Meyer 	if (cap_rights_limit(maildirfd, &rights) < 0 && errno != ENOSYS)
1679716e7d4SConrad Meyer 		err(EX_OSERR, "can't limit maildirfd rights");
1689716e7d4SConrad Meyer 
1699716e7d4SConrad Meyer 	/* Enter Capsicum capability sandbox */
1707672a014SMariusz Zaborski 	if (caph_enter() < 0)
1719716e7d4SConrad Meyer 		err(EX_OSERR, "cap_enter");
1729716e7d4SConrad Meyer #endif
1739716e7d4SConrad Meyer 
174a9e8641dSBaptiste Daroussin 	user_uid = pw->pw_uid;
175a9e8641dSBaptiste Daroussin 
176b72aa290SBaptiste Daroussin 	f = openat(maildirfd, user, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600);
177a9e8641dSBaptiste Daroussin 	if (f < 0)
178b72aa290SBaptiste Daroussin 		logfail(EX_NOINPUT, "cannot open mbox `%s'", user);
179a9e8641dSBaptiste Daroussin 
180a9e8641dSBaptiste Daroussin 	if (fchown(f, user_uid, mail_gid))
181b72aa290SBaptiste Daroussin 		logfail(EX_OSERR, "cannot change owner of mbox `%s'", user);
182a9e8641dSBaptiste Daroussin 
183a9e8641dSBaptiste Daroussin 	if (fchmod(f, 0620))
184b72aa290SBaptiste Daroussin 		logfail(EX_OSERR, "cannot change permissions of mbox `%s'",
185b72aa290SBaptiste Daroussin 		    user);
186a9e8641dSBaptiste Daroussin 
187a9e8641dSBaptiste Daroussin 	/* file should be present with the right owner and permissions */
188a9e8641dSBaptiste Daroussin 
189a9e8641dSBaptiste Daroussin 	syslog(LOG_NOTICE, "successfully created mbox for `%s'", user);
190a9e8641dSBaptiste Daroussin 
191a9e8641dSBaptiste Daroussin 	return (0);
192a9e8641dSBaptiste Daroussin }
193