smbd: pass symlink target path to safe_symlink_target_path()
[samba.git] / source3 / smbd / conn_msg.c
1 /*
2    Unix SMB/CIFS implementation.
3    Manage connections_struct structures
4    Copyright (C) Andrew Tridgell 1998
5    Copyright (C) Alexander Bokovoy 2002
6    Copyright (C) Jeremy Allison 2010
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "smbd/smbd.h"
24 #include "smbd/globals.h"
25
26 /****************************************************************************
27  Receive a smbcontrol message to forcibly unmount a share.
28  The message contains just a share name and all instances of that
29  share are unmounted.
30  The special sharename '*' forces unmount of all shares.
31 ****************************************************************************/
32
33 struct force_tdis_state {
34         const char *sharename;
35 };
36
37 static bool force_tdis_check(
38         struct connection_struct *conn,
39         void *private_data)
40 {
41         struct force_tdis_state *state = private_data;
42         const struct loadparm_substitution *lp_sub =
43                 loadparm_s3_global_substitution();
44         char *servicename = NULL;
45         bool do_close;
46
47         if (strcmp(state->sharename, "*") == 0) {
48                 DBG_WARNING("Forcing close of all shares\n");
49                 return true;
50         }
51
52         servicename = lp_servicename(talloc_tos(), lp_sub, SNUM(conn));
53         do_close = strequal(servicename, state->sharename);
54
55         TALLOC_FREE(servicename);
56
57         return do_close;
58 }
59
60 void msg_force_tdis(struct messaging_context *msg,
61                     void *private_data,
62                     uint32_t msg_type,
63                     struct server_id server_id,
64                     DATA_BLOB *data)
65 {
66         struct force_tdis_state state = {
67                 .sharename = (const char *)data->data,
68         };
69         struct smbd_server_connection *sconn =
70                 talloc_get_type_abort(private_data,
71                 struct smbd_server_connection);
72
73         if ((data->length == 0) || (data->data[data->length-1] != 0)) {
74                 DBG_WARNING("Ignoring invalid sharename\n");
75                 return;
76         }
77
78         conn_force_tdis(sconn, force_tdis_check, &state);
79 }
80
81 static bool force_tdis_denied_check(
82         struct connection_struct *conn,
83         void *private_data)
84 {
85         bool do_close;
86         uint32_t share_access;
87         bool read_only;
88         NTSTATUS status;
89
90         do_close = force_tdis_check(conn, private_data);
91         if (!do_close) {
92                 return false;
93         }
94
95         status = check_user_share_access(
96                 conn,
97                 conn->session_info,
98                 &share_access,
99                 &read_only);
100         if (!NT_STATUS_IS_OK(status)) {
101                 DBG_DEBUG("check_user_share_access returned %s\n",
102                           nt_errstr(status));
103                 return true;    /* close the share */
104         }
105
106         if (conn->share_access != share_access) {
107                 DBG_DEBUG("share_access changed from %"PRIx32" to %"PRIx32"\n",
108                           conn->share_access, share_access);
109                 return true;    /* close the share */
110         }
111
112         if (conn->read_only != read_only) {
113                 DBG_DEBUG("read_only changed from %s to %s\n",
114                           conn->read_only ? "true" : "false",
115                           read_only ? "true" : "false");
116                 return true;    /* close the share */
117         }
118
119         /*
120          * all still ok, keep the connection open
121          */
122         return false;
123 }
124
125 void msg_force_tdis_denied(
126         struct messaging_context *msg,
127         void *private_data,
128         uint32_t msg_type,
129         struct server_id server_id,
130         DATA_BLOB *data)
131 {
132         struct force_tdis_state state = {
133                 .sharename = (const char *)data->data,
134         };
135         struct smbd_server_connection *sconn =
136                 talloc_get_type_abort(private_data,
137                 struct smbd_server_connection);
138
139         if ((data->length == 0) || (data->data[data->length-1] != 0)) {
140                 DBG_WARNING("Ignoring invalid sharename\n");
141                 return;
142         }
143
144         change_to_root_user();
145         reload_services(sconn, conn_snum_used, false);
146
147         conn_force_tdis(sconn, force_tdis_denied_check, &state);
148 }