Deleted Added
full compact
subr.c (218214) subr.c (219815)
1/*-
2 * Copyright (c) 2010 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2010 The FreeBSD Foundation
3 * All rights reserved.
4 *
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: head/sbin/hastd/subr.c 218214 2011-02-03 10:37:44Z pjd $");
31__FBSDID("$FreeBSD: head/sbin/hastd/subr.c 219815 2011-03-21 08:36:50Z pjd $");
32
33#include <sys/types.h>
34#include <sys/disk.h>
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37
38#include <errno.h>
39#include <fcntl.h>
40#include <pwd.h>
32
33#include <sys/types.h>
34#include <sys/disk.h>
35#include <sys/ioctl.h>
36#include <sys/stat.h>
37
38#include <errno.h>
39#include <fcntl.h>
40#include <pwd.h>
41#include <stdarg.h>
42#include <stdio.h>
43#include <string.h>
41#include <unistd.h>
42
43#include <pjdlog.h>
44
45#include "hast.h"
46#include "subr.h"
47
48int
44#include <unistd.h>
45
46#include <pjdlog.h>
47
48#include "hast.h"
49#include "subr.h"
50
51int
52vsnprlcat(char *str, size_t size, const char *fmt, va_list ap)
53{
54 size_t len;
55
56 len = strlen(str);
57 return (vsnprintf(str + len, size - len, fmt, ap));
58}
59
60int
61snprlcat(char *str, size_t size, const char *fmt, ...)
62{
63 va_list ap;
64 int result;
65
66 va_start(ap, fmt);
67 result = vsnprlcat(str, size, fmt, ap);
68 va_end(ap);
69 return (result);
70}
71
72int
49provinfo(struct hast_resource *res, bool dowrite)
50{
51 struct stat sb;
52
53 PJDLOG_ASSERT(res->hr_localpath != NULL &&
54 res->hr_localpath[0] != '\0');
55
56 if (res->hr_localfd == -1) {
57 res->hr_localfd = open(res->hr_localpath,
58 dowrite ? O_RDWR : O_RDONLY);
59 if (res->hr_localfd < 0) {
60 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to open %s",
61 res->hr_localpath));
62 return (-1);
63 }
64 }
65 if (fstat(res->hr_localfd, &sb) < 0) {
66 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to stat %s",
67 res->hr_localpath));
68 return (-1);
69 }
70 if (S_ISCHR(sb.st_mode)) {
71 /*
72 * If this is character device, it is most likely GEOM provider.
73 */
74 if (ioctl(res->hr_localfd, DIOCGMEDIASIZE,
75 &res->hr_local_mediasize) < 0) {
76 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
77 "Unable obtain provider %s mediasize",
78 res->hr_localpath));
79 return (-1);
80 }
81 if (ioctl(res->hr_localfd, DIOCGSECTORSIZE,
82 &res->hr_local_sectorsize) < 0) {
83 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
84 "Unable obtain provider %s sectorsize",
85 res->hr_localpath));
86 return (-1);
87 }
88 } else if (S_ISREG(sb.st_mode)) {
89 /*
90 * We also support regular files for which we hardcode
91 * sector size of 512 bytes.
92 */
93 res->hr_local_mediasize = sb.st_size;
94 res->hr_local_sectorsize = 512;
95 } else {
96 /*
97 * We support no other file types.
98 */
99 pjdlog_error("%s is neither GEOM provider nor regular file.",
100 res->hr_localpath);
101 errno = EFTYPE;
102 return (-1);
103 }
104 return (0);
105}
106
107const char *
108role2str(int role)
109{
110
111 switch (role) {
112 case HAST_ROLE_INIT:
113 return ("init");
114 case HAST_ROLE_PRIMARY:
115 return ("primary");
116 case HAST_ROLE_SECONDARY:
117 return ("secondary");
118 }
119 return ("unknown");
120}
121
122int
123drop_privs(void)
124{
125 struct passwd *pw;
126 uid_t ruid, euid, suid;
127 gid_t rgid, egid, sgid;
128 gid_t gidset[1];
129
130 /*
131 * According to getpwnam(3) we have to clear errno before calling the
132 * function to be able to distinguish between an error and missing
133 * entry (with is not treated as error by getpwnam(3)).
134 */
135 errno = 0;
136 pw = getpwnam(HAST_USER);
137 if (pw == NULL) {
138 if (errno != 0) {
139 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
140 "Unable to find info about '%s' user", HAST_USER));
141 return (-1);
142 } else {
143 pjdlog_error("'%s' user doesn't exist.", HAST_USER);
144 errno = ENOENT;
145 return (-1);
146 }
147 }
148 if (chroot(pw->pw_dir) == -1) {
149 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
150 "Unable to change root directory to %s", pw->pw_dir));
151 return (-1);
152 }
153 PJDLOG_VERIFY(chdir("/") == 0);
154 gidset[0] = pw->pw_gid;
155 if (setgroups(1, gidset) == -1) {
156 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
157 "Unable to set groups to gid %u",
158 (unsigned int)pw->pw_gid));
159 return (-1);
160 }
161 if (setgid(pw->pw_gid) == -1) {
162 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set gid to %u",
163 (unsigned int)pw->pw_gid));
164 return (-1);
165 }
166 if (setuid(pw->pw_uid) == -1) {
167 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set uid to %u",
168 (unsigned int)pw->pw_uid));
169 return (-1);
170 }
171
172 /*
173 * Better be sure that everything succeeded.
174 */
175 PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0);
176 PJDLOG_VERIFY(ruid == pw->pw_uid);
177 PJDLOG_VERIFY(euid == pw->pw_uid);
178 PJDLOG_VERIFY(suid == pw->pw_uid);
179 PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0);
180 PJDLOG_VERIFY(rgid == pw->pw_gid);
181 PJDLOG_VERIFY(egid == pw->pw_gid);
182 PJDLOG_VERIFY(sgid == pw->pw_gid);
183 PJDLOG_VERIFY(getgroups(0, NULL) == 1);
184 PJDLOG_VERIFY(getgroups(1, gidset) == 1);
185 PJDLOG_VERIFY(gidset[0] == pw->pw_gid);
186
187 return (0);
188}
73provinfo(struct hast_resource *res, bool dowrite)
74{
75 struct stat sb;
76
77 PJDLOG_ASSERT(res->hr_localpath != NULL &&
78 res->hr_localpath[0] != '\0');
79
80 if (res->hr_localfd == -1) {
81 res->hr_localfd = open(res->hr_localpath,
82 dowrite ? O_RDWR : O_RDONLY);
83 if (res->hr_localfd < 0) {
84 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to open %s",
85 res->hr_localpath));
86 return (-1);
87 }
88 }
89 if (fstat(res->hr_localfd, &sb) < 0) {
90 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to stat %s",
91 res->hr_localpath));
92 return (-1);
93 }
94 if (S_ISCHR(sb.st_mode)) {
95 /*
96 * If this is character device, it is most likely GEOM provider.
97 */
98 if (ioctl(res->hr_localfd, DIOCGMEDIASIZE,
99 &res->hr_local_mediasize) < 0) {
100 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
101 "Unable obtain provider %s mediasize",
102 res->hr_localpath));
103 return (-1);
104 }
105 if (ioctl(res->hr_localfd, DIOCGSECTORSIZE,
106 &res->hr_local_sectorsize) < 0) {
107 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
108 "Unable obtain provider %s sectorsize",
109 res->hr_localpath));
110 return (-1);
111 }
112 } else if (S_ISREG(sb.st_mode)) {
113 /*
114 * We also support regular files for which we hardcode
115 * sector size of 512 bytes.
116 */
117 res->hr_local_mediasize = sb.st_size;
118 res->hr_local_sectorsize = 512;
119 } else {
120 /*
121 * We support no other file types.
122 */
123 pjdlog_error("%s is neither GEOM provider nor regular file.",
124 res->hr_localpath);
125 errno = EFTYPE;
126 return (-1);
127 }
128 return (0);
129}
130
131const char *
132role2str(int role)
133{
134
135 switch (role) {
136 case HAST_ROLE_INIT:
137 return ("init");
138 case HAST_ROLE_PRIMARY:
139 return ("primary");
140 case HAST_ROLE_SECONDARY:
141 return ("secondary");
142 }
143 return ("unknown");
144}
145
146int
147drop_privs(void)
148{
149 struct passwd *pw;
150 uid_t ruid, euid, suid;
151 gid_t rgid, egid, sgid;
152 gid_t gidset[1];
153
154 /*
155 * According to getpwnam(3) we have to clear errno before calling the
156 * function to be able to distinguish between an error and missing
157 * entry (with is not treated as error by getpwnam(3)).
158 */
159 errno = 0;
160 pw = getpwnam(HAST_USER);
161 if (pw == NULL) {
162 if (errno != 0) {
163 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
164 "Unable to find info about '%s' user", HAST_USER));
165 return (-1);
166 } else {
167 pjdlog_error("'%s' user doesn't exist.", HAST_USER);
168 errno = ENOENT;
169 return (-1);
170 }
171 }
172 if (chroot(pw->pw_dir) == -1) {
173 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
174 "Unable to change root directory to %s", pw->pw_dir));
175 return (-1);
176 }
177 PJDLOG_VERIFY(chdir("/") == 0);
178 gidset[0] = pw->pw_gid;
179 if (setgroups(1, gidset) == -1) {
180 KEEP_ERRNO(pjdlog_errno(LOG_ERR,
181 "Unable to set groups to gid %u",
182 (unsigned int)pw->pw_gid));
183 return (-1);
184 }
185 if (setgid(pw->pw_gid) == -1) {
186 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set gid to %u",
187 (unsigned int)pw->pw_gid));
188 return (-1);
189 }
190 if (setuid(pw->pw_uid) == -1) {
191 KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set uid to %u",
192 (unsigned int)pw->pw_uid));
193 return (-1);
194 }
195
196 /*
197 * Better be sure that everything succeeded.
198 */
199 PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0);
200 PJDLOG_VERIFY(ruid == pw->pw_uid);
201 PJDLOG_VERIFY(euid == pw->pw_uid);
202 PJDLOG_VERIFY(suid == pw->pw_uid);
203 PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0);
204 PJDLOG_VERIFY(rgid == pw->pw_gid);
205 PJDLOG_VERIFY(egid == pw->pw_gid);
206 PJDLOG_VERIFY(sgid == pw->pw_gid);
207 PJDLOG_VERIFY(getgroups(0, NULL) == 1);
208 PJDLOG_VERIFY(getgroups(1, gidset) == 1);
209 PJDLOG_VERIFY(gidset[0] == pw->pw_gid);
210
211 return (0);
212}