Index: head/sbin/hastd/hast.h =================================================================== --- head/sbin/hastd/hast.h (revision 218047) +++ head/sbin/hastd/hast.h (revision 218048) @@ -1,205 +1,206 @@ /*- * Copyright (c) 2009-2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _HAST_H_ #define _HAST_H_ #include #include #include #include #include #include #include #include #include #include "proto.h" /* * Version history: * 0 - initial version * 1 - HIO_KEEPALIVE added */ #define HAST_PROTO_VERSION 1 #define EHAST_OK 0 #define EHAST_NOENTRY 1 #define EHAST_INVALID 2 #define EHAST_NOMEMORY 3 #define EHAST_UNIMPLEMENTED 4 #define HASTCTL_CMD_UNKNOWN 0 #define HASTCTL_CMD_SETROLE 1 #define HASTCTL_CMD_STATUS 2 #define HAST_ROLE_UNDEF 0 #define HAST_ROLE_INIT 1 #define HAST_ROLE_PRIMARY 2 #define HAST_ROLE_SECONDARY 3 #define HAST_SYNCSRC_UNDEF 0 #define HAST_SYNCSRC_PRIMARY 1 #define HAST_SYNCSRC_SECONDARY 2 #define HIO_UNDEF 0 #define HIO_READ 1 #define HIO_WRITE 2 #define HIO_DELETE 3 #define HIO_FLUSH 4 #define HIO_KEEPALIVE 5 +#define HAST_USER "hast" #define HAST_TIMEOUT 5 #define HAST_CONFIG "/etc/hast.conf" #define HAST_CONTROL "/var/run/hastctl" #define HASTD_PORT 8457 #define HASTD_LISTEN "tcp4://0.0.0.0:8457" #define HASTD_PIDFILE "/var/run/hastd.pid" /* Default extent size. */ #define HAST_EXTENTSIZE 2097152 /* Default maximum number of extents that are kept dirty. */ #define HAST_KEEPDIRTY 64 #define HAST_ADDRSIZE 1024 #define HAST_TOKEN_SIZE 16 struct hastd_config { /* Address to communicate with hastctl(8). */ char hc_controladdr[HAST_ADDRSIZE]; /* Protocol-specific data. */ struct proto_conn *hc_controlconn; /* Incoming control connection. */ struct proto_conn *hc_controlin; /* Address to listen on. */ char hc_listenaddr[HAST_ADDRSIZE]; /* Protocol-specific data. */ struct proto_conn *hc_listenconn; /* List of resources. */ TAILQ_HEAD(, hast_resource) hc_resources; }; #define HAST_REPLICATION_FULLSYNC 0 #define HAST_REPLICATION_MEMSYNC 1 #define HAST_REPLICATION_ASYNC 2 /* * Structure that describes single resource. */ struct hast_resource { /* Resource name. */ char hr_name[NAME_MAX]; /* Replication mode (HAST_REPLICATION_*). */ int hr_replication; /* Provider name that will appear in /dev/hast/. */ char hr_provname[NAME_MAX]; /* Synchronization extent size. */ int hr_extentsize; /* Maximum number of extents that are kept dirty. */ int hr_keepdirty; /* Path to a program to execute on various events. */ char hr_exec[PATH_MAX]; /* Path to local component. */ char hr_localpath[PATH_MAX]; /* Descriptor to access local component. */ int hr_localfd; /* Offset into local component. */ off_t hr_localoff; /* Size of usable space. */ off_t hr_datasize; /* Size of entire local provider. */ off_t hr_local_mediasize; /* Sector size of local provider. */ unsigned int hr_local_sectorsize; /* Descriptor for /dev/ggctl communication. */ int hr_ggatefd; /* Unit number for ggate communication. */ int hr_ggateunit; /* Address of the remote component. */ char hr_remoteaddr[HAST_ADDRSIZE]; /* Connection for incoming data. */ struct proto_conn *hr_remotein; /* Connection for outgoing data. */ struct proto_conn *hr_remoteout; /* Token to verify both in and out connection are coming from the same node (not necessarily from the same address). */ unsigned char hr_token[HAST_TOKEN_SIZE]; /* Connection timeout. */ int hr_timeout; /* Resource unique identifier. */ uint64_t hr_resuid; /* Primary's local modification count. */ uint64_t hr_primary_localcnt; /* Primary's remote modification count. */ uint64_t hr_primary_remotecnt; /* Secondary's local modification count. */ uint64_t hr_secondary_localcnt; /* Secondary's remote modification count. */ uint64_t hr_secondary_remotecnt; /* Synchronization source. */ uint8_t hr_syncsrc; /* Resource role: HAST_ROLE_{INIT,PRIMARY,SECONDARY}. */ int hr_role; /* Previous resource role: HAST_ROLE_{INIT,PRIMARY,SECONDARY}. */ int hr_previous_role; /* PID of child worker process. 0 - no child. */ pid_t hr_workerpid; /* Control connection between parent and child. */ struct proto_conn *hr_ctrl; /* Events from child to parent. */ struct proto_conn *hr_event; /* Activemap structure. */ struct activemap *hr_amp; /* Locked used to synchronize access to hr_amp. */ pthread_mutex_t hr_amp_lock; /* Next resource. */ TAILQ_ENTRY(hast_resource) hr_next; }; struct hastd_config *yy_config_parse(const char *config, bool exitonerror); void yy_config_free(struct hastd_config *config); void yyerror(const char *); int yylex(void); int yyparse(void); #endif /* !_HAST_H_ */ Index: head/sbin/hastd/subr.c =================================================================== --- head/sbin/hastd/subr.c (revision 218047) +++ head/sbin/hastd/subr.c (revision 218048) @@ -1,118 +1,190 @@ /*- * Copyright (c) 2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include +#include +#include #include #include "hast.h" #include "subr.h" int provinfo(struct hast_resource *res, bool dowrite) { struct stat sb; assert(res->hr_localpath != NULL && res->hr_localpath[0] != '\0'); if (res->hr_localfd == -1) { res->hr_localfd = open(res->hr_localpath, dowrite ? O_RDWR : O_RDONLY); if (res->hr_localfd < 0) { KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to open %s", res->hr_localpath)); return (-1); } } if (fstat(res->hr_localfd, &sb) < 0) { KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to stat %s", res->hr_localpath)); return (-1); } if (S_ISCHR(sb.st_mode)) { /* * If this is character device, it is most likely GEOM provider. */ if (ioctl(res->hr_localfd, DIOCGMEDIASIZE, &res->hr_local_mediasize) < 0) { KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable obtain provider %s mediasize", res->hr_localpath)); return (-1); } if (ioctl(res->hr_localfd, DIOCGSECTORSIZE, &res->hr_local_sectorsize) < 0) { KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable obtain provider %s sectorsize", res->hr_localpath)); return (-1); } } else if (S_ISREG(sb.st_mode)) { /* * We also support regular files for which we hardcode * sector size of 512 bytes. */ res->hr_local_mediasize = sb.st_size; res->hr_local_sectorsize = 512; } else { /* * We support no other file types. */ pjdlog_error("%s is neither GEOM provider nor regular file.", res->hr_localpath); errno = EFTYPE; return (-1); } return (0); } const char * role2str(int role) { switch (role) { case HAST_ROLE_INIT: return ("init"); case HAST_ROLE_PRIMARY: return ("primary"); case HAST_ROLE_SECONDARY: return ("secondary"); } return ("unknown"); +} + +int +drop_privs(void) +{ + struct passwd *pw; + uid_t ruid, euid, suid; + gid_t rgid, egid, sgid; + gid_t gidset[1]; + + /* + * According to getpwnam(3) we have to clear errno before calling the + * function to be able to distinguish between an error and missing + * entry (with is not treated as error by getpwnam(3)). + */ + errno = 0; + pw = getpwnam(HAST_USER); + if (pw == NULL) { + if (errno != 0) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, + "Unable to find info about '%s' user", HAST_USER)); + return (-1); + } else { + pjdlog_error("'%s' user doesn't exist.", HAST_USER); + errno = ENOENT; + return (-1); + } + } + if (chroot(pw->pw_dir) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, + "Unable to change root directory to %s", pw->pw_dir)); + return (-1); + } + PJDLOG_VERIFY(chdir("/") == 0); + gidset[0] = pw->pw_gid; + if (setgroups(1, gidset) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, + "Unable to set groups to gid %u", + (unsigned int)pw->pw_gid)); + return (-1); + } + if (setgid(pw->pw_gid) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set gid to %u", + (unsigned int)pw->pw_gid)); + return (-1); + } + if (setuid(pw->pw_uid) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set uid to %u", + (unsigned int)pw->pw_uid)); + return (-1); + } + + /* + * Better be sure that everything succeeded. + */ + PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0); + PJDLOG_VERIFY(ruid == pw->pw_uid); + PJDLOG_VERIFY(euid == pw->pw_uid); + PJDLOG_VERIFY(suid == pw->pw_uid); + PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0); + PJDLOG_VERIFY(rgid == pw->pw_gid); + PJDLOG_VERIFY(egid == pw->pw_gid); + PJDLOG_VERIFY(sgid == pw->pw_gid); + PJDLOG_VERIFY(getgroups(0, NULL) == 1); + PJDLOG_VERIFY(getgroups(1, gidset) == 1); + PJDLOG_VERIFY(gidset[0] == pw->pw_gid); + + pjdlog_info("Privileges successfully dropped."); + + return (0); } Index: head/sbin/hastd/subr.h =================================================================== --- head/sbin/hastd/subr.h (revision 218047) +++ head/sbin/hastd/subr.h (revision 218048) @@ -1,51 +1,52 @@ /*- * Copyright (c) 2010 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef _SUBR_H_ #define _SUBR_H_ #include #include #include "hast.h" #define KEEP_ERRNO(work) do { \ int _rerrno; \ \ _rerrno = errno; \ work; \ errno = _rerrno; \ } while (0) int provinfo(struct hast_resource *res, bool dowrite); const char *role2str(int role); +int drop_privs(void); #endif /* !_SUBR_H_ */