[patch] samba-3.0.2: sys_getgrouplist_internals(..., gid, groups,
...) returns multiple instances of gid in groups
Buck Huppmann
buckh at pobox.com
Thu Feb 12 01:16:42 GMT 2004
on Solaris 9, anyway
before patch:
[2004/01/23 11:18:18, 5] auth/auth_util.c:debug_unix_user_token(505)
UNIX token of user 40535
Primary group is 118 and contains 4 supplementary groups
Group[ 0]: 118
Group[ 1]: 118
Group[ 2]: 18
Group[ 3]: 70
after:
[2004/02/11 17:55:57, 5] auth/auth_util.c:debug_unix_user_token(505)
UNIX token of user 40535
Primary group is 118 and contains 3 supplementary groups
Group[ 0]: 118
Group[ 1]: 18
Group[ 2]: 70
which is more than a cosmetic problem, if you're in 16 groups, 'cause
then calls to setgroups() fail in set_sec_ctx(), pop_sec_ctx() etc.
(and those functions don't report the error, leaving you scratching
your head when permissions problems bite)
but the patch is included for illustrative purposes only; please
rewrite, especially since this has only been tested on one system
nevertheless, samba 3 is off to a great start. thanks, you all
--buck, maryland, usa
--- samba-3.0.2/source/lib/system_smbd.c.orig Fri Oct 10 14:08:35 2003
+++ samba-3.0.2/source/lib/system_smbd.c Wed Feb 11 17:18:37 2004
@@ -38,7 +38,7 @@
*/
static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
{
- gid_t *gids_saved;
+ gid_t *gids_saved, *groups_tmp;
int ret, ngrp_saved, num_gids;
if (non_root_mode()) {
@@ -79,16 +79,82 @@
setgid(gid);
num_gids = getgroups(0, NULL);
- if (num_gids + 1 > *grpcnt) {
- *grpcnt = num_gids + 1;
- ret = -1;
- } else {
- ret = getgroups(*grpcnt - 1, &groups[1]);
- if (ret >= 0) {
- groups[0] = gid;
- *grpcnt = ret + 1;
+
+ /* see if we can use the buffer in place */
+ if (num_gids <= *grpcnt) {
+ groups_tmp = groups;
+ }
+ /* otherwise, allocate a buffer big enough so we can getgroups()
+ * and see whether or not gid is among them, so we can return the
+ * correct grpcnt (num_gids or num_gids + 1) */
+ else {
+ groups_tmp = (gid_t *)malloc(sizeof(gid_t) * (num_gids));
+ if (!groups_tmp) {
+ errno = ENOMEM;
+ ret = -1;
+ goto restore_gid;
+ }
+ }
+ ret = getgroups(num_gids, groups_tmp);
+ if (ret >= 0) {
+ int i;
+ int saw_gid = False;
+ /* just in case this has changed in the interim; can only
+ * down-size, though */
+ num_gids = ret < num_gids ? ret : num_gids;
+ for (i = 0; i < num_gids; i++) {
+ if (groups_tmp[i] == gid) {
+ saw_gid = True;
+ break;
+ }
}
+ /* if the buffer wasn't big enough and we were just
+ * counting groups, return the number we found we
+ * needed */
+ if (groups_tmp != groups) {
+ if (!saw_gid) {
+ /* one more for the gid arg, since it wasn't
+ * in the list */
+ num_gids++;
+ }
+ /* unlikely: if (num_gids now <= *grpcnt) forge-ahead; */
+ free(groups_tmp);
+ /* cse: *grpcnt = num_gids; is below */
+ ret = -1;
+ }
+ else {
+ if (saw_gid) {
+ if (i != 0) {
+ /* pull gid arg up to front */
+ memmove(&groups[1], &groups[0],
+ sizeof(gid_t) * i);
+ groups[0] = gid;
+ }
+ /* cse: *grpcnt = num_gids; is below */
+ }
+ else {
+ num_gids++;
+ ret++;
+ /* cse: *grpcnt = num_gids; is below */
+ if (num_gids > *grpcnt) {
+ ret = -1;
+ }
+ else {
+ /* avoid 0-length memmove() */
+ if (num_gids > 1) {
+ memmove(&groups[1],
+ &groups[0],
+ sizeof(gid_t)
+ * (num_gids - 1));
+ }
+ groups[0] = gid;
+ }
+ }
+ }
+ *grpcnt = num_gids;
}
+
+restore_gid:
restore_re_gid();
More information about the samba-technical
mailing list