xref: /dflybsd-src/libexec/dma/dma-mbox-create.c (revision 92fe556d1644256324e534f2cbaef0e73e2d85bc)
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