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