Esempio n. 1
0
void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
{
	struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
	
	/* Set the security context */

	DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
		(unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));

	debug_nt_user_token(DBGC_CLASS, 5, token);
	debug_unix_user_token(DBGC_CLASS, 5, uid, gid, ngroups, groups);

	gain_root();

#ifdef HAVE_SETGROUPS
	sys_setgroups(ngroups, groups);
#endif

	ctx_p->ut.ngroups = ngroups;

	SAFE_FREE(ctx_p->ut.groups);
	if (token && (token == ctx_p->token)) {
		smb_panic("DUPLICATE_TOKEN");
	}

	TALLOC_FREE(ctx_p->token);
	
	if (ngroups) {
		ctx_p->ut.groups = (gid_t *)memdup(groups,
						   sizeof(gid_t) * ngroups);
		if (!ctx_p->ut.groups) {
			smb_panic("memdup failed");
		}
	} else {
		ctx_p->ut.groups = NULL;
	}

	if (token) {
		ctx_p->token = dup_nt_token(NULL, token);
		if (!ctx_p->token) {
			smb_panic("dup_nt_token failed");
		}
	} else {
		ctx_p->token = NULL;
	}

	become_id(uid, gid);

	ctx_p->ut.uid = uid;
	ctx_p->ut.gid = gid;

	/* Update current_user stuff */

	current_user.ut.uid = uid;
	current_user.ut.gid = gid;
	current_user.ut.ngroups = ngroups;
	current_user.ut.groups = groups;
	current_user.nt_user_token = ctx_p->token;
}
static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
{
	/* Start context switch */
	gain_root();
#ifdef HAVE_SETGROUPS
	if (sys_setgroups(gid, ngroups, groups) != 0 && !non_root_mode()) {
		smb_panic("sys_setgroups failed");
	}
#endif
	become_id(uid, gid);
	/* end context switch */
}
Esempio n. 3
0
BOOL pop_sec_ctx(void)
{
	struct sec_ctx *ctx_p;
	struct sec_ctx *prev_ctx_p;

	/* Check for stack underflow */

	if (sec_ctx_stack_ndx == 0) {
		DEBUG(0, ("Security context stack underflow!\n"));
		smb_panic("Security context stack underflow!\n");
	}

	ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];

	/* Clear previous user info */

	ctx_p->uid = (uid_t)-1;
	ctx_p->gid = (gid_t)-1;

	SAFE_FREE(ctx_p->groups);
	ctx_p->ngroups = 0;

	delete_nt_token(&ctx_p->token);

	/* Pop back previous user */

	sec_ctx_stack_ndx--;

	gain_root();

	prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];

#ifdef HAVE_SETGROUPS
	sys_setgroups(prev_ctx_p->ngroups, prev_ctx_p->groups);
#endif

	become_id(prev_ctx_p->uid, prev_ctx_p->gid);

	/* Update current_user stuff */

	current_user.uid = prev_ctx_p->uid;
	current_user.gid = prev_ctx_p->gid;
	current_user.ngroups = prev_ctx_p->ngroups;
	current_user.groups = prev_ctx_p->groups;
	current_user.nt_user_token = prev_ctx_p->token;

	DEBUG(3, ("pop_sec_ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
		(unsigned int)geteuid(), (unsigned int)getegid(), sec_ctx_stack_ndx));

	return True;
}
Esempio n. 4
0
void set_sec_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups, NT_USER_TOKEN *token)
{
	struct sec_ctx *ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx];
	
	/* Set the security context */

	DEBUG(3, ("setting sec ctx (%u, %u) - sec_ctx_stack_ndx = %d\n", 
		(unsigned int)uid, (unsigned int)gid, sec_ctx_stack_ndx));

	if (ngroups) {
		int i;

		DEBUG(3, ("%d user groups: \n", ngroups));
		for (i = 0; i < ngroups; i++) {
			DEBUGADD(3, ("%u ", (unsigned int)groups[i]));
		}

		DEBUG(3, ("\n"));
	}
	

	gain_root();

#ifdef HAVE_SETGROUPS
	sys_setgroups(ngroups, groups);
#endif

	ctx_p->ngroups = ngroups;

	SAFE_FREE(ctx_p->groups);
	if (token && (token == ctx_p->token))
		smb_panic("DUPLICATE_TOKEN");

	delete_nt_token(&ctx_p->token);
	
	ctx_p->groups = memdup(groups, sizeof(gid_t) * ngroups);
	ctx_p->token = dup_nt_token(token);

	become_id(uid, gid);

	ctx_p->uid = uid;
	ctx_p->gid = gid;

	/* Update current_user stuff */

	current_user.uid = uid;
	current_user.gid = gid;
	current_user.ngroups = ngroups;
	current_user.groups = groups;
	current_user.nt_user_token = ctx_p->token;
}
Esempio n. 5
0
/****************************************************************************
 some systems don't have an initgroups call 
****************************************************************************/
 int initgroups(char *name,gid_t id)
{
#ifndef HAVE_SETGROUPS
	static int done;
	if (!done) {
		DEBUG(1,("WARNING: running without setgroups\n"));
		done=1;
	}
	/* yikes! no SETGROUPS or INITGROUPS? how can this work? */
	return(0);
#else /* HAVE_SETGROUPS */
	gid_t *grouplst = NULL;
	int max_gr = groups_max();
	int ret;
	int    i,j;
	struct group *g;
	char   *gr;
	
	if((grouplst = SMB_MALLOC_ARRAY(gid_t, max_gr)) == NULL) {
		DEBUG(0,("initgroups: malloc fail !\n"));
		return -1;
	}

	grouplst[0] = id;
	i = 1;
	while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) {
		if (g->gr_gid == id)
			continue;
		j = 0;
		gr = g->gr_mem[0];
		while (gr && (*gr != (char)NULL)) {
			if (strcmp(name,gr) == 0) {
				grouplst[i] = g->gr_gid;
				i++;
				gr = (char *)NULL;
				break;
			}
			gr = g->gr_mem[++j];
		}
	}
	endgrent();
	ret = sys_setgroups(i,grouplst);
	SAFE_FREE(grouplst);
	return ret;
#endif /* HAVE_SETGROUPS */
}
Esempio n. 6
0
/*
  This is a *much* faster way of getting the list of groups for a user
  without changing the current supplemenrary group list. The old
  method used getgrent() which could take 20 minutes on a really big
  network with hundeds of thousands of groups and users. The new method
  takes a couple of seconds.

  NOTE!! this function only works if it is called as root!
  */
static int getgrouplist_internals(const char *user, gid_t gid, gid_t *groups, int *grpcnt)
{
	gid_t *gids_saved;
	int ret, ngrp_saved, num_gids;

	if (non_root_mode()) {
		*grpcnt = 0;
		return 0;
	}

	/* work out how many groups we need to save */
	ngrp_saved = getgroups(0, NULL);
	if (ngrp_saved == -1) {
		/* this shouldn't happen */
		return -1;
	}
	
	gids_saved = (gid_t *)malloc(sizeof(gid_t) * (ngrp_saved+1));
	if (!gids_saved) {
		errno = ENOMEM;
		return -1;
	}

	ngrp_saved = getgroups(ngrp_saved, gids_saved);
	if (ngrp_saved == -1) {
		SAFE_FREE(gids_saved);
		/* very strange! */
		return -1;
	}

	if (initgroups(user, gid) != 0) {
		DEBUG(0, ("getgrouplist_internals: initgroups() failed!\n"));
		SAFE_FREE(gids_saved);
		return -1;
	}

	/* this must be done to cope with systems that put the current egid in the
	   return from getgroups() */
	save_re_gid();
	set_effective_gid(gid);
	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;
		}
	}

	restore_re_gid();

	if (sys_setgroups(ngrp_saved, gids_saved) != 0) {
		/* yikes! */
		DEBUG(0,("ERROR: getgrouplist: failed to reset group list!\n"));
		smb_panic("getgrouplist: failed to reset group list!\n");
		free(gids_saved);
		return -1;
	}
	
	/* this will remove any duplicates gids in the list and 
	   update the group counter */
	   
	remove_duplicate_gids( grpcnt, groups );

	free(gids_saved);
	return ret;
}
Esempio n. 7
0
int ckpt_restore_cred(ckpt_desc_t desc)
{
    int ret = 0;
    ckpt_cred_t cred;
    gid_t *groups = NULL;
    const struct cred *curr_cred = current->cred;

    log_restore_cred("restoring cred ...");
    if (ckpt_read(desc, &cred, sizeof(ckpt_cred_t)) != sizeof(ckpt_cred_t)) {
        log_err("failed to get cred");
        return -EIO;
    }

    if (cred.ngroups > NGROUPS_MAX) {
        log_err("ngroups (%d) > NGROUPS_MAX", cred.ngroups);
        return -EINVAL;
    }

    if (cred.ngroups > 0) {
        int i;
        size_t size = cred.ngroups * sizeof(gid_t);
        struct group_info *gi = curr_cred->group_info;

        groups = vmalloc(size);
        if (!groups) {
            log_err("no memory");
            return -ENOMEM;
        }

        if (ckpt_read(desc, groups, size) != size) {
            log_err("failed to get groups");
            ret = -EIO;
            goto out;
        }

        for (i = 0; i < cred.ngroups; i++) {
            if (!groups_search(gi, groups[i])) {
                mm_segment_t fs = get_fs();
                set_fs(KERNEL_DS);
                ret = sys_setgroups(cred.ngroups, groups);
                set_fs(fs);
                if (ret < 0) {
                    log_err("failed to set groups");
                    goto out;
                }
                break;
            }
        }
    }

    current->gpid = cred.gpid;
    ret = sys_setresgid(cred.gid, cred.egid, cred.sgid);
    if (ret < 0) {
        log_err("failed to restore gid");
        goto out;
    }

    ret = sys_setresuid(cred.uid, cred.euid, cred.suid);
    if (ret < 0) {
        log_err("failed to restore uid");
        goto out;
    }

    if ((curr_cred->euid == curr_cred->uid) && (curr_cred->egid == curr_cred->gid))
        set_dumpable(current->mm, 1);
    else
        set_dumpable(current->mm, *compat_suid_dumpable);
    log_restore_pos(desc);
out:
    if (groups)
        vfree(groups);
    return ret;
}
Esempio n. 8
0
int winbind_initgroups(char *user, gid_t gid)
{
	gid_t *tgr, *groups = NULL;
	int result;

	/* Call normal initgroups if we are a local user */

	if (!strchr(user, *lp_winbind_separator())) {
		return initgroups(user, gid);
	}

	result = wb_getgroups(user, &groups);

	DEBUG(10,("winbind_getgroups: %s: result = %s\n", user, 
		  result == -1 ? "FAIL" : "SUCCESS"));

	if (result != -1) {
		int ngroups = result, i;
		BOOL is_member = False;

		/* Check to see if the passed gid is already in the list */

		for (i = 0; i < ngroups; i++) {
			if (groups[i] == gid) {
				is_member = True;
			}
		}

		/* Add group to list if necessary */

		if (!is_member) {
			tgr = (gid_t *)Realloc(groups, sizeof(gid_t) * ngroups + 1);
			
			if (!tgr) {
				errno = ENOMEM;
				result = -1;
				goto done;
			}
			else groups = tgr;

			groups[ngroups] = gid;
			ngroups++;
		}

		/* Set the groups */

		if (sys_setgroups(ngroups, groups) == -1) {
			errno = EPERM;
			result = -1;
			goto done;
		}

	} else {
		
		/* The call failed.  Set errno to something so we don't get
		   a bogus value from the last failed system call. */

		errno = EIO;
	}

	/* Free response data if necessary */

 done:
	SAFE_FREE(groups);

	return result;
}
/* Note: it is necessary to treat gidsetsize as an unsigned int,
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
asmlinkage long compat_sys_setgroups(u32 gidsetsize, gid_t __user *grouplist)
{
	return sys_setgroups((int)gidsetsize, grouplist);
}
Esempio n. 10
0
int cr_load_creds(cr_rstrt_proc_req_t *proc_req)
{
    cr_errbuf_t *eb = proc_req->req->errbuf;
    struct cr_context_creds cf_creds;
    int retval;
    gid_t *groups = NULL;

    CR_KTRACE_HIGH_LVL("%d: Restoring credentials", current->pid);

    retval = cr_kread(eb, proc_req->file, &cf_creds, sizeof(cf_creds));
    if (retval < sizeof(cf_creds)) {
	CR_ERR_PROC_REQ(proc_req, "credentials: read returned %d", retval);
        goto out;
    }
     
    if (cf_creds.ngroups > CR_NGROUPS_MAX) {
	CR_ERR_PROC_REQ(proc_req, "Invalid supplemental group count (%d)", (int)cf_creds.ngroups);
	retval = -EINVAL;
	goto out;
    } else if (cf_creds.ngroups) {
	size_t sizeof_groups = cf_creds.ngroups*sizeof(gid_t);
	groups = vmalloc(sizeof_groups);
	retval = -ENOMEM;
	if (groups == NULL) {
	    goto out;
	}

	retval = cr_kread(eb, proc_req->file, groups, sizeof_groups);
	if (retval < sizeof_groups) {
	    CR_ERR_PROC_REQ(proc_req, "groups: read returned %d", retval);
            goto out_vfree;
        }
    }

#if CR_RESTORE_IDS
    if (cf_creds.ngroups) {
      #if CR_HAVE_GROUP_INFO || defined(CR_KCODE_groups_search) || !defined(CR_KCODE_supplemental_group_member)
	cr_group_info_t gi = cr_current_groups();
      #endif
	int i;
	/* Search for any required "expansion" of the group set */
	for (i = 0; i < cf_creds.ngroups; ++i) {
	    gid_t g = groups[i];
	    int gid_ok = 0; /* Assume no match for this gid */

    #if defined(CR_KCODE_groups_search)
	    gid_ok = groups_search((struct group_info *)gi, g); // search is const, but not declared as such
    #elif defined(CR_KCODE_supplemental_group_member)
	    gid_ok = supplemental_group_member(g);
    #else
	    /* Just in case groups_search() or supplemental_group_member()
	     * is not found (each was static in some kernels) */
	    int j;
	    for (j = 0; j < gi->ngroups; ++j) {
                if (g == CR_GROUP_AT(gi, j)) {
		    gid_ok = 1; /* OK, g is in the existing set */
		    break;
		}
	    }
    #endif

	    if (!gid_ok) {
	        /* If we reach here then we've seen a supplemental group in the
	         * saved context, which is not present in the current list.
		 * The set_groups() call checks permissions for us.  If we fail,
		 * then we must not have enough credentials.
		 */
		mm_segment_t oldfs = get_fs();
		set_fs(KERNEL_DS);
		retval = sys_setgroups(cf_creds.ngroups, groups);
		set_fs(oldfs);
		if (retval < 0) {
		    CR_ERR_PROC_REQ(proc_req, "Failed to restore supplemental group(s).");
		    goto out_vfree;
		}
		CR_KTRACE_LOW_LVL("Restored %d supplemental group(s)", cf_creds.ngroups);
		break; /* no need to continue the i loop */
	    }
	}
  #if CR_HAVE_GROUP_INFO
	(void)cr_insert_object(proc_req->req->map, (void *)cf_creds.group_info, (void *)gi, GFP_KERNEL);
  #endif
    }
  #if CR_HAVE_GROUP_INFO
    else {
	// NOTE: requires restore order match save order
	struct group_info *found_group_info = NULL;

	if (!cr_find_object(proc_req->req->map, (void *)cf_creds.group_info, (void **)&found_group_info)) {
	   // Nothing to do
	} else if (found_group_info != cr_current_groups()) {
	    // validation and sort were done previously, but are not worth avoiding
	    set_current_groups(found_group_info);
	    CR_KTRACE_LOW_LVL("Reuse cached group_info %p", found_group_info);
	} else {
	    CR_KTRACE_LOW_LVL("Cached group_info == current");
	}
    }
  #endif

    {
	cr_cred_t my_cred = cr_current_cred();

	/* The set_setresgid() call checks permissions for us, always OK if no change . */
	retval = sys_setresgid(cf_creds.gid, cf_creds.egid, cf_creds.sgid);
	if (retval < 0) {
	    CR_ERR_PROC_REQ(proc_req, "Failed to restore real/effective/saved gids.");
	    goto out_vfree;
	}
	CR_KTRACE_LOW_LVL("Restored gids");

	/* The set_setresuid() call checks permissions for us, always OK if no change . */
	retval = sys_setresuid(cf_creds.uid, cf_creds.euid, cf_creds.suid);
	if (retval < 0) {
	    CR_ERR_PROC_REQ(proc_req, "Failed to restore real/effective/saved uids.");
	    goto out_vfree;
	}
	CR_KTRACE_LOW_LVL("Restored uids");

        /* 
	 * sys_setresuid sets current->mm->dumpable to suid_dumpable if the
	 * call was successful.  This can have some weird side-effects on
	 * restarted jobs, like /proc/self/fd will not be accessable.  
         *
	 * We should probably save this flag and restore it if we ever
	 * support real setuid checkpoints from the user, but for now we'll
	 * just set the flag to 1 if the user had permission to restore their
	 * credentials in the first place.  This should mimic the behavior
         * of exec.
         *
         * Set the dumpable flag for the process, taken from 2.6.22 fs/exec.c
         */
        if (my_cred->euid == my_cred->uid && my_cred->egid == my_cred->gid) {
            cr_set_dumpable(current->mm, 1);
        } else {
            cr_set_dumpable(current->mm, cr_suid_dumpable);
        }
    }
#endif	 /* CR_RESTORE_IDS */

out_vfree:
    vfree(groups);

out:
    return retval;
}