Fix bug 7104 - "wide links" and "unix extensions" are incompatible.
[samba.git] / source3 / smbd / service.c
index 898e4290e65b19ad113a4be18a24fffb6d88fe70..8039d16586eb164f576f4c4def3a919aac6feff1 100644 (file)
@@ -56,7 +56,12 @@ bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
        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;
        }
@@ -182,8 +187,8 @@ bool set_current_service(connection_struct *conn, uint16 flags, bool do_chdir)
        if (do_chdir &&
            vfs_ChDir(conn,conn->connectpath) != 0 &&
            vfs_ChDir(conn,conn->origpath) != 0) {
-               DEBUG(0,("chdir (%s) failed\n",
-                        conn->connectpath));
+                DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n",
+                         conn->connectpath, strerror(errno)));
                return(False);
        }
 
@@ -259,7 +264,7 @@ int add_home_service(const char *service, const char *username, const char *home
 {
        int iHomeService;
 
-       if (!service || !homedir)
+       if (!service || !homedir || homedir[0] == '\0')
                return -1;
 
        if ((iHomeService = lp_servicenumber(HOMES_NAME)) < 0) {
@@ -636,15 +641,14 @@ static NTSTATUS create_connection_server_info(struct smbd_server_connection *sco
   connecting user if appropriate.
 ****************************************************************************/
 
-static connection_struct *make_connection_snum(
-                                       struct smbd_server_connection *sconn,
+connection_struct *make_connection_snum(struct smbd_server_connection *sconn,
                                        int snum, user_struct *vuser,
                                        DATA_BLOB password,
                                        const char *pdev,
                                        NTSTATUS *pstatus)
 {
        connection_struct *conn;
-       SMB_STRUCT_STAT st;
+       struct smb_filename *smb_fname_cpath = NULL;
        fstring dev;
        int ret;
        char addr[INET6_ADDRSTRLEN];
@@ -652,13 +656,12 @@ static connection_struct *make_connection_snum(
        NTSTATUS status;
 
        fstrcpy(dev, pdev);
-       SET_STAT_INVALID(st);
 
        if (NT_STATUS_IS_ERR(*pstatus = share_sanity_checks(snum, dev))) {
                return NULL;
        }       
 
-       conn = conn_new();
+       conn = conn_new(sconn);
        if (!conn) {
                DEBUG(0,("Couldn't find free connection.\n"));
                *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
@@ -694,7 +697,6 @@ static connection_struct *make_connection_snum(
        conn->printer = (strncmp(dev,"LPT",3) == 0);
        conn->ipc = ( (strncmp(dev,"IPC",3) == 0) ||
                      ( lp_enable_asu_support() && strequal(dev,"ADMIN$")) );
-       conn->dirptr = NULL;
 
        /* Case options for the share. */
        if (lp_casesensitive(snum) == Auto) {
@@ -714,7 +716,6 @@ static connection_struct *make_connection_snum(
        conn->hide_list = NULL;
        conn->veto_oplock_list = NULL;
        conn->aio_write_behind_list = NULL;
-       string_set(&conn->dirpath,"");
 
        conn->read_only = lp_readonly(SNUM(conn));
        conn->admin_user = False;
@@ -991,14 +992,21 @@ static connection_struct *make_connection_snum(
        /* Any error exit after here needs to call the disconnect hook. */
        on_err_call_dis_hook = true;
 
+       status = create_synthetic_smb_fname(talloc_tos(), conn->connectpath,
+                                           NULL, NULL, &smb_fname_cpath);
+       if (!NT_STATUS_IS_OK(status)) {
+               *pstatus = status;
+               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, conn->connectpath, &st)) != 0 ||
-           !S_ISDIR(st.st_ex_mode)) {
-               if (ret == 0 && !S_ISDIR(st.st_ex_mode)) {
+       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(snum)));
@@ -1031,12 +1039,20 @@ static connection_struct *make_connection_snum(
        }
 #endif
 
+       if (lp_unix_extensions() && lp_widelinks(snum)) {
+               DEBUG(0,("Share '%s' has wide links and unix extensions enabled. "
+                       "These parameters are incompatible. "
+                       "Disabling wide links for this share.\n",
+                       lp_servicename(snum) ));
+               lp_do_parameter(snum, "wide links", "False");
+       }
+
        /* 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
@@ -1060,7 +1076,7 @@ static connection_struct *make_connection_snum(
        return(conn);
 
   err_root_exit:
-
+       TALLOC_FREE(smb_fname_cpath);
        change_to_root_user();
        if (on_err_call_dis_hook) {
                /* Call VFS disconnect hook */
@@ -1099,7 +1115,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn,
                smb_panic("make_connection: PANIC ERROR. Called as nonroot\n");
        }
 
-       if (conn_num_open() > 2047) {
+       if (conn_num_open(sconn) > 2047) {
                *status = NT_STATUS_INSUFF_SERVER_RESOURCES;
                return NULL;
        }
@@ -1186,7 +1202,7 @@ connection_struct *make_connection(struct smbd_server_connection *sconn,
                        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));