114dfb991SJoris Giovannangeli /*
237d59876SJohn Marino * Copyright (c) 2010-2014, Simon Schubert <2@0x2c.org>.
314dfb991SJoris Giovannangeli * Copyright (c) 2008 The DragonFly Project. All rights reserved.
414dfb991SJoris Giovannangeli *
514dfb991SJoris Giovannangeli * This code is derived from software contributed to The DragonFly Project
637d59876SJohn Marino * by Simon Schubert <2@0x2c.org>.
714dfb991SJoris Giovannangeli *
814dfb991SJoris Giovannangeli * Redistribution and use in source and binary forms, with or without
914dfb991SJoris Giovannangeli * modification, are permitted provided that the following conditions
1014dfb991SJoris Giovannangeli * are met:
1114dfb991SJoris Giovannangeli *
1214dfb991SJoris Giovannangeli * 1. Redistributions of source code must retain the above copyright
1314dfb991SJoris Giovannangeli * notice, this list of conditions and the following disclaimer.
1414dfb991SJoris Giovannangeli * 2. Redistributions in binary form must reproduce the above copyright
1514dfb991SJoris Giovannangeli * notice, this list of conditions and the following disclaimer in
1614dfb991SJoris Giovannangeli * the documentation and/or other materials provided with the
1714dfb991SJoris Giovannangeli * distribution.
1814dfb991SJoris Giovannangeli * 3. Neither the name of The DragonFly Project nor the names of its
1914dfb991SJoris Giovannangeli * contributors may be used to endorse or promote products derived
2014dfb991SJoris Giovannangeli * from this software without specific, prior written permission.
2114dfb991SJoris Giovannangeli *
2214dfb991SJoris Giovannangeli * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2314dfb991SJoris Giovannangeli * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2414dfb991SJoris Giovannangeli * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
2514dfb991SJoris Giovannangeli * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
2614dfb991SJoris Giovannangeli * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
2714dfb991SJoris Giovannangeli * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
2814dfb991SJoris Giovannangeli * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2914dfb991SJoris Giovannangeli * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
3014dfb991SJoris Giovannangeli * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
3114dfb991SJoris Giovannangeli * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
3214dfb991SJoris Giovannangeli * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3314dfb991SJoris Giovannangeli * SUCH DAMAGE.
3414dfb991SJoris Giovannangeli */
3514dfb991SJoris Giovannangeli
3614dfb991SJoris Giovannangeli /*
3714dfb991SJoris Giovannangeli * This binary is setuid root. Use extreme caution when touching
3814dfb991SJoris Giovannangeli * user-supplied information. Keep the root window as small as possible.
3914dfb991SJoris Giovannangeli */
4014dfb991SJoris Giovannangeli
4114dfb991SJoris Giovannangeli #include <sys/param.h>
4214dfb991SJoris Giovannangeli #include <sys/stat.h>
4314dfb991SJoris Giovannangeli
4414dfb991SJoris Giovannangeli #include <errno.h>
4514dfb991SJoris Giovannangeli #include <fcntl.h>
4614dfb991SJoris Giovannangeli #include <grp.h>
4714dfb991SJoris Giovannangeli #include <paths.h>
4814dfb991SJoris Giovannangeli #include <pwd.h>
4914dfb991SJoris Giovannangeli #include <stdio.h>
50*92fe556dSDaniel Fojt #include <string.h>
5114dfb991SJoris Giovannangeli #include <syslog.h>
5214dfb991SJoris Giovannangeli #include <unistd.h>
5314dfb991SJoris Giovannangeli
5414dfb991SJoris Giovannangeli #include "dma.h"
5514dfb991SJoris Giovannangeli
5614dfb991SJoris Giovannangeli
5714dfb991SJoris Giovannangeli static void
logfail(int exitcode,const char * fmt,...)58*92fe556dSDaniel Fojt logfail(int exitcode, const char *fmt, ...)
5914dfb991SJoris Giovannangeli {
6014dfb991SJoris Giovannangeli int oerrno = errno;
6114dfb991SJoris Giovannangeli va_list ap;
6214dfb991SJoris Giovannangeli char outs[1024];
6314dfb991SJoris Giovannangeli
6414dfb991SJoris Giovannangeli outs[0] = 0;
6514dfb991SJoris Giovannangeli if (fmt != NULL) {
6614dfb991SJoris Giovannangeli va_start(ap, fmt);
6714dfb991SJoris Giovannangeli vsnprintf(outs, sizeof(outs), fmt, ap);
6814dfb991SJoris Giovannangeli va_end(ap);
6914dfb991SJoris Giovannangeli }
7014dfb991SJoris Giovannangeli
7114dfb991SJoris Giovannangeli errno = oerrno;
7214dfb991SJoris Giovannangeli if (*outs != 0)
7314dfb991SJoris Giovannangeli syslog(LOG_ERR, errno ? "%s: %m" : "%s", outs);
7414dfb991SJoris Giovannangeli else
7514dfb991SJoris Giovannangeli syslog(LOG_ERR, errno ? "%m" : "unknown error");
7614dfb991SJoris Giovannangeli
77*92fe556dSDaniel Fojt exit(exitcode);
7814dfb991SJoris Giovannangeli }
7914dfb991SJoris Giovannangeli
8014dfb991SJoris Giovannangeli /*
8114dfb991SJoris Giovannangeli * Create a mbox in /var/mail for a given user, or make sure
8214dfb991SJoris Giovannangeli * the permissions are correct for dma.
8314dfb991SJoris Giovannangeli */
8414dfb991SJoris Giovannangeli
8514dfb991SJoris Giovannangeli int
main(int argc,char ** argv)8614dfb991SJoris Giovannangeli main(int argc, char **argv)
8714dfb991SJoris Giovannangeli {
8814dfb991SJoris Giovannangeli const char *user;
8914dfb991SJoris Giovannangeli struct passwd *pw;
9014dfb991SJoris Giovannangeli struct group *gr;
9114dfb991SJoris Giovannangeli uid_t user_uid;
9214dfb991SJoris Giovannangeli gid_t mail_gid;
93*92fe556dSDaniel Fojt int f, maildirfd;
9414dfb991SJoris Giovannangeli
9514dfb991SJoris Giovannangeli openlog("dma-mbox-create", 0, LOG_MAIL);
9614dfb991SJoris Giovannangeli
9714dfb991SJoris Giovannangeli errno = 0;
9814dfb991SJoris Giovannangeli gr = getgrnam(DMA_GROUP);
9914dfb991SJoris Giovannangeli if (!gr)
100*92fe556dSDaniel Fojt logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP);
10114dfb991SJoris Giovannangeli
10214dfb991SJoris Giovannangeli mail_gid = gr->gr_gid;
10314dfb991SJoris Giovannangeli
10414dfb991SJoris Giovannangeli if (setgid(mail_gid) != 0)
105*92fe556dSDaniel Fojt logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP);
10614dfb991SJoris Giovannangeli if (getegid() != mail_gid)
107*92fe556dSDaniel Fojt logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid());
10814dfb991SJoris Giovannangeli
10914dfb991SJoris Giovannangeli /*
11014dfb991SJoris Giovannangeli * We take exactly one argument: the username.
11114dfb991SJoris Giovannangeli */
11214dfb991SJoris Giovannangeli if (argc != 2) {
11314dfb991SJoris Giovannangeli errno = 0;
114*92fe556dSDaniel Fojt logfail(EX_USAGE, "no arguments");
11514dfb991SJoris Giovannangeli }
11614dfb991SJoris Giovannangeli user = argv[1];
11714dfb991SJoris Giovannangeli
11814dfb991SJoris Giovannangeli syslog(LOG_NOTICE, "creating mbox for `%s'", user);
11914dfb991SJoris Giovannangeli
12014dfb991SJoris Giovannangeli /* the username may not contain a pathname separator */
12114dfb991SJoris Giovannangeli if (strchr(user, '/')) {
12214dfb991SJoris Giovannangeli errno = 0;
123*92fe556dSDaniel Fojt logfail(EX_DATAERR, "path separator in username `%s'", user);
12414dfb991SJoris Giovannangeli exit(1);
12514dfb991SJoris Giovannangeli }
12614dfb991SJoris Giovannangeli
12714dfb991SJoris Giovannangeli /* verify the user exists */
12814dfb991SJoris Giovannangeli errno = 0;
12914dfb991SJoris Giovannangeli pw = getpwnam(user);
13014dfb991SJoris Giovannangeli if (!pw)
131*92fe556dSDaniel Fojt logfail(EX_NOUSER, "cannot find user `%s'", user);
132*92fe556dSDaniel Fojt
133*92fe556dSDaniel Fojt maildirfd = open(_PATH_MAILDIR, O_RDONLY);
134*92fe556dSDaniel Fojt if (maildirfd < 0)
135*92fe556dSDaniel Fojt logfail(EX_NOINPUT, "cannot open maildir %s", _PATH_MAILDIR);
13614dfb991SJoris Giovannangeli
13714dfb991SJoris Giovannangeli user_uid = pw->pw_uid;
13814dfb991SJoris Giovannangeli
139*92fe556dSDaniel Fojt f = openat(maildirfd, user, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600);
14014dfb991SJoris Giovannangeli if (f < 0)
141*92fe556dSDaniel Fojt logfail(EX_NOINPUT, "cannot open mbox `%s'", user);
14214dfb991SJoris Giovannangeli
14314dfb991SJoris Giovannangeli if (fchown(f, user_uid, mail_gid))
144*92fe556dSDaniel Fojt logfail(EX_OSERR, "cannot change owner of mbox `%s'", user);
14514dfb991SJoris Giovannangeli
14614dfb991SJoris Giovannangeli if (fchmod(f, 0620))
147*92fe556dSDaniel Fojt logfail(EX_OSERR, "cannot change permissions of mbox `%s'",
148*92fe556dSDaniel Fojt user);
14914dfb991SJoris Giovannangeli
15014dfb991SJoris Giovannangeli /* file should be present with the right owner and permissions */
15114dfb991SJoris Giovannangeli
15214dfb991SJoris Giovannangeli syslog(LOG_NOTICE, "successfully created mbox for `%s'", user);
15314dfb991SJoris Giovannangeli
15414dfb991SJoris Giovannangeli return (0);
15514dfb991SJoris Giovannangeli }
156