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