subr.c revision 218048
1204076Spjd/*-
2204076Spjd * Copyright (c) 2010 The FreeBSD Foundation
3204076Spjd * All rights reserved.
4204076Spjd *
5204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from
6204076Spjd * the FreeBSD Foundation.
7204076Spjd *
8204076Spjd * Redistribution and use in source and binary forms, with or without
9204076Spjd * modification, are permitted provided that the following conditions
10204076Spjd * are met:
11204076Spjd * 1. Redistributions of source code must retain the above copyright
12204076Spjd *    notice, this list of conditions and the following disclaimer.
13204076Spjd * 2. Redistributions in binary form must reproduce the above copyright
14204076Spjd *    notice, this list of conditions and the following disclaimer in the
15204076Spjd *    documentation and/or other materials provided with the distribution.
16204076Spjd *
17204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20204076Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27204076Spjd * SUCH DAMAGE.
28204076Spjd */
29204076Spjd
30204076Spjd#include <sys/cdefs.h>
31204076Spjd__FBSDID("$FreeBSD: head/sbin/hastd/subr.c 218048 2011-01-28 22:33:47Z pjd $");
32204076Spjd
33204076Spjd#include <sys/types.h>
34204076Spjd#include <sys/disk.h>
35204076Spjd#include <sys/ioctl.h>
36204076Spjd#include <sys/stat.h>
37204076Spjd
38204076Spjd#include <assert.h>
39204076Spjd#include <errno.h>
40204076Spjd#include <fcntl.h>
41218048Spjd#include <pwd.h>
42218048Spjd#include <unistd.h>
43204076Spjd
44204076Spjd#include <pjdlog.h>
45204076Spjd
46204076Spjd#include "hast.h"
47204076Spjd#include "subr.h"
48204076Spjd
49204076Spjdint
50204076Spjdprovinfo(struct hast_resource *res, bool dowrite)
51204076Spjd{
52204076Spjd	struct stat sb;
53204076Spjd
54204076Spjd	assert(res->hr_localpath != NULL && res->hr_localpath[0] != '\0');
55204076Spjd
56204076Spjd	if (res->hr_localfd == -1) {
57204076Spjd		res->hr_localfd = open(res->hr_localpath,
58204076Spjd		    dowrite ? O_RDWR : O_RDONLY);
59204076Spjd		if (res->hr_localfd < 0) {
60204076Spjd			KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to open %s",
61204076Spjd			    res->hr_localpath));
62204076Spjd			return (-1);
63204076Spjd		}
64204076Spjd	}
65204076Spjd	if (fstat(res->hr_localfd, &sb) < 0) {
66204076Spjd		KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to stat %s",
67204076Spjd		    res->hr_localpath));
68204076Spjd		return (-1);
69204076Spjd	}
70204076Spjd	if (S_ISCHR(sb.st_mode)) {
71204076Spjd		/*
72204076Spjd		 * If this is character device, it is most likely GEOM provider.
73204076Spjd		 */
74204076Spjd		if (ioctl(res->hr_localfd, DIOCGMEDIASIZE,
75204076Spjd		    &res->hr_local_mediasize) < 0) {
76204076Spjd			KEEP_ERRNO(pjdlog_errno(LOG_ERR,
77204076Spjd			    "Unable obtain provider %s mediasize",
78204076Spjd			    res->hr_localpath));
79204076Spjd			return (-1);
80204076Spjd		}
81204076Spjd		if (ioctl(res->hr_localfd, DIOCGSECTORSIZE,
82204076Spjd		    &res->hr_local_sectorsize) < 0) {
83204076Spjd			KEEP_ERRNO(pjdlog_errno(LOG_ERR,
84204076Spjd			    "Unable obtain provider %s sectorsize",
85204076Spjd			    res->hr_localpath));
86204076Spjd			return (-1);
87204076Spjd		}
88204076Spjd	} else if (S_ISREG(sb.st_mode)) {
89204076Spjd		/*
90204076Spjd		 * We also support regular files for which we hardcode
91204076Spjd		 * sector size of 512 bytes.
92204076Spjd		 */
93204076Spjd		res->hr_local_mediasize = sb.st_size;
94204076Spjd		res->hr_local_sectorsize = 512;
95204076Spjd	} else {
96204076Spjd		/*
97204076Spjd		 * We support no other file types.
98204076Spjd		 */
99204076Spjd		pjdlog_error("%s is neither GEOM provider nor regular file.",
100204076Spjd		    res->hr_localpath);
101204076Spjd		errno = EFTYPE;
102204076Spjd		return (-1);
103204076Spjd	}
104204076Spjd	return (0);
105204076Spjd}
106204076Spjd
107204076Spjdconst char *
108204076Spjdrole2str(int role)
109204076Spjd{
110204076Spjd
111204076Spjd	switch (role) {
112204076Spjd	case HAST_ROLE_INIT:
113204076Spjd		return ("init");
114204076Spjd	case HAST_ROLE_PRIMARY:
115204076Spjd		return ("primary");
116204076Spjd	case HAST_ROLE_SECONDARY:
117204076Spjd		return ("secondary");
118204076Spjd	}
119204076Spjd	return ("unknown");
120204076Spjd}
121218048Spjd
122218048Spjdint
123218048Spjddrop_privs(void)
124218048Spjd{
125218048Spjd	struct passwd *pw;
126218048Spjd	uid_t ruid, euid, suid;
127218048Spjd	gid_t rgid, egid, sgid;
128218048Spjd	gid_t gidset[1];
129218048Spjd
130218048Spjd	/*
131218048Spjd	 * According to getpwnam(3) we have to clear errno before calling the
132218048Spjd	 * function to be able to distinguish between an error and missing
133218048Spjd	 * entry (with is not treated as error by getpwnam(3)).
134218048Spjd	 */
135218048Spjd	errno = 0;
136218048Spjd	pw = getpwnam(HAST_USER);
137218048Spjd	if (pw == NULL) {
138218048Spjd		if (errno != 0) {
139218048Spjd			KEEP_ERRNO(pjdlog_errno(LOG_ERR,
140218048Spjd			    "Unable to find info about '%s' user", HAST_USER));
141218048Spjd			return (-1);
142218048Spjd		} else {
143218048Spjd			pjdlog_error("'%s' user doesn't exist.", HAST_USER);
144218048Spjd			errno = ENOENT;
145218048Spjd			return (-1);
146218048Spjd		}
147218048Spjd	}
148218048Spjd	if (chroot(pw->pw_dir) == -1) {
149218048Spjd		KEEP_ERRNO(pjdlog_errno(LOG_ERR,
150218048Spjd		    "Unable to change root directory to %s", pw->pw_dir));
151218048Spjd		return (-1);
152218048Spjd	}
153218048Spjd	PJDLOG_VERIFY(chdir("/") == 0);
154218048Spjd	gidset[0] = pw->pw_gid;
155218048Spjd	if (setgroups(1, gidset) == -1) {
156218048Spjd		KEEP_ERRNO(pjdlog_errno(LOG_ERR,
157218048Spjd		    "Unable to set groups to gid %u",
158218048Spjd		    (unsigned int)pw->pw_gid));
159218048Spjd		return (-1);
160218048Spjd	}
161218048Spjd	if (setgid(pw->pw_gid) == -1) {
162218048Spjd		KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set gid to %u",
163218048Spjd		    (unsigned int)pw->pw_gid));
164218048Spjd		return (-1);
165218048Spjd	}
166218048Spjd	if (setuid(pw->pw_uid) == -1) {
167218048Spjd		KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set uid to %u",
168218048Spjd		    (unsigned int)pw->pw_uid));
169218048Spjd		return (-1);
170218048Spjd	}
171218048Spjd
172218048Spjd	/*
173218048Spjd	 * Better be sure that everything succeeded.
174218048Spjd	 */
175218048Spjd	PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0);
176218048Spjd	PJDLOG_VERIFY(ruid == pw->pw_uid);
177218048Spjd	PJDLOG_VERIFY(euid == pw->pw_uid);
178218048Spjd	PJDLOG_VERIFY(suid == pw->pw_uid);
179218048Spjd	PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0);
180218048Spjd	PJDLOG_VERIFY(rgid == pw->pw_gid);
181218048Spjd	PJDLOG_VERIFY(egid == pw->pw_gid);
182218048Spjd	PJDLOG_VERIFY(sgid == pw->pw_gid);
183218048Spjd	PJDLOG_VERIFY(getgroups(0, NULL) == 1);
184218048Spjd	PJDLOG_VERIFY(getgroups(1, gidset) == 1);
185218048Spjd	PJDLOG_VERIFY(gidset[0] == pw->pw_gid);
186218048Spjd
187218048Spjd	pjdlog_info("Privileges successfully dropped.");
188218048Spjd
189218048Spjd	return (0);
190218048Spjd}
191