notifyd: Use messaging_register for MSG_SMB_NOTIFY_GET_DB
[vlendec/samba-autobuild/.git] / source3 / smbd / service.c
index 4b16dbad5e92510067f15f6e35744b849c9004a1..75a47dee0caae891a5364ee00a858400250ad17c 100644 (file)
 #include "lib/param/loadparm.h"
 #include "messages.h"
 #include "lib/afs/afs_funcs.h"
+#include "lib/util_path.h"
 
 static bool canonicalize_connect_path(connection_struct *conn)
 {
        bool ret;
-       char *resolved_name = SMB_VFS_REALPATH(conn,conn->connectpath);
-       if (!resolved_name) {
+       struct smb_filename con_fname = { .base_name = conn->connectpath };
+       struct smb_filename *resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(),
+                                               &con_fname);
+       if (resolved_fname == NULL) {
                return false;
        }
-       ret = set_conn_connectpath(conn,resolved_name);
-       SAFE_FREE(resolved_name);
+       ret = set_conn_connectpath(conn,resolved_fname->base_name);
+       TALLOC_FREE(resolved_fname);
        return ret;
 }
 
 /****************************************************************************
  Ensure when setting connectpath it is a canonicalized (no ./ // or ../)
  absolute path stating in / and not ending in /.
- Observent people will notice a similarity between this and check_path_syntax :-).
 ****************************************************************************/
 
 bool set_conn_connectpath(connection_struct *conn, const char *connectpath)
 {
        char *destname;
-       char *d;
-       const char *s = connectpath;
-        bool start_of_name_component = true;
 
        if (connectpath == NULL || connectpath[0] == '\0') {
                return false;
        }
 
-       /* Allocate for strlen + '\0' + possible leading '/' */
-       destname = (char *)talloc_size(conn, strlen(connectpath) + 2);
-       if (!destname) {
+       destname = canonicalize_absolute_path(conn, connectpath);
+       if (destname == NULL) {
                return false;
        }
-       d = destname;
-
-       *d++ = '/'; /* Always start with root. */
-
-       while (*s) {
-               if (*s == '/') {
-                       /* Eat multiple '/' */
-                       while (*s == '/') {
-                                s++;
-                        }
-                       if ((d > destname + 1) && (*s != '\0')) {
-                               *d++ = '/';
-                       }
-                       start_of_name_component = True;
-                       continue;
-               }
-
-               if (start_of_name_component) {
-                       if ((s[0] == '.') && (s[1] == '.') && (s[2] == '/' || s[2] == '\0')) {
-                               /* Uh oh - "/../" or "/..\0" ! */
-
-                               /* Go past the ../ or .. */
-                               if (s[2] == '/') {
-                                       s += 3;
-                               } else {
-                                       s += 2; /* Go past the .. */
-                               }
-
-                               /* If  we just added a '/' - delete it */
-                               if ((d > destname) && (*(d-1) == '/')) {
-                                       *(d-1) = '\0';
-                                       d--;
-                               }
-
-                               /* Are we at the start ? Can't go back further if so. */
-                               if (d <= destname) {
-                                       *d++ = '/'; /* Can't delete root */
-                                       continue;
-                               }
-                               /* Go back one level... */
-                               /* Decrement d first as d points to the *next* char to write into. */
-                               for (d--; d > destname; d--) {
-                                       if (*d == '/') {
-                                               break;
-                                       }
-                               }
-                               /* We're still at the start of a name component, just the previous one. */
-                               continue;
-                       } else if ((s[0] == '.') && ((s[1] == '\0') || s[1] == '/')) {
-                               /* Component of pathname can't be "." only - skip the '.' . */
-                               if (s[1] == '/') {
-                                       s += 2;
-                               } else {
-                                       s++;
-                               }
-                               continue;
-                       }
-               }
-
-               if (!(*s & 0x80)) {
-                       *d++ = *s++;
-               } else {
-                       size_t siz;
-                       /* Get the size of the next MB character. */
-                       next_codepoint(s,&siz);
-                       switch(siz) {
-                               case 5:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 4:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 3:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 2:
-                                       *d++ = *s++;
-                                       /*fall through*/
-                               case 1:
-                                       *d++ = *s++;
-                                       break;
-                               default:
-                                       break;
-                       }
-               }
-               start_of_name_component = false;
-       }
-       *d = '\0';
-
-       /* And must not end in '/' */
-       if (d > destname + 1 && (*(d-1) == '/')) {
-               *(d-1) = '\0';
-       }
 
        DEBUG(10,("set_conn_connectpath: service %s, connectpath = %s\n",
                lp_servicename(talloc_tos(), SNUM(conn)), destname ));
 
        talloc_free(conn->connectpath);
        conn->connectpath = destname;
-       /* Ensure conn->cwd is initialized - start as conn->connectpath. */
-       TALLOC_FREE(conn->cwd);
-       conn->cwd = talloc_strdup(conn, conn->connectpath);
-       if (!conn->cwd) {
+       /*
+        * Ensure conn->cwd_fname is initialized.
+        * start as conn->connectpath.
+        */
+       TALLOC_FREE(conn->cwd_fname);
+       conn->cwd_fname = synthetic_smb_fname(conn,
+                               conn->connectpath,
+                               NULL,
+                               NULL,
+                               0);
+       if (conn->cwd_fname == NULL) {
                return false;
        }
        return true;
@@ -192,12 +104,22 @@ bool set_current_service(connection_struct *conn, uint16_t flags, bool do_chdir)
 
        snum = SNUM(conn);
 
-       if (do_chdir &&
-           vfs_ChDir(conn,conn->connectpath) != 0 &&
-           vfs_ChDir(conn,conn->origpath) != 0) {
-                DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n",
-                         conn->connectpath, strerror(errno)));
-               return(False);
+       {
+               struct smb_filename connectpath_fname = {
+                       .base_name = conn->connectpath
+               };
+               struct smb_filename origpath_fname = {
+                       .base_name = conn->origpath
+               };
+
+               if (do_chdir &&
+                   vfs_ChDir(conn, &connectpath_fname) != 0 &&
+                   vfs_ChDir(conn, &origpath_fname) != 0) {
+                       DEBUG(((errno!=EACCES)?0:3),
+                               ("chdir (%s) failed, reason: %s\n",
+                               conn->connectpath, strerror(errno)));
+                       return(False);
+               }
        }
 
        if ((conn == last_conn) && (last_flags == flags)) {
@@ -529,7 +451,7 @@ static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
        }
 
        sconn->notify_ctx = notify_init(sconn, sconn->msg_ctx, sconn->ev_ctx,
-                                       notify_callback);
+                                       sconn, notify_callback);
        if (sconn->notify_ctx == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -544,6 +466,18 @@ static NTSTATUS notify_init_sconn(struct smbd_server_connection *sconn)
                return status;
        }
 
+       status = messaging_register(sconn->msg_ctx, sconn,
+                                   MSG_SMB_NOTIFY_STARTED,
+                                   smbd_notifyd_restarted);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_DEBUG("messaging_register failed: %s\n",
+                         nt_errstr(status));
+               messaging_deregister(sconn->msg_ctx,
+                                    MSG_SMB_NOTIFY_CANCEL_DELETED, sconn);
+               TALLOC_FREE(sconn->notify_ctx);
+               return status;
+       }
+
        return NT_STATUS_OK;
 }
 
@@ -611,6 +545,18 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
        conn->short_case_preserve = lp_short_preserve_case(snum);
 
        conn->encrypt_level = lp_smb_encrypt(snum);
+       if (conn->encrypt_level > SMB_SIGNING_OFF) {
+               if (lp_smb_encrypt(-1) == SMB_SIGNING_OFF) {
+                       if (conn->encrypt_level == SMB_SIGNING_REQUIRED) {
+                               DBG_ERR("Service [%s] requires encryption, but "
+                                       "it is disabled globally!\n",
+                                       lp_servicename(talloc_tos(), snum));
+                               status = NT_STATUS_ACCESS_DENIED;
+                               goto err_root_exit;
+                       }
+                       conn->encrypt_level = SMB_SIGNING_OFF;
+               }
+       }
 
        conn->veto_list = NULL;
        conn->hide_list = NULL;
@@ -752,7 +698,7 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
                                        conn->session_info->info->domain_name,
                                        lp_root_preexec(talloc_tos(), snum));
                DEBUG(5,("cmd=%s\n",cmd));
-               ret = smbrun(cmd,NULL);
+               ret = smbrun(cmd, NULL, NULL);
                TALLOC_FREE(cmd);
                if (ret != 0 && lp_root_preexec_close(snum)) {
                        DEBUG(1,("root preexec gave %d - failing "
@@ -789,7 +735,7 @@ static NTSTATUS make_connection_snum(struct smbXsrv_connection *xconn,
                                        conn->session_info->unix_info->sanitized_username,
                                        conn->session_info->info->domain_name,
                                        lp_preexec(talloc_tos(), snum));
-               ret = smbrun(cmd,NULL);
+               ret = smbrun(cmd, NULL, NULL);
                TALLOC_FREE(cmd);
                if (ret != 0 && lp_preexec_close(snum)) {
                        DEBUG(1,("preexec gave %d - failing connection\n",
@@ -1156,6 +1102,9 @@ connection_struct *make_connection(struct smb_request *req,
 
 void close_cnum(connection_struct *conn, uint64_t vuid)
 {
+       char rootpath[2] = { '/', '\0'};
+       struct smb_filename root_fname = { .base_name = rootpath };
+
        file_close_conn(conn);
 
        if (!IS_IPC(conn)) {
@@ -1171,7 +1120,7 @@ void close_cnum(connection_struct *conn, uint64_t vuid)
                                 lp_servicename(talloc_tos(), SNUM(conn))));
 
        /* make sure we leave the directory available for unmount */
-       vfs_ChDir(conn, "/");
+       vfs_ChDir(conn, &root_fname);
 
        /* Call VFS disconnect hook */
        SMB_VFS_DISCONNECT(conn);
@@ -1187,7 +1136,7 @@ void close_cnum(connection_struct *conn, uint64_t vuid)
                                        conn->session_info->unix_info->sanitized_username,
                                        conn->session_info->info->domain_name,
                                        lp_postexec(talloc_tos(), SNUM(conn)));
-               smbrun(cmd,NULL);
+               smbrun(cmd, NULL, NULL);
                TALLOC_FREE(cmd);
                change_to_root_user();
        }
@@ -1203,7 +1152,7 @@ void close_cnum(connection_struct *conn, uint64_t vuid)
                                        conn->session_info->unix_info->sanitized_username,
                                        conn->session_info->info->domain_name,
                                        lp_root_postexec(talloc_tos(), SNUM(conn)));
-               smbrun(cmd,NULL);
+               smbrun(cmd, NULL, NULL);
                TALLOC_FREE(cmd);
        }