Ejemplo n.º 1
0
static void gain_root(void)
{
	if (non_root_mode()) {
		return;
	}

	if (geteuid() != 0) {
		set_effective_uid(0);

		if (geteuid() != 0) {
			DEBUG(0,
			      ("Warning: You appear to have a trapdoor "
			       "uid system\n"));
		}
	}

	if (getegid() != 0) {
		set_effective_gid(0);

		if (getegid() != 0) {
			DEBUG(0,
			      ("Warning: You appear to have a trapdoor "
			       "gid system\n"));
		}
	}
}
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 */
}
Ejemplo n.º 3
0
/****************************************************************************
abort if we haven't set the uid correctly
****************************************************************************/
static void assert_uid(uid_t ruid, uid_t euid)
{
	if ((euid != (uid_t)-1 && geteuid() != euid) ||
	    (ruid != (uid_t)-1 && getuid() != ruid)) {
		if (!non_root_mode()) {
			DEBUG(0,("Failed to set uid privileges to (%d,%d) now set to (%d,%d)\n",
				 (int)ruid, (int)euid,
				 (int)getuid(), (int)geteuid()));
			smb_panic("failed to set uid\n");
			exit(1);
		}
	}
}
static void set_unix_security_ctx(uid_t uid, gid_t gid, int ngroups, gid_t *groups)
{
	int max = groups_max();

	/* Start context switch */
	gain_root();

	become_gid(gid);


	if (syscall(SYS_initgroups, (ngroups > max) ? max : ngroups,
			groups, uid) == -1 && !non_root_mode()) {
		DEBUG(0, ("WARNING: failed to set group list "
			"(%d groups) for UID %d: %s\n",
			ngroups, uid, strerror(errno)));
		smb_panic("sys_setgroups failed");
	}

	become_uid(uid);
	/* end context switch */
}
Ejemplo n.º 5
0
BOOL initialise_groups(char *user, uid_t uid, gid_t gid)
{
	struct sec_ctx *prev_ctx_p;
	BOOL result = True;

	if (non_root_mode()) {
		return True;
	}

	become_root();

	/* Call initgroups() to get user groups */

	if (winbind_initgroups(user,gid) == -1) {
		DEBUG(0,("Unable to initgroups. Error was %s\n", strerror(errno) ));
		if (getuid() == 0) {
			if (gid < 0 || gid > 32767 || uid < 0 || uid > 32767) {
				DEBUG(0,("This is probably a problem with the account %s\n", user));
			}
		}
		result = False;
		goto done;
	}

	/* Store groups in previous user's security context.  This will
	   always work as the become_root() call increments the stack
	   pointer. */

	prev_ctx_p = &sec_ctx_stack[sec_ctx_stack_ndx - 1];

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

	get_current_groups(gid, &prev_ctx_p->ngroups, &prev_ctx_p->groups);

 done:
	unbecome_root();

	return result;
}
Ejemplo n.º 6
0
connection_struct *make_connection(struct smbd_server_connection *sconn,
				   const char *service_in, DATA_BLOB password,
				   const char *pdev, uint16 vuid,
				   NTSTATUS *status)
{
	uid_t euid;
	user_struct *vuser = NULL;
	fstring service;
	fstring dev;
	int snum = -1;
	char addr[INET6_ADDRSTRLEN];

	fstrcpy(dev, pdev);

	/* This must ONLY BE CALLED AS ROOT. As it exits this function as
	 * root. */
	if (!non_root_mode() && (euid = geteuid()) != 0) {
		DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
			 "(%u)\n", (unsigned int)euid ));
		smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
	}

	if (conn_num_open(sconn) > 2047) {
		*status = NT_STATUS_INSUFF_SERVER_RESOURCES;
		return NULL;
	}

	if(lp_security() != SEC_SHARE) {
		vuser = get_valid_user_struct(sconn, vuid);
		if (!vuser) {
			DEBUG(1,("make_connection: refusing to connect with "
				 "no session setup\n"));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}
	}

	/* Logic to try and connect to the correct [homes] share, preferably
	   without too many getpwnam() lookups.  This is particulary nasty for
	   winbind usernames, where the share name isn't the same as unix
	   username.

	   The snum of the homes share is stored on the vuser at session setup
	   time.
	*/

	if (strequal(service_in,HOMES_NAME)) {
		if(lp_security() != SEC_SHARE) {
			DATA_BLOB no_pw = data_blob_null;
			if (vuser->homes_snum == -1) {
				DEBUG(2, ("[homes] share not available for "
					  "this user because it was not found "
					  "or created at session setup "
					  "time\n"));
				*status = NT_STATUS_BAD_NETWORK_NAME;
				return NULL;
			}
			DEBUG(5, ("making a connection to [homes] service "
				  "created at session setup time\n"));
			return make_connection_snum(sconn,
						    vuser->homes_snum,
						    vuser, no_pw, 
						    dev, status);
		} else {
			/* Security = share. Try with
			 * current_user_info.smb_name as the username.  */
			if (*current_user_info.smb_name) {
				fstring unix_username;
				fstrcpy(unix_username,
					current_user_info.smb_name);
				map_username(sconn, unix_username);
				snum = find_service(unix_username);
			} 
			if (snum != -1) {
				DEBUG(5, ("making a connection to 'homes' "
					  "service %s based on "
					  "security=share\n", service_in));
				return make_connection_snum(sconn,
							    snum, NULL,
							    password,
							    dev, status);
			}
		}
	} else if ((lp_security() != SEC_SHARE) && (vuser->homes_snum != -1)
		   && strequal(service_in,
			       lp_servicename(vuser->homes_snum))) {
		DATA_BLOB no_pw = data_blob_null;
		DEBUG(5, ("making a connection to 'homes' service [%s] "
			  "created at session setup time\n", service_in));
		return make_connection_snum(sconn,
					    vuser->homes_snum,
					    vuser, no_pw, 
					    dev, status);
	}
	
	fstrcpy(service, service_in);

	strlower_m(service);

	snum = find_service(service);

	if (snum < 0) {
		if (strequal(service,"IPC$") ||
		    (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
			DEBUG(3,("refusing IPC connection to %s\n", service));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}

		DEBUG(3,("%s (%s) couldn't find service %s\n",
			get_remote_machine_name(),
			client_addr(get_client_fd(),addr,sizeof(addr)),
			service));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/* Handle non-Dfs clients attempting connections to msdfs proxy */
	if (lp_host_msdfs() && (*lp_msdfs_proxy(snum) != '\0'))  {
		DEBUG(3, ("refusing connection to dfs proxy share '%s' "
			  "(pointing to %s)\n", 
			service, lp_msdfs_proxy(snum)));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	DEBUG(5, ("making a connection to 'normal' service %s\n", service));

	return make_connection_snum(sconn, snum, vuser,
				    password,
				    dev, status);
}
Ejemplo n.º 7
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;
}
Ejemplo n.º 8
0
connection_struct *make_connection(struct smb_request *req,
				   NTTIME now,
				   const char *service_in,
				   const char *pdev, uint64_t vuid,
				   NTSTATUS *status)
{
	struct smbd_server_connection *sconn = req->sconn;
	uid_t euid;
	struct user_struct *vuser = NULL;
	char *service = NULL;
	fstring dev;
	int snum = -1;

	fstrcpy(dev, pdev);

	/* This must ONLY BE CALLED AS ROOT. As it exits this function as
	 * root. */
	if (!non_root_mode() && (euid = geteuid()) != 0) {
		DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot "
			 "(%u)\n", (unsigned int)euid ));
		smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
	}

	if (conn_num_open(sconn) > 2047) {
		*status = NT_STATUS_INSUFF_SERVER_RESOURCES;
		return NULL;
	}

	vuser = get_valid_user_struct(sconn, vuid);
	if (!vuser) {
		DEBUG(1,("make_connection: refusing to connect with "
			 "no session setup\n"));
		*status = NT_STATUS_ACCESS_DENIED;
		return NULL;
	}

	/* Logic to try and connect to the correct [homes] share, preferably
	   without too many getpwnam() lookups.  This is particulary nasty for
	   winbind usernames, where the share name isn't the same as unix
	   username.

	   The snum of the homes share is stored on the vuser at session setup
	   time.
	*/

	if (strequal(service_in,HOMES_NAME)) {
		if (vuser->homes_snum == -1) {
			DEBUG(2, ("[homes] share not available for "
				  "this user because it was not found "
				  "or created at session setup "
				  "time\n"));
			*status = NT_STATUS_BAD_NETWORK_NAME;
			return NULL;
		}
		DEBUG(5, ("making a connection to [homes] service "
			  "created at session setup time\n"));
		return make_connection_smb1(req, now,
					    vuser->homes_snum,
					    vuser,
					    dev, status);
	} else if ((vuser->homes_snum != -1)
		   && strequal(service_in,
			       lp_servicename(talloc_tos(), vuser->homes_snum))) {
		DEBUG(5, ("making a connection to 'homes' service [%s] "
			  "created at session setup time\n", service_in));
		return make_connection_smb1(req, now,
					    vuser->homes_snum,
					    vuser,
					    dev, status);
	}

	service = talloc_strdup(talloc_tos(), service_in);
	if (!service) {
		*status = NT_STATUS_NO_MEMORY;
		return NULL;
	}

	if (!strlower_m(service)) {
		DEBUG(2, ("strlower_m %s failed\n", service));
		*status = NT_STATUS_INVALID_PARAMETER;
		return NULL;
	}

	snum = find_service(talloc_tos(), service, &service);
	if (!service) {
		*status = NT_STATUS_NO_MEMORY;
		return NULL;
	}

	if (snum < 0) {
		if (strequal(service,"IPC$") ||
		    (lp_enable_asu_support() && strequal(service,"ADMIN$"))) {
			DEBUG(3,("refusing IPC connection to %s\n", service));
			*status = NT_STATUS_ACCESS_DENIED;
			return NULL;
		}

		DEBUG(3,("%s (%s) couldn't find service %s\n",
			get_remote_machine_name(),
			tsocket_address_string(
				sconn->remote_address, talloc_tos()),
			service));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	/* Handle non-Dfs clients attempting connections to msdfs proxy */
	if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), snum) != '\0'))  {
		DEBUG(3, ("refusing connection to dfs proxy share '%s' "
			  "(pointing to %s)\n", 
			service, lp_msdfs_proxy(talloc_tos(), snum)));
		*status = NT_STATUS_BAD_NETWORK_NAME;
		return NULL;
	}

	DEBUG(5, ("making a connection to 'normal' service %s\n", service));

	return make_connection_smb1(req, now, snum, vuser,
				    dev, status);
}