const char *s = connectpath;
bool start_of_name_component = true;
- destname = SMB_STRDUP(connectpath);
+ if (connectpath == NULL || connectpath[0] == '\0') {
+ return false;
+ }
+
+ /* Allocate for strlen + '\0' + possible leading '/' */
+ destname = SMB_MALLOC(strlen(connectpath) + 2);
if (!destname) {
return false;
}
{
int iHomeService;
- if (!service || !homedir)
+ if (!service || !homedir || homedir[0] == '\0')
return -1;
if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) {
const char *pdev,
NTSTATUS *pstatus)
{
- connection_struct *conn;
+ connection_struct *conn = NULL;
struct smb_filename *smb_fname_cpath = NULL;
fstring dev;
int ret;
char addr[INET6_ADDRSTRLEN];
bool on_err_call_dis_hook = false;
+ bool claimed_connection = false;
+ uid_t effuid;
+ gid_t effgid;
NTSTATUS status;
fstrcpy(dev, pdev);
if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) {
- return NULL;
- }
+ goto err_root_exit;
+ }
conn = conn_new(sconn);
if (!conn) {
DEBUG(0,("Couldn't find free connection.\n"));
*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
- return NULL;
+ goto err_root_exit;
}
conn->params->service = snum;
DEBUG(1, ("create_connection_server_info failed: %s\n",
nt_errstr(status)));
*pstatus = status;
- conn_free(conn);
- return NULL;
+ goto err_root_exit;
}
if ((lp_guest_only(snum)) || (lp_security() == SEC_SHARE)) {
fuser = talloc_string_sub(conn, lp_force_user(snum), "%S",
lp_servicename(snum));
if (fuser == NULL) {
- conn_free(conn);
*pstatus = NT_STATUS_NO_MEMORY;
- return NULL;
+ goto err_root_exit;
}
status = make_serverinfo_from_username(
conn, fuser, conn->server_info->guest,
&forced_serverinfo);
if (!NT_STATUS_IS_OK(status)) {
- conn_free(conn);
*pstatus = status;
- return NULL;
+ goto err_root_exit;
}
TALLOC_FREE(conn->server_info);
&conn->server_info->utok.gid);
if (!NT_STATUS_IS_OK(status)) {
- conn_free(conn);
*pstatus = status;
- return NULL;
+ goto err_root_exit;
}
/*
pdb_get_domain(conn->server_info->sam_account),
lp_pathname(snum));
if (!s) {
- conn_free(conn);
*pstatus = NT_STATUS_NO_MEMORY;
- return NULL;
+ goto err_root_exit;
}
if (!set_conn_connectpath(conn,s)) {
TALLOC_FREE(s);
- conn_free(conn);
*pstatus = NT_STATUS_NO_MEMORY;
- return NULL;
+ goto err_root_exit;
}
DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
lp_servicename(snum)));
"denied due to security "
"descriptor.\n",
lp_servicename(snum)));
- conn_free(conn);
*pstatus = NT_STATUS_ACCESS_DENIED;
- return NULL;
+ goto err_root_exit;
} else {
conn->read_only = True;
}
if (!smbd_vfs_init(conn)) {
DEBUG(0, ("vfs_init failed for service %s\n",
lp_servicename(snum)));
- conn_free(conn);
*pstatus = NT_STATUS_BAD_NETWORK_NAME;
- return NULL;
- }
-
- /*
- * 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(snum),
- conn->connectpath));
- conn_free(conn);
- *pstatus = NT_STATUS_BAD_NETWORK_NAME;
- return NULL;
- }
+ goto err_root_exit;
}
if ((!conn->printer) && (!conn->ipc)) {
conn);
}
-/* ROOT Activities: */
+/* ROOT Activities: */
+ /* explicitly check widelinks here so that we can correctly warn
+ * in the logs. */
+ widelinks_warning(snum);
+
/*
* Enforce the max connections parameter.
*/
DEBUG(1, ("Max connections (%d) exceeded for %s\n",
lp_max_connections(snum), lp_servicename(snum)));
- conn_free(conn);
*pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
- return NULL;
- }
+ goto err_root_exit;
+ }
/*
* Get us an entry in the connections db
*/
if (!claim_connection(conn, lp_servicename(snum), 0)) {
DEBUG(1, ("Could not store connections entry\n"));
- conn_free(conn);
*pstatus = NT_STATUS_INTERNAL_DB_ERROR;
- return NULL;
- }
+ goto err_root_exit;
+ }
+ claimed_connection = true;
+
+ /*
+ * 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 */
if (ret != 0 && lp_rootpreexec_close(snum)) {
DEBUG(1,("root preexec gave %d - failing "
"connection\n", ret));
- yield_connection(conn, lp_servicename(snum));
- conn_free(conn);
*pstatus = NT_STATUS_ACCESS_DENIED;
- return NULL;
+ goto err_root_exit;
}
}
if (!change_to_user(conn, conn->vuid)) {
/* No point continuing if they fail the basic checks */
DEBUG(0,("Can't become connected user!\n"));
- yield_connection(conn, lp_servicename(snum));
- conn_free(conn);
*pstatus = NT_STATUS_LOGON_FAILURE;
- return NULL;
+ 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 */
}
}
+ /*
+ * 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)) {
+
+ /* We need to do the path canonicalization
+ * as root, as we may not have rights to
+ * this path as the user. */
+
+ change_to_root_user();
+
+/* ROOT Activites: */
+ if (!canonicalize_connect_path(conn)) {
+ DEBUG(0, ("canonicalize_connect_path failed "
+ "for service %s, path %s\n",
+ lp_servicename(snum),
+ conn->connectpath));
+ *pstatus = NT_STATUS_BAD_NETWORK_NAME;
+ goto err_root_exit;
+ }
+
+ /* Back to the user for the VFS_CONNECT call. */
+ if (!change_to_user(conn, conn->vuid)) {
+ *pstatus = NT_STATUS_LOGON_FAILURE;
+ goto err_root_exit;
+ }
+/* USER Activites: */
+ }
+
#ifdef WITH_FAKE_KASERVER
if (lp_afs_share(snum)) {
afs_login(conn);
}
#endif
-
+
/* Add veto/hide lists */
if (!IS_IPC(conn) && !IS_PRINT(conn)) {
set_namearray( &conn->veto_list, lp_veto_files(snum));
set_namearray( &conn->aio_write_behind_list,
lp_aio_write_behind(snum));
}
-
+
/* Invoke VFS make connection hook - do this before the VFS_STAT call
to allow any filesystems needing user credentials to initialize
themselves. */
check during individual operations. To match this behaviour
I have disabled this chdir check (tridge) */
/* the alternative is just to check the directory exists */
+
+ /*
+ * 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 ((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)) {
string_set(&conn->origpath,conn->connectpath);
-#if SOFTLINK_OPTIMISATION
- /* resolve any soft links early if possible */
- if (vfs_ChDir(conn,conn->connectpath) == 0) {
- TALLOC_CTX *ctx = talloc_tos();
- char *s = vfs_GetWd(ctx,s);
- if (!s) {
- *status = map_nt_error_from_unix(errno);
- goto err_root_exit;
- }
- if (!set_conn_connectpath(conn,s)) {
- *status = NT_STATUS_NO_MEMORY;
- goto err_root_exit;
- }
- vfs_ChDir(conn,conn->connectpath);
- }
-#endif
-
/* 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->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
/*
* Print out the 'connected as' stuff here as we need
dbgtext( "connect to service %s ", lp_servicename(snum) );
dbgtext( "initially as user %s ",
conn->server_info->unix_name );
- dbgtext( "(uid=%d, gid=%d) ", (int)geteuid(), (int)getegid() );
+ dbgtext( "(uid=%d, gid=%d) ", (int)effuid, (int)effgid );
dbgtext( "(pid %d)\n", (int)sys_getpid() );
}
- /* we've finished with the user stuff - go back to root */
- change_to_root_user();
return(conn);
err_root_exit:
TALLOC_FREE(smb_fname_cpath);
- change_to_root_user();
+ /* 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);
}
- yield_connection(conn, lp_servicename(snum));
- conn_free(conn);
+ if (claimed_connection) {
+ yield_connection(conn, lp_servicename(snum));
+ }
+ if (conn) {
+ conn_free(conn);
+ }
return NULL;
}
return NULL;
}
- DEBUG(0,("%s (%s) couldn't find service %s\n",
+ DEBUG(3,("%s (%s) couldn't find service %s\n",
get_remote_machine_name(),
client_addr(get_client_fd(),addr,sizeof(addr)),
service));