Merge branch 'vendor/ZSTD' into master
[dragonfly.git] / libexec / dma / dma-mbox-create.c
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 #include <sys/param.h>
42 #include <sys/stat.h>
43
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <grp.h>
47 #include <paths.h>
48 #include <pwd.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <unistd.h>
53
54 #include "dma.h"
55
56
57 static void
58 logfail(int exitcode, const char *fmt, ...)
59 {
60         int oerrno = errno;
61         va_list ap;
62         char outs[1024];
63
64         outs[0] = 0;
65         if (fmt != NULL) {
66                 va_start(ap, fmt);
67                 vsnprintf(outs, sizeof(outs), fmt, ap);
68                 va_end(ap);
69         }
70
71         errno = oerrno;
72         if (*outs != 0)
73                 syslog(LOG_ERR, errno ? "%s: %m" : "%s", outs);
74         else
75                 syslog(LOG_ERR, errno ? "%m" : "unknown error");
76
77         exit(exitcode);
78 }
79
80 /*
81  * Create a mbox in /var/mail for a given user, or make sure
82  * the permissions are correct for dma.
83  */
84
85 int
86 main(int argc, char **argv)
87 {
88         const char *user;
89         struct passwd *pw;
90         struct group *gr;
91         uid_t user_uid;
92         gid_t mail_gid;
93         int f, maildirfd;
94
95         openlog("dma-mbox-create", 0, LOG_MAIL);
96
97         errno = 0;
98         gr = getgrnam(DMA_GROUP);
99         if (!gr)
100                 logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP);
101
102         mail_gid = gr->gr_gid;
103
104         if (setgid(mail_gid) != 0)
105                 logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP);
106         if (getegid() != mail_gid)
107                 logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid());
108
109         /*
110          * We take exactly one argument: the username.
111          */
112         if (argc != 2) {
113                 errno = 0;
114                 logfail(EX_USAGE, "no arguments");
115         }
116         user = argv[1];
117
118         syslog(LOG_NOTICE, "creating mbox for `%s'", user);
119
120         /* the username may not contain a pathname separator */
121         if (strchr(user, '/')) {
122                 errno = 0;
123                 logfail(EX_DATAERR, "path separator in username `%s'", user);
124                 exit(1);
125         }
126
127         /* verify the user exists */
128         errno = 0;
129         pw = getpwnam(user);
130         if (!pw)
131                 logfail(EX_NOUSER, "cannot find user `%s'", user);
132
133         maildirfd = open(_PATH_MAILDIR, O_RDONLY);
134         if (maildirfd < 0)
135                 logfail(EX_NOINPUT, "cannot open maildir %s", _PATH_MAILDIR);
136
137         user_uid = pw->pw_uid;
138
139         f = openat(maildirfd, user, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600);
140         if (f < 0)
141                 logfail(EX_NOINPUT, "cannot open mbox `%s'", user);
142
143         if (fchown(f, user_uid, mail_gid))
144                 logfail(EX_OSERR, "cannot change owner of mbox `%s'", user);
145
146         if (fchmod(f, 0620))
147                 logfail(EX_OSERR, "cannot change permissions of mbox `%s'",
148                     user);
149
150         /* file should be present with the right owner and permissions */
151
152         syslog(LOG_NOTICE, "successfully created mbox for `%s'", user);
153
154         return (0);
155 }