static int gssx_dec_linux_creds(struct xdr_stream *xdr, struct svc_cred *creds) { u32 length; __be32 *p; u32 tmp; u32 N; int i, err; p = xdr_inline_decode(xdr, 4); if (unlikely(p == NULL)) return -ENOSPC; length = be32_to_cpup(p); if (length > (3 + NGROUPS_MAX) * sizeof(u32)) return -ENOSPC; /* uid */ err = get_host_u32(xdr, &tmp); if (err) return err; creds->cr_uid = make_kuid(&init_user_ns, tmp); /* gid */ err = get_host_u32(xdr, &tmp); if (err) return err; creds->cr_gid = make_kgid(&init_user_ns, tmp); /* number of additional gid's */ err = get_host_u32(xdr, &tmp); if (err) return err; N = tmp; if ((3 + N) * sizeof(u32) != length) return -EINVAL; creds->cr_group_info = groups_alloc(N); if (creds->cr_group_info == NULL) return -ENOMEM; /* gid's */ for (i = 0; i < N; i++) { kgid_t kgid; err = get_host_u32(xdr, &tmp); if (err) goto out_free_groups; err = -EINVAL; kgid = make_kgid(&init_user_ns, tmp); if (!gid_valid(kgid)) goto out_free_groups; creds->cr_group_info->gid[i] = kgid; } groups_sort(creds->cr_group_info); return 0; out_free_groups: groups_free(creds->cr_group_info); return err; }
/* validate and set current->group_info */ int set_current_groups(struct group_info *group_info) { int retval; struct group_info *old_info; retval = security_task_setgroups(group_info); if (retval) return retval; groups_sort(group_info); get_group_info(group_info); task_lock(current); old_info = current->group_info; current->group_info = group_info; task_unlock(current); put_group_info(old_info); return 0; }