]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libcapsicum/libcapsicum_pwd.c
Symbolic bindings for the dts files...
[FreeBSD/FreeBSD.git] / lib / libcapsicum / libcapsicum_pwd.c
1 /*-
2  * Copyright (c) 2013 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$");
32
33 #include <sys/types.h>
34
35 #include <assert.h>
36 #include <errno.h>
37 #include <pwd.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42 #include <nv.h>
43
44 #include "libcapsicum.h"
45 #include "libcapsicum_pwd.h"
46
47 static struct passwd gpwd;
48 static char *gbuffer;
49 static size_t gbufsize;
50
51 static int
52 passwd_resize(void)
53 {
54         char *buf;
55
56         if (gbufsize == 0)
57                 gbufsize = 1024;
58         else
59                 gbufsize *= 2;
60
61         buf = gbuffer;
62         gbuffer = realloc(buf, gbufsize);
63         if (gbuffer == NULL) {
64                 free(buf);
65                 gbufsize = 0;
66                 return (ENOMEM);
67         }
68         memset(gbuffer, 0, gbufsize);
69
70         return (0);
71 }
72
73 static int
74 passwd_unpack_string(const nvlist_t *nvl, const char *fieldname, char **fieldp,
75     char **bufferp, size_t *bufsizep)
76 {
77         const char *str;
78         size_t len;
79
80         str = nvlist_get_string(nvl, fieldname);
81         len = strlcpy(*bufferp, str, *bufsizep);
82         if (len >= *bufsizep)
83                 return (ERANGE);
84         *fieldp = *bufferp;
85         *bufferp += len + 1;
86         *bufsizep -= len + 1;
87
88         return (0);
89 }
90
91 static int
92 passwd_unpack(const nvlist_t *nvl, struct passwd *pwd, char *buffer,
93     size_t bufsize)
94 {
95         int error;
96
97         if (!nvlist_exists_string(nvl, "pw_name"))
98                 return (EINVAL);
99
100         memset(pwd, 0, sizeof(*pwd));
101
102         error = passwd_unpack_string(nvl, "pw_name", &pwd->pw_name, &buffer,
103             &bufsize);
104         if (error != 0)
105                 return (error);
106         pwd->pw_uid = (uid_t)nvlist_get_number(nvl, "pw_uid");
107         pwd->pw_gid = (gid_t)nvlist_get_number(nvl, "pw_gid");
108         pwd->pw_change = (time_t)nvlist_get_number(nvl, "pw_change");
109         error = passwd_unpack_string(nvl, "pw_passwd", &pwd->pw_passwd, &buffer,
110             &bufsize);
111         if (error != 0)
112                 return (error);
113         error = passwd_unpack_string(nvl, "pw_class", &pwd->pw_class, &buffer,
114             &bufsize);
115         if (error != 0)
116                 return (error);
117         error = passwd_unpack_string(nvl, "pw_gecos", &pwd->pw_gecos, &buffer,
118             &bufsize);
119         if (error != 0)
120                 return (error);
121         error = passwd_unpack_string(nvl, "pw_dir", &pwd->pw_dir, &buffer,
122             &bufsize);
123         if (error != 0)
124                 return (error);
125         error = passwd_unpack_string(nvl, "pw_shell", &pwd->pw_shell, &buffer,
126             &bufsize);
127         if (error != 0)
128                 return (error);
129         pwd->pw_expire = (time_t)nvlist_get_number(nvl, "pw_expire");
130         pwd->pw_fields = (int)nvlist_get_number(nvl, "pw_fields");
131
132         return (0);
133 }
134
135 static int
136 cap_getpwcommon_r(cap_channel_t *chan, const char *cmd, const char *login,
137     uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
138     struct passwd **result)
139 {
140         nvlist_t *nvl;
141         bool getpw_r;
142         int error;
143
144         nvl = nvlist_create(0);
145         nvlist_add_string(nvl, "cmd", cmd);
146         if (strcmp(cmd, "getpwent") == 0 || strcmp(cmd, "getpwent_r") == 0) {
147                 /* Add nothing. */
148         } else if (strcmp(cmd, "getpwnam") == 0 ||
149             strcmp(cmd, "getpwnam_r") == 0) {
150                 nvlist_add_string(nvl, "name", login);
151         } else if (strcmp(cmd, "getpwuid") == 0 ||
152             strcmp(cmd, "getpwuid_r") == 0) {
153                 nvlist_add_number(nvl, "uid", (uint64_t)uid);
154         } else {
155                 abort();
156         }
157         nvl = cap_xfer_nvlist(chan, nvl);
158         if (nvl == NULL) {
159                 assert(errno != 0);
160                 *result = NULL;
161                 return (errno);
162         }
163         error = (int)nvlist_get_number(nvl, "error");
164         if (error != 0) {
165                 nvlist_destroy(nvl);
166                 *result = NULL;
167                 return (error);
168         }
169
170         if (!nvlist_exists_string(nvl, "pw_name")) {
171                 /* Not found. */
172                 nvlist_destroy(nvl);
173                 *result = NULL;
174                 return (0);
175         }
176
177         getpw_r = (strcmp(cmd, "getpwent_r") == 0 ||
178             strcmp(cmd, "getpwnam_r") == 0 || strcmp(cmd, "getpwuid_r") == 0);
179
180         for (;;) {
181                 error = passwd_unpack(nvl, pwd, buffer, bufsize);
182                 if (getpw_r || error != ERANGE)
183                         break;
184                 assert(buffer == gbuffer);
185                 assert(bufsize == gbufsize);
186                 error = passwd_resize();
187                 if (error != 0)
188                         break;
189                 /* Update pointers after resize. */
190                 buffer = gbuffer;
191                 bufsize = gbufsize;
192         }
193
194         nvlist_destroy(nvl);
195
196         if (error == 0)
197                 *result = pwd;
198         else
199                 *result = NULL;
200
201         return (error);
202 }
203
204 static struct passwd *
205 cap_getpwcommon(cap_channel_t *chan, const char *cmd, const char *login,
206     uid_t uid)
207 {
208         struct passwd *result;
209         int error, serrno;
210
211         serrno = errno;
212
213         error = cap_getpwcommon_r(chan, cmd, login, uid, &gpwd, gbuffer,
214             gbufsize, &result);
215         if (error != 0) {
216                 errno = error;
217                 return (NULL);
218         }
219
220         errno = serrno;
221
222         return (result);
223 }
224
225 struct passwd *
226 cap_getpwent(cap_channel_t *chan)
227 {
228
229         return (cap_getpwcommon(chan, "getpwent", NULL, 0));
230 }
231
232 struct passwd *
233 cap_getpwnam(cap_channel_t *chan, const char *login)
234 {
235
236         return (cap_getpwcommon(chan, "getpwnam", login, 0));
237 }
238
239 struct passwd *
240 cap_getpwuid(cap_channel_t *chan, uid_t uid)
241 {
242
243         return (cap_getpwcommon(chan, "getpwuid", NULL, uid));
244 }
245
246 int
247 cap_getpwent_r(cap_channel_t *chan, struct passwd *pwd, char *buffer,
248     size_t bufsize, struct passwd **result)
249 {
250
251         return (cap_getpwcommon_r(chan, "getpwent_r", NULL, 0, pwd, buffer,
252             bufsize, result));
253 }
254
255 int
256 cap_getpwnam_r(cap_channel_t *chan, const char *name, struct passwd *pwd,
257     char *buffer, size_t bufsize, struct passwd **result)
258 {
259
260         return (cap_getpwcommon_r(chan, "getpwnam_r", name, 0, pwd, buffer,
261             bufsize, result));
262 }
263
264 int
265 cap_getpwuid_r(cap_channel_t *chan, uid_t uid, struct passwd *pwd, char *buffer,
266     size_t bufsize, struct passwd **result)
267 {
268
269         return (cap_getpwcommon_r(chan, "getpwuid_r", NULL, uid, pwd, buffer,
270             bufsize, result));
271 }
272
273 int
274 cap_setpassent(cap_channel_t *chan, int stayopen)
275 {
276         nvlist_t *nvl;
277
278         nvl = nvlist_create(0);
279         nvlist_add_string(nvl, "cmd", "setpassent");
280         nvlist_add_bool(nvl, "stayopen", stayopen != 0);
281         nvl = cap_xfer_nvlist(chan, nvl);
282         if (nvl == NULL)
283                 return (0);
284         if (nvlist_get_number(nvl, "error") != 0) {
285                 errno = nvlist_get_number(nvl, "error");
286                 nvlist_destroy(nvl);
287                 return (0);
288         }
289         nvlist_destroy(nvl);
290
291         return (1);
292 }
293
294 static void
295 cap_set_end_pwent(cap_channel_t *chan, const char *cmd)
296 {
297         nvlist_t *nvl;
298
299         nvl = nvlist_create(0);
300         nvlist_add_string(nvl, "cmd", cmd);
301         /* Ignore any errors, we have no way to report them. */
302         nvlist_destroy(cap_xfer_nvlist(chan, nvl));
303 }
304
305 void
306 cap_setpwent(cap_channel_t *chan)
307 {
308
309         cap_set_end_pwent(chan, "setpwent");
310 }
311
312 void
313 cap_endpwent(cap_channel_t *chan)
314 {
315
316         cap_set_end_pwent(chan, "endpwent");
317 }
318
319 int
320 cap_pwd_limit_cmds(cap_channel_t *chan, const char * const *cmds, size_t ncmds)
321 {
322         nvlist_t *limits, *nvl;
323         unsigned int i;
324
325         if (cap_limit_get(chan, &limits) < 0)
326                 return (-1);
327         if (limits == NULL) {
328                 limits = nvlist_create(0);
329         } else {
330                 if (nvlist_exists_nvlist(limits, "cmds"))
331                         nvlist_free_nvlist(limits, "cmds");
332         }
333         nvl = nvlist_create(0);
334         for (i = 0; i < ncmds; i++)
335                 nvlist_add_null(nvl, cmds[i]);
336         nvlist_move_nvlist(limits, "cmds", nvl);
337         return (cap_limit_set(chan, limits));
338 }
339
340 int
341 cap_pwd_limit_fields(cap_channel_t *chan, const char * const *fields,
342     size_t nfields)
343 {
344         nvlist_t *limits, *nvl;
345         unsigned int i;
346
347         if (cap_limit_get(chan, &limits) < 0)
348                 return (-1);
349         if (limits == NULL) {
350                 limits = nvlist_create(0);
351         } else {
352                 if (nvlist_exists_nvlist(limits, "fields"))
353                         nvlist_free_nvlist(limits, "fields");
354         }
355         nvl = nvlist_create(0);
356         for (i = 0; i < nfields; i++)
357                 nvlist_add_null(nvl, fields[i]);
358         nvlist_move_nvlist(limits, "fields", nvl);
359         return (cap_limit_set(chan, limits));
360 }
361
362 int
363 cap_pwd_limit_users(cap_channel_t *chan, const char * const *names,
364     size_t nnames, uid_t *uids, size_t nuids)
365 {
366         nvlist_t *limits, *users;
367         unsigned int i;
368
369         if (cap_limit_get(chan, &limits) < 0)
370                 return (-1);
371         if (limits == NULL) {
372                 limits = nvlist_create(0);
373         } else {
374                 if (nvlist_exists_nvlist(limits, "users"))
375                         nvlist_free_nvlist(limits, "users");
376         }
377         users = nvlist_create(0);
378         for (i = 0; i < nuids; i++)
379                 nvlist_addf_number(users, (uint64_t)uids[i], "uid%u", i);
380         for (i = 0; i < nnames; i++)
381                 nvlist_addf_string(users, names[i], "name%u", i);
382         nvlist_move_nvlist(limits, "users", users);
383         return (cap_limit_set(chan, limits));
384 }