/src/samba/source3/smbd/smb1_service.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | service (connection) opening and closing |
4 | | Copyright (C) Andrew Tridgell 1992-1998 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "includes.h" |
21 | | #include "system/filesys.h" |
22 | | #include "system/passwd.h" /* uid_wrapper */ |
23 | | #include "../lib/tsocket/tsocket.h" |
24 | | #include "smbd/smbd.h" |
25 | | #include "smbd/globals.h" |
26 | | #include "../librpc/gen_ndr/netlogon.h" |
27 | | #include "../libcli/security/security.h" |
28 | | #include "printing/pcap.h" |
29 | | #include "passdb/lookup_sid.h" |
30 | | #include "auth.h" |
31 | | #include "../auth/auth_util.h" |
32 | | #include "lib/param/loadparm.h" |
33 | | #include "messages.h" |
34 | | #include "lib/afs/afs_funcs.h" |
35 | | #include "lib/util_path.h" |
36 | | #include "lib/util/string_wrappers.h" |
37 | | #include "source3/lib/substitute.h" |
38 | | |
39 | | /**************************************************************************** |
40 | | Make a connection to a service from SMB1. Internal interface. |
41 | | ****************************************************************************/ |
42 | | |
43 | | static connection_struct *make_connection_smb1(struct smb_request *req, |
44 | | NTTIME now, |
45 | | int snum, |
46 | | const char *pdev, |
47 | | NTSTATUS *pstatus) |
48 | 0 | { |
49 | 0 | const struct loadparm_substitution *lp_sub = |
50 | 0 | loadparm_s3_global_substitution(); |
51 | 0 | uint32_t session_global_id; |
52 | 0 | char *share_name = NULL; |
53 | 0 | struct smbXsrv_tcon *tcon; |
54 | 0 | NTSTATUS status; |
55 | 0 | struct connection_struct *conn; |
56 | 0 | const char *lease_mask = NULL; |
57 | |
|
58 | 0 | session_global_id = req->session->global->session_global_id; |
59 | 0 | share_name = lp_servicename(talloc_tos(), lp_sub, snum); |
60 | 0 | if (share_name == NULL) { |
61 | 0 | *pstatus = NT_STATUS_NO_MEMORY; |
62 | 0 | return NULL; |
63 | 0 | } |
64 | | |
65 | 0 | if ((lp_max_connections(snum) > 0) |
66 | 0 | && (count_current_connections(lp_const_servicename(snum), true) >= |
67 | 0 | lp_max_connections(snum))) { |
68 | |
|
69 | 0 | DBG_WARNING("Max connections (%d) exceeded for [%s][%s]\n", |
70 | 0 | lp_max_connections(snum), |
71 | 0 | lp_const_servicename(snum), share_name); |
72 | 0 | TALLOC_FREE(share_name); |
73 | 0 | *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; |
74 | 0 | return NULL; |
75 | 0 | } |
76 | | |
77 | 0 | status = smb1srv_tcon_create(req->xconn, |
78 | 0 | session_global_id, |
79 | 0 | share_name, |
80 | 0 | now, &tcon); |
81 | 0 | if (!NT_STATUS_IS_OK(status)) { |
82 | 0 | DBG_ERR("Couldn't find free tcon for [%s] - %s\n", |
83 | 0 | share_name, |
84 | 0 | nt_errstr(status)); |
85 | 0 | TALLOC_FREE(share_name); |
86 | 0 | *pstatus = status; |
87 | 0 | return NULL; |
88 | 0 | } |
89 | 0 | TALLOC_FREE(share_name); |
90 | |
|
91 | 0 | conn = conn_new(req->sconn); |
92 | 0 | if (!conn) { |
93 | 0 | TALLOC_FREE(tcon); |
94 | |
|
95 | 0 | DBG_ERR("Couldn't find free connection.\n"); |
96 | 0 | *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; |
97 | 0 | return NULL; |
98 | 0 | } |
99 | | |
100 | 0 | conn->cnum = tcon->global->tcon_wire_id; |
101 | 0 | conn->tcon = tcon; |
102 | |
|
103 | 0 | *pstatus = make_connection_snum(req->xconn, |
104 | 0 | conn, |
105 | 0 | snum, |
106 | 0 | req->session, |
107 | 0 | pdev); |
108 | 0 | if (!NT_STATUS_IS_OK(*pstatus)) { |
109 | 0 | TALLOC_FREE(conn); |
110 | 0 | TALLOC_FREE(tcon); |
111 | 0 | return NULL; |
112 | 0 | } |
113 | | |
114 | 0 | lease_mask = lp_parm_const_string(SNUM(tcon->compat), |
115 | 0 | "smb1", |
116 | 0 | "max lease mask", |
117 | 0 | "RWH"); |
118 | |
|
119 | 0 | tcon->compat = talloc_move(tcon, &conn); |
120 | 0 | tcon->status = NT_STATUS_OK; |
121 | 0 | tcon->smb_max_lease_mask = smb2_util_lease_state(lease_mask); |
122 | |
|
123 | 0 | *pstatus = NT_STATUS_OK; |
124 | |
|
125 | 0 | return tcon->compat; |
126 | 0 | } |
127 | | |
128 | | /**************************************************************************** |
129 | | Make a connection to a service. External SMB1 interface. |
130 | | * |
131 | | * @param service |
132 | | ****************************************************************************/ |
133 | | |
134 | | connection_struct *make_connection(struct smb_request *req, |
135 | | NTTIME now, |
136 | | const char *service_in, |
137 | | const char *pdev, uint64_t vuid, |
138 | | NTSTATUS *status) |
139 | 0 | { |
140 | 0 | struct smbd_server_connection *sconn = req->sconn; |
141 | 0 | struct smbXsrv_session *session = req->session; |
142 | 0 | const struct loadparm_substitution *lp_sub = |
143 | 0 | loadparm_s3_global_substitution(); |
144 | 0 | uid_t euid; |
145 | 0 | char *service = NULL; |
146 | 0 | fstring dev; |
147 | 0 | int snum = -1; |
148 | |
|
149 | 0 | fstrcpy(dev, pdev); |
150 | | |
151 | | /* This must ONLY BE CALLED AS ROOT. As it exits this function as |
152 | | * root. */ |
153 | 0 | if (!non_root_mode() && (euid = geteuid()) != 0) { |
154 | 0 | DBG_ERR("PANIC ERROR. Called as nonroot (%u)\n", |
155 | 0 | (unsigned int)euid); |
156 | 0 | smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); |
157 | 0 | } |
158 | | |
159 | 0 | if (conn_num_open(sconn) > 2047) { |
160 | 0 | *status = NT_STATUS_INSUFF_SERVER_RESOURCES; |
161 | 0 | return NULL; |
162 | 0 | } |
163 | | |
164 | 0 | if (session == NULL) { |
165 | 0 | DBG_WARNING("refusing to connect with no session setup\n"); |
166 | 0 | *status = NT_STATUS_ACCESS_DENIED; |
167 | 0 | return NULL; |
168 | 0 | } |
169 | | |
170 | | /* Logic to try and connect to the correct [homes] share, preferably |
171 | | without too many getpwnam() lookups. This is particularly nasty for |
172 | | winbind usernames, where the share name isn't the same as unix |
173 | | username. |
174 | | */ |
175 | | |
176 | 0 | if (strequal(service_in,HOMES_NAME)) { |
177 | 0 | if (session->homes_snum == -1) { |
178 | 0 | DBG_NOTICE("[homes] share not available for " |
179 | 0 | "this user because it was not found " |
180 | 0 | "or created at session setup " |
181 | 0 | "time\n"); |
182 | 0 | *status = NT_STATUS_BAD_NETWORK_NAME; |
183 | 0 | return NULL; |
184 | 0 | } |
185 | 0 | DBG_INFO("making a connection to [homes] service " |
186 | 0 | "created at session setup time\n"); |
187 | 0 | return make_connection_smb1(req, now, |
188 | 0 | session->homes_snum, |
189 | 0 | dev, status); |
190 | 0 | } else if ((session->homes_snum != -1) |
191 | 0 | && strequal(service_in, |
192 | 0 | lp_const_servicename(session->homes_snum))) { |
193 | 0 | DBG_INFO("making a connection to 'homes' service [%s] " |
194 | 0 | "created at session setup time\n", |
195 | 0 | service_in); |
196 | 0 | return make_connection_smb1(req, now, |
197 | 0 | session->homes_snum, |
198 | 0 | dev, status); |
199 | 0 | } |
200 | | |
201 | 0 | service = talloc_strdup(talloc_tos(), service_in); |
202 | 0 | if (!service) { |
203 | 0 | *status = NT_STATUS_NO_MEMORY; |
204 | 0 | return NULL; |
205 | 0 | } |
206 | | |
207 | 0 | if (!strlower_m(service)) { |
208 | 0 | DBG_NOTICE("strlower_m %s failed\n", service); |
209 | 0 | *status = NT_STATUS_INVALID_PARAMETER; |
210 | 0 | return NULL; |
211 | 0 | } |
212 | | |
213 | 0 | snum = find_service(talloc_tos(), service, &service); |
214 | 0 | if (!service) { |
215 | 0 | *status = NT_STATUS_NO_MEMORY; |
216 | 0 | return NULL; |
217 | 0 | } |
218 | | |
219 | 0 | if (snum < 0) { |
220 | 0 | if (strequal(service,"IPC$") || |
221 | 0 | (lp_enable_asu_support() && strequal(service,"ADMIN$"))) { |
222 | 0 | DBG_NOTICE("refusing IPC connection to %s\n", service); |
223 | 0 | *status = NT_STATUS_ACCESS_DENIED; |
224 | 0 | return NULL; |
225 | 0 | } |
226 | | |
227 | 0 | DBG_NOTICE("%s (%s) couldn't find service %s\n", |
228 | 0 | get_remote_machine_name(), |
229 | 0 | tsocket_address_string(sconn->remote_address, |
230 | 0 | talloc_tos()), |
231 | 0 | service); |
232 | 0 | *status = NT_STATUS_BAD_NETWORK_NAME; |
233 | 0 | return NULL; |
234 | 0 | } |
235 | | |
236 | | /* Handle non-Dfs clients attempting connections to msdfs proxy */ |
237 | 0 | if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) != '\0')) { |
238 | 0 | DBG_NOTICE("refusing connection to dfs proxy share '%s' " |
239 | 0 | "(pointing to %s)\n", |
240 | 0 | service, |
241 | 0 | lp_msdfs_proxy(talloc_tos(), lp_sub, snum)); |
242 | 0 | *status = NT_STATUS_BAD_NETWORK_NAME; |
243 | 0 | return NULL; |
244 | 0 | } |
245 | | |
246 | 0 | DBG_INFO("making a connection to 'normal' service %s\n", service); |
247 | |
|
248 | 0 | return make_connection_smb1(req, now, snum, |
249 | 0 | dev, status); |
250 | 0 | } |