summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/smbd/service.c180
1 files changed, 109 insertions, 71 deletions
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 2cd3363cf6..dd09a6955e 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -21,16 +21,17 @@
extern userdom_struct current_user_info;
-static bool canonicalize_path(connection_struct *conn, pstring path)
+static bool canonicalize_connect_path(connection_struct *conn)
{
#ifdef REALPATH_TAKES_NULL
- char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL);
+ bool ret;
+ char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath,NULL);
if (!resolved_name) {
- return False;
+ return false;
}
- pstrcpy(path, resolved_name);
+ ret = set_conn_connectpath(conn,resolved_name);
SAFE_FREE(resolved_name);
- return True;
+ return ret;
#else
#ifdef PATH_MAX
char resolved_name_buf[PATH_MAX+1];
@@ -39,10 +40,9 @@ static bool canonicalize_path(connection_struct *conn, pstring path)
#endif
char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf);
if (!resolved_name) {
- return False;
+ return false;
}
- pstrcpy(path, resolved_name);
- return True;
+ return set_conn_connectpath(conn,resolved_name);
#endif /* REALPATH_TAKES_NULL */
}
@@ -52,12 +52,18 @@ static bool canonicalize_path(connection_struct *conn, pstring path)
Observent people will notice a similarity between this and check_path_syntax :-).
****************************************************************************/
-void set_conn_connectpath(connection_struct *conn, const char *connectpath)
+bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
{
- pstring destname;
- char *d = destname;
+ char *destname;
+ char *d;
const char *s = connectpath;
- bool start_of_name_component = True;
+ bool start_of_name_component = true;
+
+ destname = SMB_STRDUP(connectpath);
+ if (!destname) {
+ return false;
+ }
+ d = destname;
*d++ = '/'; /* Always start with root. */
@@ -142,7 +148,7 @@ void set_conn_connectpath(connection_struct *conn, const char *connectpath)
break;
}
}
- start_of_name_component = False;
+ start_of_name_component = false;
}
*d = '\0';
@@ -155,6 +161,8 @@ void set_conn_connectpath(connection_struct *conn, const char *connectpath)
lp_servicename(SNUM(conn)), destname ));
string_set(&conn->connectpath, destname);
+ SAFE_FREE(destname);
+ return true;
}
/****************************************************************************
@@ -422,13 +430,17 @@ int find_service(fstring service)
* could get overwritten by the recursive find_service() call
* below. Fix from Josef Hinteregger <joehtg@joehtg.co.at>.
*/
- pstring defservice;
- pstrcpy(defservice, pdefservice);
+ char *defservice = SMB_STRDUP(pdefservice);
+
+ if (!defservice) {
+ goto fail;
+ }
/* Disallow anything except explicit share names. */
if (strequal(defservice,HOMES_NAME) ||
strequal(defservice, PRINTERS_NAME) ||
strequal(defservice, "IPC$")) {
+ SAFE_FREE(defservice);
goto fail;
}
@@ -437,6 +449,7 @@ int find_service(fstring service)
all_string_sub(service, "_","/",0);
iService = lp_add_service(service, iService);
}
+ SAFE_FREE(defservice);
}
}
@@ -642,6 +655,7 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
fstring dev;
int ret;
char addr[INET6_ADDRSTRLEN];
+ bool on_err_call_dis_hook = false;
*user = 0;
fstrcpy(dev, pdev);
@@ -889,16 +903,27 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
}
{
- pstring s;
- pstrcpy(s,lp_pathname(snum));
- standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
- conn->connectpath, conn->gid,
- get_current_username(),
- current_user_info.domain,
- s, sizeof(s));
- set_conn_connectpath(conn,s);
+ char *s = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)), conn->user,
+ conn->connectpath, conn->gid,
+ get_current_username(),
+ current_user_info.domain,
+ lp_pathname(snum));
+ if (!s) {
+ conn_free(conn);
+ *status = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
+
+ if (!set_conn_connectpath(conn,s)) {
+ TALLOC_FREE(s);
+ conn_free(conn);
+ *status = NT_STATUS_NO_MEMORY;
+ return NULL;
+ }
DEBUG(3,("Connect path is '%s' for service [%s]\n",s,
lp_servicename(snum)));
+ TALLOC_FREE(s);
}
/*
@@ -969,10 +994,15 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
* depend on the realpath() pointer in the vfs table. JRA.
*/
if (!lp_widelinks(snum)) {
- pstring s;
- pstrcpy(s,conn->connectpath);
- canonicalize_path(conn, s);
- set_conn_connectpath(conn,s);
+ 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);
+ *status = NT_STATUS_BAD_NETWORK_NAME;
+ return NULL;
+ }
}
if ((!conn->printer) && (!conn->ipc)) {
@@ -1012,15 +1042,15 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
* to below */
/* execute any "root preexec = " line */
if (*lp_rootpreexec(snum)) {
- pstring cmd;
- pstrcpy(cmd,lp_rootpreexec(snum));
- standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
- conn->connectpath, conn->gid,
- get_current_username(),
- current_user_info.domain,
- cmd, sizeof(cmd));
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)), conn->user,
+ conn->connectpath, conn->gid,
+ get_current_username(),
+ current_user_info.domain,
+ lp_rootpreexec(snum));
DEBUG(5,("cmd=%s\n",cmd));
ret = smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
if (ret != 0 && lp_rootpreexec_close(snum)) {
DEBUG(1,("root preexec gave %d - failing "
"connection\n", ret));
@@ -1049,22 +1079,19 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
/* execute any "preexec = " line */
if (*lp_preexec(snum)) {
- pstring cmd;
- pstrcpy(cmd,lp_preexec(snum));
- standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
- conn->connectpath, conn->gid,
- get_current_username(),
- current_user_info.domain,
- cmd, sizeof(cmd));
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)), conn->user,
+ conn->connectpath, conn->gid,
+ get_current_username(),
+ current_user_info.domain,
+ lp_preexec(snum));
ret = smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
if (ret != 0 && lp_preexec_close(snum)) {
DEBUG(1,("preexec gave %d - failing connection\n",
ret));
- change_to_root_user();
- yield_connection(conn, lp_servicename(snum));
- conn_free(conn);
*status = NT_STATUS_ACCESS_DENIED;
- return NULL;
+ goto err_root_exit;
}
}
@@ -1087,13 +1114,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
if (SMB_VFS_CONNECT(conn, lp_servicename(snum), user) < 0) {
DEBUG(0,("make_connection: VFS make connection failed!\n"));
- change_to_root_user();
- yield_connection(conn, lp_servicename(snum));
- conn_free(conn);
*status = NT_STATUS_UNSUCCESSFUL;
- return NULL;
+ goto err_root_exit;
}
+ /* Any error exit after here needs to call the disconnect hook. */
+ on_err_call_dis_hook = true;
+
/* 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
@@ -1111,13 +1138,8 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
conn->connectpath, lp_servicename(snum),
strerror(errno) ));
}
- change_to_root_user();
- /* Call VFS disconnect hook */
- SMB_VFS_DISCONNECT(conn);
- yield_connection(conn, lp_servicename(snum));
- conn_free(conn);
*status = NT_STATUS_BAD_NETWORK_NAME;
- return NULL;
+ goto err_root_exit;
}
string_set(&conn->origpath,conn->connectpath);
@@ -1129,9 +1151,14 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
char *s = vfs_GetWd(ctx,s);
if (!s) {
*status = map_nt_error_from_unix(errno);
- return NULL;
+ TALLOC_FREE(ctx);
+ goto err_root_exit;
+ }
+ if (!set_conn_connectpath(conn,s)) {
+ *status = NT_STATUS_NO_MEMORY;
+ TALLOC_FREE(ctx);
+ goto err_root_exit;
}
- set_conn_connectpath(conn,s);
vfs_ChDir(conn,conn->connectpath);
TALLOC_FREE(ctx);
}
@@ -1156,6 +1183,17 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
/* we've finished with the user stuff - go back to root */
change_to_root_user();
return(conn);
+
+ err_root_exit:
+
+ 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);
+ return NULL;
}
/***************************************************************************************
@@ -1356,28 +1394,28 @@ void close_cnum(connection_struct *conn, uint16 vuid)
/* execute any "postexec = " line */
if (*lp_postexec(SNUM(conn)) &&
change_to_user(conn, vuid)) {
- pstring cmd;
- pstrcpy(cmd,lp_postexec(SNUM(conn)));
- standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
- conn->connectpath, conn->gid,
- get_current_username(),
- current_user_info.domain,
- cmd, sizeof(cmd));
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)), conn->user,
+ conn->connectpath, conn->gid,
+ get_current_username(),
+ current_user_info.domain,
+ lp_postexec(SNUM(conn)));
smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
change_to_root_user();
}
change_to_root_user();
/* execute any "root postexec = " line */
if (*lp_rootpostexec(SNUM(conn))) {
- pstring cmd;
- pstrcpy(cmd,lp_rootpostexec(SNUM(conn)));
- standard_sub_advanced(lp_servicename(SNUM(conn)), conn->user,
- conn->connectpath, conn->gid,
- get_current_username(),
- current_user_info.domain,
- cmd, sizeof(cmd));
+ char *cmd = talloc_sub_advanced(talloc_tos(),
+ lp_servicename(SNUM(conn)), conn->user,
+ conn->connectpath, conn->gid,
+ get_current_username(),
+ current_user_info.domain,
+ lp_rootpostexec(SNUM(conn)));
smbrun(cmd,NULL);
+ TALLOC_FREE(cmd);
}
conn_free(conn);