1262266Sbapt/*
2289123Sbapt * Copyright (c) 2010-2014, Simon Schubert <2@0x2c.org>.
3262266Sbapt * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
4262266Sbapt *
5262266Sbapt * This code is derived from software contributed to The DragonFly Project
6289123Sbapt * by Simon Schubert <2@0x2c.org>.
7262266Sbapt *
8262266Sbapt * Redistribution and use in source and binary forms, with or without
9262266Sbapt * modification, are permitted provided that the following conditions
10262266Sbapt * are met:
11262266Sbapt *
12262266Sbapt * 1. Redistributions of source code must retain the above copyright
13262266Sbapt *    notice, this list of conditions and the following disclaimer.
14262266Sbapt * 2. Redistributions in binary form must reproduce the above copyright
15262266Sbapt *    notice, this list of conditions and the following disclaimer in
16262266Sbapt *    the documentation and/or other materials provided with the
17262266Sbapt *    distribution.
18262266Sbapt * 3. Neither the name of The DragonFly Project nor the names of its
19262266Sbapt *    contributors may be used to endorse or promote products derived
20262266Sbapt *    from this software without specific, prior written permission.
21262266Sbapt *
22262266Sbapt * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23262266Sbapt * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24262266Sbapt * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25262266Sbapt * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
26262266Sbapt * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27262266Sbapt * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
28262266Sbapt * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29262266Sbapt * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30262266Sbapt * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31262266Sbapt * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
32262266Sbapt * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33262266Sbapt * SUCH DAMAGE.
34262266Sbapt */
35262266Sbapt
36262266Sbapt/*
37262266Sbapt * This binary is setuid root.  Use extreme caution when touching
38262266Sbapt * user-supplied information.  Keep the root window as small as possible.
39262266Sbapt */
40262266Sbapt
41262266Sbapt#include <sys/param.h>
42262266Sbapt#include <sys/stat.h>
43262266Sbapt
44262266Sbapt#include <errno.h>
45262266Sbapt#include <fcntl.h>
46262266Sbapt#include <grp.h>
47262266Sbapt#include <paths.h>
48262266Sbapt#include <pwd.h>
49262266Sbapt#include <stdio.h>
50262266Sbapt#include <syslog.h>
51262266Sbapt#include <unistd.h>
52262266Sbapt
53262266Sbapt#include "dma.h"
54262266Sbapt
55262266Sbapt
56262266Sbaptstatic void
57289123Sbaptlogfail(int exitcode, const char *fmt, ...)
58262266Sbapt{
59262266Sbapt	int oerrno = errno;
60262266Sbapt	va_list ap;
61262266Sbapt	char outs[1024];
62262266Sbapt
63262266Sbapt	outs[0] = 0;
64262266Sbapt	if (fmt != NULL) {
65262266Sbapt		va_start(ap, fmt);
66262266Sbapt		vsnprintf(outs, sizeof(outs), fmt, ap);
67262266Sbapt		va_end(ap);
68262266Sbapt	}
69262266Sbapt
70262266Sbapt	errno = oerrno;
71262266Sbapt	if (*outs != 0)
72262266Sbapt		syslog(LOG_ERR, errno ? "%s: %m" : "%s", outs);
73262266Sbapt	else
74262266Sbapt		syslog(LOG_ERR, errno ? "%m" : "unknown error");
75262266Sbapt
76289123Sbapt	exit(exitcode);
77262266Sbapt}
78262266Sbapt
79262266Sbapt/*
80262266Sbapt * Create a mbox in /var/mail for a given user, or make sure
81262266Sbapt * the permissions are correct for dma.
82262266Sbapt */
83262266Sbapt
84262266Sbaptint
85262266Sbaptmain(int argc, char **argv)
86262266Sbapt{
87262266Sbapt	const char *user;
88262266Sbapt	struct passwd *pw;
89262266Sbapt	struct group *gr;
90262266Sbapt	uid_t user_uid;
91262266Sbapt	gid_t mail_gid;
92306800Sbapt	int f, maildirfd;
93262266Sbapt
94262266Sbapt	openlog("dma-mbox-create", 0, LOG_MAIL);
95262266Sbapt
96262266Sbapt	errno = 0;
97262266Sbapt	gr = getgrnam(DMA_GROUP);
98262266Sbapt	if (!gr)
99289123Sbapt		logfail(EX_CONFIG, "cannot find dma group `%s'", DMA_GROUP);
100262266Sbapt
101262266Sbapt	mail_gid = gr->gr_gid;
102262266Sbapt
103262266Sbapt	if (setgid(mail_gid) != 0)
104289123Sbapt		logfail(EX_NOPERM, "cannot set gid to %d (%s)", mail_gid, DMA_GROUP);
105262266Sbapt	if (getegid() != mail_gid)
106289123Sbapt		logfail(EX_NOPERM, "cannot set gid to %d (%s), still at %d", mail_gid, DMA_GROUP, getegid());
107262266Sbapt
108262266Sbapt	/*
109262266Sbapt	 * We take exactly one argument: the username.
110262266Sbapt	 */
111262266Sbapt	if (argc != 2) {
112262266Sbapt		errno = 0;
113289123Sbapt		logfail(EX_USAGE, "no arguments");
114262266Sbapt	}
115262266Sbapt	user = argv[1];
116262266Sbapt
117262266Sbapt	syslog(LOG_NOTICE, "creating mbox for `%s'", user);
118262266Sbapt
119262266Sbapt	/* the username may not contain a pathname separator */
120262266Sbapt	if (strchr(user, '/')) {
121262266Sbapt		errno = 0;
122289123Sbapt		logfail(EX_DATAERR, "path separator in username `%s'", user);
123262266Sbapt		exit(1);
124262266Sbapt	}
125262266Sbapt
126262266Sbapt	/* verify the user exists */
127262266Sbapt	errno = 0;
128262266Sbapt	pw = getpwnam(user);
129262266Sbapt	if (!pw)
130289123Sbapt		logfail(EX_NOUSER, "cannot find user `%s'", user);
131262266Sbapt
132306800Sbapt	maildirfd = open(_PATH_MAILDIR, O_RDONLY);
133306800Sbapt	if (maildirfd < 0)
134306800Sbapt		logfail(EX_NOINPUT, "cannot open maildir %s", _PATH_MAILDIR);
135306800Sbapt
136262266Sbapt	user_uid = pw->pw_uid;
137262266Sbapt
138306800Sbapt	f = openat(maildirfd, user, O_RDONLY|O_CREAT|O_NOFOLLOW, 0600);
139262266Sbapt	if (f < 0)
140306800Sbapt		logfail(EX_NOINPUT, "cannot open mbox `%s'", user);
141262266Sbapt
142262266Sbapt	if (fchown(f, user_uid, mail_gid))
143306800Sbapt		logfail(EX_OSERR, "cannot change owner of mbox `%s'", user);
144262266Sbapt
145262266Sbapt	if (fchmod(f, 0620))
146306800Sbapt		logfail(EX_OSERR, "cannot change permissions of mbox `%s'",
147306800Sbapt		    user);
148262266Sbapt
149262266Sbapt	/* file should be present with the right owner and permissions */
150262266Sbapt
151262266Sbapt	syslog(LOG_NOTICE, "successfully created mbox for `%s'", user);
152262266Sbapt
153262266Sbapt	return (0);
154262266Sbapt}
155