Exemplo n.º 1
0
static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
					connection_struct *conn,
					int snum, struct user_struct *vuser,
					const char *pdev)
{
	struct smbd_server_connection *sconn = xconn->client->sconn;
	struct smb_filename *smb_fname_cpath = NULL;
	fstring dev;
	int ret;
	bool on_err_call_dis_hook = false;
	uid_t effuid;
	gid_t effgid;
	NTSTATUS status;

	fstrcpy(dev, pdev);

	status = share_sanity_checks(sconn->remote_address,
				       sconn->remote_hostname,
				       snum,
				       dev);
	if (NT_STATUS_IS_ERR(status)) {
		goto err_root_exit;
	}

	conn->params->service = snum;

	status = create_connection_session_info(sconn,
		conn, snum, vuser->session_info,
		&conn->session_info);

	if (!NT_STATUS_IS_OK(status)) {
		DEBUG(1, ("create_connection_session_info failed: %s\n",
			  nt_errstr(status)));
		goto err_root_exit;
	}

	if (lp_guest_only(snum)) {
		conn->force_user = true;
	}

	conn->num_files_open = 0;
	conn->lastused = conn->lastused_count = time(NULL);
	conn->printer = (strncmp(dev,"LPT",3) == 0);
	conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
		      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );

	/* Case options for the share. */
	if (lp_case_sensitive(snum) == Auto) {
		/* We will be setting this per packet. Set to be case
		 * insensitive for now. */
		conn->case_sensitive = False;
	} else {
		conn->case_sensitive = (bool)lp_case_sensitive(snum);
	}

	conn->case_preserve = lp_preserve_case(snum);
	conn->short_case_preserve = lp_short_preserve_case(snum);

	conn->encrypt_level = lp_smb_encrypt(snum);

	conn->veto_list = NULL;
	conn->hide_list = NULL;
	conn->veto_oplock_list = NULL;
	conn->aio_write_behind_list = NULL;

	conn->read_only = lp_read_only(SNUM(conn));

	status = set_conn_force_user_group(conn, snum);
	if (!NT_STATUS_IS_OK(status)) {
		goto err_root_exit;
	}

	conn->vuid = vuser->vuid;

	{
		char *s = talloc_sub_advanced(talloc_tos(),
					lp_servicename(talloc_tos(), SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_path(talloc_tos(), snum));
		if (!s) {
			status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}

		if (!set_conn_connectpath(conn,s)) {
			TALLOC_FREE(s);
			status = NT_STATUS_NO_MEMORY;
			goto err_root_exit;
		}
		DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
			 lp_servicename(talloc_tos(), snum)));
		TALLOC_FREE(s);
	}

	/*
	 * Set up the share security descriptor.
	 * NOTE - we use the *INCOMING USER* session_info
	 * here, as does (indirectly) change_to_user(),
	 * which can be called on any incoming packet.
	 * This way we set up the share access based
	 * on the authenticated user, not the forced
	 * user. See bug:
	 *
	 * https://bugzilla.samba.org/show_bug.cgi?id=9878
	 */

	status = check_user_share_access(conn,
					vuser->session_info,
					&conn->share_access,
					&conn->read_only);
	if (!NT_STATUS_IS_OK(status)) {
		goto err_root_exit;
	}

	/* Initialise VFS function pointers */

	if (!smbd_vfs_init(conn)) {
		DEBUG(0, ("vfs_init failed for service %s\n",
			  lp_servicename(talloc_tos(), snum)));
		status = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}

/* ROOT Activities: */
	/* explicitly check widelinks here so that we can correctly warn
	 * in the logs. */
	widelinks_warning(snum);

	/*
	 * Enforce the max connections parameter.
	 */

	if ((lp_max_connections(snum) > 0)
	    && (count_current_connections(lp_servicename(talloc_tos(), SNUM(conn)), True) >=
		lp_max_connections(snum))) {

		DEBUG(1, ("Max connections (%d) exceeded for %s\n",
			  lp_max_connections(snum),
			  lp_servicename(talloc_tos(), snum)));
		status = NT_STATUS_INSUFFICIENT_RESOURCES;
		goto err_root_exit;
	}

	/* Invoke VFS make connection hook - this must be the first
	   filesystem operation that we do. */

	if (SMB_VFS_CONNECT(conn, lp_servicename(talloc_tos(), snum),
			    conn->session_info->unix_info->unix_name) < 0) {
		DBG_WARNING("SMB_VFS_CONNECT for service '%s' at '%s' failed: %s\n",
			    lp_servicename(talloc_tos(), snum), conn->connectpath,
			    strerror(errno));
		status = NT_STATUS_UNSUCCESSFUL;
		goto err_root_exit;
	}

	/* Any error exit after here needs to call the disconnect hook. */
	on_err_call_dis_hook = true;

	if ((!conn->printer) && (!conn->ipc) &&
	    lp_change_notify()) {
		if (sconn->notify_ctx == NULL) {
			sconn->notify_ctx = notify_init(
				sconn, sconn->msg_ctx, sconn->ev_ctx);
			status = messaging_register(
				sconn->msg_ctx, sconn,
				MSG_SMB_NOTIFY_CANCEL_DELETED,
				smbd_notify_cancel_deleted);
		}
		if (sconn->sys_notify_ctx == NULL) {
			sconn->sys_notify_ctx = sys_notify_context_create(
				sconn, sconn->ev_ctx);
		}
	}

	if (lp_kernel_oplocks(snum)) {
		init_kernel_oplocks(conn->sconn);
	}

	/*
	 * Fix compatibility issue pointed out by Volker.
	 * We pass the conn->connectpath to the preexec
	 * scripts as a parameter, so attempt to canonicalize
	 * it here before calling the preexec scripts.
	 * We ignore errors here, as it is possible that
	 * the conn->connectpath doesn't exist yet and
	 * the preexec scripts will create them.
	 */

	(void)canonicalize_connect_path(conn);

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */
	/* execute any "root preexec = " line */
	if (*lp_root_preexec(talloc_tos(), snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(talloc_tos(), SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_root_preexec(talloc_tos(), snum));
		DEBUG(5,("cmd=%s\n",cmd));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_root_preexec_close(snum)) {
			DEBUG(1,("root preexec gave %d - failing "
				 "connection\n", ret));
			status = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

/* USER Activites: */
	if (!change_to_user(conn, conn->vuid)) {
		/* No point continuing if they fail the basic checks */
		DEBUG(0,("Can't become connected user!\n"));
		status = NT_STATUS_LOGON_FAILURE;
		goto err_root_exit;
	}

	effuid = geteuid();
	effgid = getegid();

	/* Remember that a different vuid can connect later without these
	 * checks... */

	/* Preexecs are done here as they might make the dir we are to ChDir
	 * to below */

	/* execute any "preexec = " line */
	if (*lp_preexec(talloc_tos(), snum)) {
		char *cmd = talloc_sub_advanced(talloc_tos(),
					lp_servicename(talloc_tos(), SNUM(conn)),
					conn->session_info->unix_info->unix_name,
					conn->connectpath,
					conn->session_info->unix_token->gid,
					conn->session_info->unix_info->sanitized_username,
					conn->session_info->info->domain_name,
					lp_preexec(talloc_tos(), snum));
		ret = smbrun(cmd,NULL);
		TALLOC_FREE(cmd);
		if (ret != 0 && lp_preexec_close(snum)) {
			DEBUG(1,("preexec gave %d - failing connection\n",
				 ret));
			status = NT_STATUS_ACCESS_DENIED;
			goto err_root_exit;
		}
	}

#ifdef WITH_FAKE_KASERVER
	if (lp_afs_share(snum)) {
		afs_login(conn);
	}
#endif

	/*
	 * we've finished with the user stuff - go back to root
	 * so the SMB_VFS_STAT call will only fail on path errors,
	 * not permission problems.
	 */
	change_to_root_user();
/* ROOT Activites: */

	/*
	 * If widelinks are disallowed we need to canonicalise the connect
	 * path here to ensure we don't have any symlinks in the
	 * connectpath. We will be checking all paths on this connection are
	 * below this directory. We must do this after the VFS init as we
	 * depend on the realpath() pointer in the vfs table. JRA.
	 */
	if (!lp_widelinks(snum)) {
		if (!canonicalize_connect_path(conn)) {
			DEBUG(0, ("canonicalize_connect_path failed "
			"for service %s, path %s\n",
				lp_servicename(talloc_tos(), snum),
				conn->connectpath));
			status = NT_STATUS_BAD_NETWORK_NAME;
			goto err_root_exit;
		}
	}

	/* Add veto/hide lists */
	if (!IS_IPC(conn) && !IS_PRINT(conn)) {
		set_namearray( &conn->veto_list,
			       lp_veto_files(talloc_tos(), snum));
		set_namearray( &conn->hide_list,
			       lp_hide_files(talloc_tos(), snum));
		set_namearray( &conn->veto_oplock_list,
			       lp_veto_oplock_files(talloc_tos(), snum));
		set_namearray( &conn->aio_write_behind_list,
				lp_aio_write_behind(talloc_tos(), snum));
	}
	smb_fname_cpath = synthetic_smb_fname(talloc_tos(), conn->connectpath,
					      NULL, NULL);
	if (smb_fname_cpath == NULL) {
		status = NT_STATUS_NO_MEMORY;
		goto err_root_exit;
	}

	/* win2000 does not check the permissions on the directory
	   during the tree connect, instead relying on permission
	   check during individual operations. To match this behaviour
	   I have disabled this chdir check (tridge) */
	/* the alternative is just to check the directory exists */

	if ((ret = SMB_VFS_STAT(conn, smb_fname_cpath)) != 0 ||
	    !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
		if (ret == 0 && !S_ISDIR(smb_fname_cpath->st.st_ex_mode)) {
			DEBUG(0,("'%s' is not a directory, when connecting to "
				 "[%s]\n", conn->connectpath,
				 lp_servicename(talloc_tos(), snum)));
		} else {
			DEBUG(0,("'%s' does not exist or permission denied "
				 "when connecting to [%s] Error was %s\n",
				 conn->connectpath,
				 lp_servicename(talloc_tos(), snum),
				 strerror(errno) ));
		}
		status = NT_STATUS_BAD_NETWORK_NAME;
		goto err_root_exit;
	}
	conn->base_share_dev = smb_fname_cpath->st.st_ex_dev;

	talloc_free(conn->origpath);
	conn->origpath = talloc_strdup(conn, conn->connectpath);

	/* Figure out the characteristics of the underlying filesystem. This
	 * assumes that all the filesystem mounted withing a share path have
	 * the same characteristics, which is likely but not guaranteed.
	 */

	conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);

	/*
	 * Print out the 'connected as' stuff here as we need
	 * to know the effective uid and gid we will be using
	 * (at least initially).
	 */

	if( DEBUGLVL( IS_IPC(conn) ? 3 : 2 ) ) {
		dbgtext( "%s (%s) ", get_remote_machine_name(),
			 tsocket_address_string(conn->sconn->remote_address,
						talloc_tos()) );
		dbgtext( "%s", srv_is_signing_active(xconn) ? "signed " : "");
		dbgtext( "connect to service %s ",
			 lp_servicename(talloc_tos(), snum) );
		dbgtext( "initially as user %s ",
			 conn->session_info->unix_info->unix_name );
		dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
		dbgtext( "(pid %d)\n", (int)getpid() );
	}

	return status;

  err_root_exit:

	TALLOC_FREE(smb_fname_cpath);
	/* We must exit this function as root. */
	if (geteuid() != 0) {
		change_to_root_user();
	}
	if (on_err_call_dis_hook) {
		/* Call VFS disconnect hook */
		SMB_VFS_DISCONNECT(conn);
	}
	return status;
}
Exemplo n.º 2
0
Arquivo: main.c Projeto: OPSF/uClinux
static void do_server_recv(int f_in, int f_out, int argc,char *argv[])
{
	int status;
	struct file_list *flist;
	char *local_name = NULL;
	char *dir = NULL;
	int save_verbose = verbose;

	if (filesfrom_fd >= 0) {
		/* We can't mix messages with files-from data on the socket,
		 * so temporarily turn off verbose messages. */
		verbose = 0;
	}

	if (verbose > 2) {
		rprintf(FINFO, "server_recv(%d) starting pid=%ld\n",
			argc, (long)getpid());
	}

	if (am_daemon && lp_read_only(module_id)) {
		rprintf(FERROR,"ERROR: module is read only\n");
		exit_cleanup(RERR_SYNTAX);
		return;
	}


	if (argc > 0) {
		dir = argv[0];
		argc--;
		argv++;
		if (!am_daemon && !push_dir(dir)) {
			rsyserr(FERROR, errno, "push_dir#4 %s failed",
				full_fname(dir));
			exit_cleanup(RERR_FILESELECT);
		}
	}

	io_start_buffering_in();
	recv_filter_list(f_in);

	if (filesfrom_fd >= 0) {
		/* We need to send the files-from names to the sender at the
		 * same time that we receive the file-list from them, so we
		 * need the IO routines to automatically write out the names
		 * onto our f_out socket as we read the file-list.  This
		 * avoids both deadlock and extra delays/buffers. */
		io_set_filesfrom_fds(filesfrom_fd, f_out);
		filesfrom_fd = -1;
	}

	flist = recv_file_list(f_in);
	verbose = save_verbose;
	if (!flist) {
		rprintf(FERROR,"server_recv: recv_file_list error\n");
		exit_cleanup(RERR_FILESELECT);
	}
	the_file_list = flist;

	if (argc > 0) {
		if (strcmp(dir,".")) {
			argv[0] += strlen(dir);
			if (argv[0][0] == '/')
				argv[0]++;
		}
		local_name = get_local_name(flist,argv[0]);
	}

	status = do_recv(f_in,f_out,flist,local_name);
	exit_cleanup(status);
}
Exemplo n.º 3
0
static int rsync_module(int fd, int i)
{
	int argc=0;
	char *argv[MAX_ARGS];
	char **argp;
	char line[MAXPATHLEN];
	uid_t uid = (uid_t)-2;
	gid_t gid = (gid_t)-2;
	char *p;
	char *addr = client_addr(fd);
	char *host = client_name(fd);
	char *name = lp_name(i);
	int use_chroot = lp_use_chroot(i);
	int start_glob=0;
	int ret;
	char *request=NULL;
	extern int am_sender;
	extern int remote_version;
	extern int am_root;

	if (!allow_access(addr, host, lp_hosts_allow(i), lp_hosts_deny(i))) {
		rprintf(FERROR,"rsync denied on module %s from %s (%s)\n",
			name, client_name(fd), client_addr(fd));
		io_printf(fd,"@ERROR: access denied to %s from %s (%s)\n",
			  name, client_name(fd), client_addr(fd));
		return -1;
	}

	if (!claim_connection(lp_lock_file(i), lp_max_connections(i))) {
		if (errno) {
			rprintf(FERROR,"failed to open lock file %s : %s\n",
				lp_lock_file(i), strerror(errno));
			io_printf(fd,"@ERROR: failed to open lock file %s : %s\n",
				  lp_lock_file(i), strerror(errno));
		} else {
			rprintf(FERROR,"max connections (%d) reached\n",
				lp_max_connections(i));
			io_printf(fd,"@ERROR: max connections (%d) reached - try again later\n", lp_max_connections(i));
		}
		return -1;
	}

	
	auth_user = auth_server(fd, i, addr, "@RSYNCD: AUTHREQD ");

	if (!auth_user) {
		rprintf(FERROR,"auth failed on module %s from %s (%s)\n",
			name, client_name(fd), client_addr(fd));
		io_printf(fd,"@ERROR: auth failed on module %s\n",name);
		return -1;		
	}

	module_id = i;

	if (lp_read_only(i))
		read_only = 1;

	am_root = (getuid() == 0);

	if (am_root) {
		p = lp_uid(i);
		if (!name_to_uid(p, &uid)) {
			if (!isdigit(*p)) {
				rprintf(FERROR,"Invalid uid %s\n", p);
				io_printf(fd,"@ERROR: invalid uid\n");
				return -1;
			} 
			uid = atoi(p);
		}

		p = lp_gid(i);
		if (!name_to_gid(p, &gid)) {
			if (!isdigit(*p)) {
				rprintf(FERROR,"Invalid gid %s\n", p);
				io_printf(fd,"@ERROR: invalid gid\n");
				return -1;
			} 
			gid = atoi(p);
		}
	}

	p = lp_include_from(i);
	add_exclude_file(p, 1, 1);

	p = lp_include(i);
	add_include_line(p);

	p = lp_exclude_from(i);
	add_exclude_file(p, 1, 0);

	p = lp_exclude(i);
	add_exclude_line(p);

	log_open();

	if (use_chroot) {
		if (chroot(lp_path(i))) {
			rprintf(FERROR,"chroot %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chroot failed\n");
			return -1;
		}

		if (!push_dir("/", 0)) {
			rprintf(FERROR,"chdir %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chdir failed\n");
			return -1;
		}

	} else {
		if (!push_dir(lp_path(i), 0)) {
			rprintf(FERROR,"chdir %s failed\n", lp_path(i));
			io_printf(fd,"@ERROR: chdir failed\n");
			return -1;
		}
	}

	if (am_root) {
		if (setgid(gid)) {
			rprintf(FERROR,"setgid %d failed\n", gid);
			io_printf(fd,"@ERROR: setgid failed\n");
			return -1;
		}

		if (setuid(uid)) {
			rprintf(FERROR,"setuid %d failed\n", uid);
			io_printf(fd,"@ERROR: setuid failed\n");
			return -1;
		}

		am_root = (getuid() == 0);
	}

	io_printf(fd,"@RSYNCD: OK\n");

	argv[argc++] = "rsyncd";

	while (1) {
		if (!read_line(fd, line, sizeof(line)-1)) {
			return -1;
		}

		if (!*line) break;

		p = line;

		argv[argc] = strdup(p);
		if (!argv[argc]) {
			return -1;
		}

		if (start_glob) {
			if (start_glob == 1) {
				request = strdup(p);
				start_glob++;
			}
			glob_expand(name, argv, &argc, MAX_ARGS, !use_chroot);
		} else {
			argc++;
		}

		if (strcmp(line,".") == 0) {
			start_glob = 1;
		}

		if (argc == MAX_ARGS) {
			return -1;
		}
	}

	if (!use_chroot) {
		/*
		 * Note that this is applied to all parameters, whether or not
		 *    they are filenames, but no other legal parameters contain
		 *    the forms that need to be sanitized so it doesn't hurt;
		 *    it is not known at this point which parameters are files
		 *    and which aren't.
		 */
		for (i = 1; i < argc; i++) {
			sanitize_path(argv[i]);
		}
	}

	ret = parse_arguments(argc, argv, 0);

	if (request) {
		if (*auth_user) {
			rprintf(FINFO,"rsync %s %s from %s@%s (%s)\n",
				am_sender?"on":"to",
				request, auth_user, host, addr);
		} else {
			rprintf(FINFO,"rsync %s %s from %s (%s)\n",
				am_sender?"on":"to",
				request, host, addr);
		}
		free(request);
	}

#if !TRIDGE
	/* don't allow the logs to be flooded too fast */
	if (verbose > 1) verbose = 1;
#endif

	argc -= optind;
	argp = argv + optind;
	optind = 0;

	if (remote_version > 17 && am_sender)
		io_start_multiplex_out(fd);

	if (!ret) {
		option_error();
	}

	if (lp_timeout(i)) {
		extern int io_timeout;
		io_timeout = lp_timeout(i);
	}

	start_server(fd, fd, argc, argp);

	return 0;
}
Exemplo n.º 4
0
Arquivo: main.c Projeto: OPSF/uClinux
static void do_server_sender(int f_in, int f_out, int argc,char *argv[])
{
	int i;
	struct file_list *flist;
	char *dir = argv[0];

	if (verbose > 2) {
		rprintf(FINFO, "server_sender starting pid=%ld\n",
			(long)getpid());
	}

	if (am_daemon && lp_write_only(module_id)) {
		rprintf(FERROR, "ERROR: module is write only\n");
		exit_cleanup(RERR_SYNTAX);
		return;
	}
	if (am_daemon && lp_read_only(module_id) && remove_sent_files) {
		rprintf(FERROR,
		    "ERROR: --remove-sent-files cannot be used with a read-only module\n");
		exit_cleanup(RERR_SYNTAX);
		return;
	}

	if (!relative_paths && !push_dir(dir)) {
		rsyserr(FERROR, errno, "push_dir#3 %s failed",
			full_fname(dir));
		exit_cleanup(RERR_FILESELECT);
	}
	argc--;
	argv++;

	if (strcmp(dir,".")) {
		int l = strlen(dir);
		if (strcmp(dir,"/") == 0)
			l = 0;
		for (i = 0; i < argc; i++)
			argv[i] += l+1;
	}

	if (argc == 0 && (recurse || list_only)) {
		argc = 1;
		argv--;
		argv[0] = ".";
	}

	flist = send_file_list(f_out,argc,argv);
	if (!flist || flist->count == 0) {
		exit_cleanup(0);
	}
	the_file_list = flist;

	io_start_buffering_in();
	io_start_buffering_out();

	send_files(flist,f_out,f_in);
	io_flush(FULL_FLUSH);
	handle_stats(f_out);
	if (protocol_version >= 24)
		read_final_goodbye(f_in, f_out);
	io_flush(FULL_FLUSH);
	exit_cleanup(0);
}