Changes spcfd_add so it accepts an offset (this will be used by xget for
[spfs.git] / libspfs / uxusers.c
blob4a4aa790ab96313e6ca369013158022884f2de74
1 /*
2 * Copyright (C) 2006 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <string.h>
28 #include <pwd.h>
29 #include <grp.h>
30 #include <errno.h>
31 #include "spfs.h"
32 #include "spfsimpl.h"
34 static Spuser *sp_unix_uname2user(Spuserpool *, char *uname);
35 static Spuser *sp_unix_uid2user(Spuserpool *, u32 uid);
36 static Spgroup *sp_unix_gname2group(Spuserpool *, char *gname);
37 static Spgroup *sp_unix_gid2group(Spuserpool *, u32 gid);
38 static int sp_unix_ismember(Spuserpool *, Spuser *u, Spgroup *g);
39 static void sp_unix_udestroy(Spuserpool *, Spuser *);
40 static void sp_unix_gdestroy(Spuserpool *, Spgroup *);
41 static int sp_init_user_groups(Spuser *u);
43 static Spuserpool upool = {
44 .uname2user = sp_unix_uname2user,
45 .uid2user = sp_unix_uid2user,
46 .gname2group = sp_unix_gname2group,
47 .gid2group = sp_unix_gid2group,
48 .ismember = sp_unix_ismember,
49 .udestroy = sp_unix_udestroy,
50 .gdestroy = sp_unix_gdestroy,
53 Spuserpool *sp_unix_users = &upool;
55 static struct Spusercache {
56 int init;
57 int hsize;
58 Spuser** htable;
59 } usercache = { 0 };
61 static struct Spgroupcache {
62 int init;
63 int hsize;
64 Spgroup** htable;
65 } groupcache = { 0 };
67 static void
68 initusercache(void)
70 if (!usercache.init) {
71 usercache.hsize = 64;
72 usercache.htable = calloc(usercache.hsize, sizeof(Spuser *));
73 usercache.init = 1;
77 static void
78 initgroupcache(void)
80 if (!groupcache.init) {
81 groupcache.hsize = 64;
82 groupcache.htable = calloc(groupcache.hsize, sizeof(Spgroup *));
83 if (!groupcache.htable) {
84 sp_werror(Enomem, ENOMEM);
85 return;
87 groupcache.init = 1;
91 static Spuser *
92 sp_unix_uname2user(Spuserpool *up, char *uname)
94 int i, n;
95 struct passwd pw, *pwp;
96 int bufsize;
97 char *buf;
98 Spuser *u;
100 if (!usercache.init)
101 initusercache();
103 for(i = 0; i<usercache.hsize; i++)
104 for(u = usercache.htable[i]; u != NULL; u = u->next)
105 if (strcmp(uname, u->uname) == 0)
106 goto done;
108 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
109 if (bufsize < 256)
110 bufsize = 256;
112 buf = sp_malloc(bufsize);
113 if (!buf)
114 return NULL;
116 i = getpwnam_r(uname, &pw, buf, bufsize, &pwp);
117 if (i) {
118 sp_uerror(i);
119 free(buf);
120 return NULL;
123 u = sp_malloc(sizeof(*u) + strlen(pw.pw_name) + 1);
124 if (!u) {
125 free(buf);
126 return NULL;
129 u->refcount = 1;
130 u->upool = up;
131 u->uid = pw.pw_uid;
132 u->uname = (char *)u + sizeof(*u);
133 strcpy(u->uname, pw.pw_name);
134 u->dfltgroup = (*up->gid2group)(up, pw.pw_gid);
136 u->ngroups = 0;
137 u->groups = NULL;
138 sp_init_user_groups(u);
140 n = u->uid % usercache.hsize;
141 u->next = usercache.htable[n];
142 usercache.htable[n] = u;
144 free(buf);
146 done:
147 sp_user_incref(u);
148 return u;
151 static Spuser *
152 sp_unix_uid2user(Spuserpool *up, u32 uid)
154 int n, i;
155 Spuser *u;
156 struct passwd pw, *pwp;
157 int bufsize;
158 char *buf;
160 if (!usercache.init)
161 initusercache();
163 n = uid % usercache.hsize;
164 for(u = usercache.htable[n]; u != NULL; u = u->next)
165 if (u->uid == uid)
166 goto done;
168 bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
169 if (bufsize < 256)
170 bufsize = 256;
172 buf = sp_malloc(bufsize);
173 if (!buf)
174 return NULL;
176 i = getpwuid_r(uid, &pw, buf, bufsize, &pwp);
177 if (i) {
178 sp_uerror(i);
179 free(buf);
180 return NULL;
183 u = sp_malloc(sizeof(*u) + strlen(pw.pw_name) + 1);
184 if (!u) {
185 free(buf);
186 return NULL;
189 u->refcount = 1;
190 u->upool = up;
191 u->uid = uid;
192 u->uname = (char *)u + sizeof(*u);
193 strcpy(u->uname, pw.pw_name);
194 u->dfltgroup = up->gid2group(up, pw.pw_gid);
196 u->ngroups = 0;
197 u->groups = NULL;
198 sp_init_user_groups(u);
200 u->next = usercache.htable[n];
201 usercache.htable[n] = u;
203 free(buf);
205 done:
206 sp_user_incref(u);
207 return u;
210 static Spgroup *
211 sp_unix_gname2group(Spuserpool *up, char *gname)
213 int i, n, bufsize;
214 Spgroup *g;
215 struct group grp, *pgrp;
216 char *buf;
218 if (!groupcache.init)
219 initgroupcache();
221 for(i = 0; i < groupcache.hsize; i++)
222 for(g = groupcache.htable[i]; g != NULL; g = g->next)
223 if (strcmp(g->gname, gname) == 0)
224 goto done;
226 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
227 if (bufsize < 256)
228 bufsize = 256;
230 buf = sp_malloc(bufsize);
231 if (!buf)
232 return NULL;
234 i = getgrnam_r(gname, &grp, buf, bufsize, &pgrp);
235 if (i) {
236 sp_uerror(i);
237 free(buf);
238 return NULL;
241 g = sp_malloc(sizeof(*g) + strlen(grp.gr_name) + 1);
242 if (!g) {
243 free(buf);
244 return NULL;
247 g->refcount = 1;
248 g->upool = up;
249 g->gid = grp.gr_gid;
250 g->gname = (char *)g + sizeof(*g);
251 strcpy(g->gname, grp.gr_name);
253 n = g->gid % groupcache.hsize;
254 g->next = groupcache.htable[n];
255 groupcache.htable[n] = g;
257 free(buf);
259 done:
260 sp_group_incref(g);
261 return g;
264 static Spgroup *
265 sp_unix_gid2group(Spuserpool *up, u32 gid)
267 int n, err;
268 Spgroup *g;
269 struct group grp, *pgrp;
270 int bufsize;
271 char *buf;
273 if (!groupcache.init)
274 initgroupcache();
276 n = gid % groupcache.hsize;
277 for(g = groupcache.htable[n]; g != NULL; g = g->next)
278 if (g->gid == gid)
279 goto done;
281 bufsize = sysconf(_SC_GETGR_R_SIZE_MAX);
282 if (bufsize < 256)
283 bufsize = 256;
285 buf = sp_malloc(bufsize);
286 if (!buf)
287 return NULL;
289 err = getgrgid_r(gid, &grp, buf, bufsize, &pgrp);
290 if (err) {
291 sp_uerror(err);
292 free(buf);
293 return NULL;
296 g = sp_malloc(sizeof(*g) + strlen(grp.gr_name) + 1);
297 if (!g) {
298 free(buf);
299 return NULL;
302 g->refcount = 1;
303 g->upool = up;
304 g->gid = grp.gr_gid;
305 g->gname = (char *)g + sizeof(*g);
306 strcpy(g->gname, grp.gr_name);
308 g->next = groupcache.htable[n];
309 groupcache.htable[n] = g;
311 free(buf);
313 done:
314 sp_group_incref(g);
315 return g;
318 static int
319 sp_unix_ismember(Spuserpool *up, Spuser *u, Spgroup *g)
321 int i;
323 if (!u->groups && sp_init_user_groups(u)<0)
324 return -1;
326 for(i = 0; i < u->ngroups; i++) {
327 if (g == u->groups[i])
328 return 1;
331 return 0;
334 static void
335 sp_unix_udestroy(Spuserpool *up, Spuser *u)
339 static void
340 sp_unix_gdestroy(Spuserpool *up, Spgroup *g)
344 static int
345 sp_init_user_groups(Spuser *u)
347 int i, n=0;
348 int maxgroups = 256; /* warning: configurable in kernel */
349 Spgroup **grps;
350 struct group *g;
351 gid_t gids[maxgroups];
353 free(u->groups);
354 u->ngroups = 0;
356 setgrent();
358 if(u->dfltgroup) {
359 gids[0] = u->dfltgroup->gid;
360 n++;
363 while ((g = getgrent()) != NULL) {
364 for (i = 0; g->gr_mem[i]; i++) {
365 if (strcmp(u->uname, g->gr_mem[0]) == 0) {
366 n++;
367 if(n < maxgroups)
368 gids[n] = g->gr_gid;
373 endgrent();
375 grps = sp_malloc(sizeof(*grps) * n);
376 if (!grps) {
377 free(gids);
378 return -1;
381 for(i = 0; i < n; i++) {
382 grps[i] = u->upool->gid2group(u->upool, gids[i]);
383 if (grps[i]) {
384 free(grps);
385 return -1;
389 u->groups = grps;
390 u->ngroups = n;
391 return 0;