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
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.
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
{
61 static struct Spgroupcache
{
70 if (!usercache
.init
) {
72 usercache
.htable
= calloc(usercache
.hsize
, sizeof(Spuser
*));
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
);
92 sp_unix_uname2user(Spuserpool
*up
, char *uname
)
95 struct passwd pw
, *pwp
;
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)
108 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
112 buf
= sp_malloc(bufsize
);
116 i
= getpwnam_r(uname
, &pw
, buf
, bufsize
, &pwp
);
123 u
= sp_malloc(sizeof(*u
) + strlen(pw
.pw_name
) + 1);
132 u
->uname
= (char *)u
+ sizeof(*u
);
133 strcpy(u
->uname
, pw
.pw_name
);
134 u
->dfltgroup
= (*up
->gid2group
)(up
, pw
.pw_gid
);
138 sp_init_user_groups(u
);
140 n
= u
->uid
% usercache
.hsize
;
141 u
->next
= usercache
.htable
[n
];
142 usercache
.htable
[n
] = u
;
152 sp_unix_uid2user(Spuserpool
*up
, u32 uid
)
156 struct passwd pw
, *pwp
;
163 n
= uid
% usercache
.hsize
;
164 for(u
= usercache
.htable
[n
]; u
!= NULL
; u
= u
->next
)
168 bufsize
= sysconf(_SC_GETPW_R_SIZE_MAX
);
172 buf
= sp_malloc(bufsize
);
176 i
= getpwuid_r(uid
, &pw
, buf
, bufsize
, &pwp
);
183 u
= sp_malloc(sizeof(*u
) + strlen(pw
.pw_name
) + 1);
192 u
->uname
= (char *)u
+ sizeof(*u
);
193 strcpy(u
->uname
, pw
.pw_name
);
194 u
->dfltgroup
= up
->gid2group(up
, pw
.pw_gid
);
198 sp_init_user_groups(u
);
200 u
->next
= usercache
.htable
[n
];
201 usercache
.htable
[n
] = u
;
211 sp_unix_gname2group(Spuserpool
*up
, char *gname
)
215 struct group grp
, *pgrp
;
218 if (!groupcache
.init
)
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)
226 bufsize
= sysconf(_SC_GETGR_R_SIZE_MAX
);
230 buf
= sp_malloc(bufsize
);
234 i
= getgrnam_r(gname
, &grp
, buf
, bufsize
, &pgrp
);
241 g
= sp_malloc(sizeof(*g
) + strlen(grp
.gr_name
) + 1);
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
;
265 sp_unix_gid2group(Spuserpool
*up
, u32 gid
)
269 struct group grp
, *pgrp
;
273 if (!groupcache
.init
)
276 n
= gid
% groupcache
.hsize
;
277 for(g
= groupcache
.htable
[n
]; g
!= NULL
; g
= g
->next
)
281 bufsize
= sysconf(_SC_GETGR_R_SIZE_MAX
);
285 buf
= sp_malloc(bufsize
);
289 err
= getgrgid_r(gid
, &grp
, buf
, bufsize
, &pgrp
);
296 g
= sp_malloc(sizeof(*g
) + strlen(grp
.gr_name
) + 1);
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
;
319 sp_unix_ismember(Spuserpool
*up
, Spuser
*u
, Spgroup
*g
)
323 if (!u
->groups
&& sp_init_user_groups(u
)<0)
326 for(i
= 0; i
< u
->ngroups
; i
++) {
327 if (g
== u
->groups
[i
])
335 sp_unix_udestroy(Spuserpool
*up
, Spuser
*u
)
340 sp_unix_gdestroy(Spuserpool
*up
, Spgroup
*g
)
345 sp_init_user_groups(Spuser
*u
)
348 int maxgroups
= 256; /* warning: configurable in kernel */
351 gid_t gids
[maxgroups
];
359 gids
[0] = u
->dfltgroup
->gid
;
363 while ((g
= getgrent()) != NULL
) {
364 for (i
= 0; g
->gr_mem
[i
]; i
++) {
365 if (strcmp(u
->uname
, g
->gr_mem
[0]) == 0) {
375 grps
= sp_malloc(sizeof(*grps
) * n
);
381 for(i
= 0; i
< n
; i
++) {
382 grps
[i
] = u
->upool
->gid2group(u
->upool
, gids
[i
]);