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