/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 | |
|
57 | 0 | session_global_id = req->session->global->session_global_id; |
58 | 0 | share_name = lp_servicename(talloc_tos(), lp_sub, snum); |
59 | 0 | if (share_name == NULL) { |
60 | 0 | *pstatus = NT_STATUS_NO_MEMORY; |
61 | 0 | return NULL; |
62 | 0 | } |
63 | | |
64 | 0 | if ((lp_max_connections(snum) > 0) |
65 | 0 | && (count_current_connections(lp_const_servicename(snum), true) >= |
66 | 0 | lp_max_connections(snum))) { |
67 | |
|
68 | 0 | DBG_WARNING("Max connections (%d) exceeded for [%s][%s]\n", |
69 | 0 | lp_max_connections(snum), |
70 | 0 | lp_const_servicename(snum), share_name); |
71 | 0 | TALLOC_FREE(share_name); |
72 | 0 | *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; |
73 | 0 | return NULL; |
74 | 0 | } |
75 | | |
76 | 0 | status = smb1srv_tcon_create(req->xconn, |
77 | 0 | session_global_id, |
78 | 0 | share_name, |
79 | 0 | now, &tcon); |
80 | 0 | if (!NT_STATUS_IS_OK(status)) { |
81 | 0 | DEBUG(0,("make_connection_smb1: Couldn't find free tcon for [%s] - %s\n", |
82 | 0 | share_name, nt_errstr(status))); |
83 | 0 | TALLOC_FREE(share_name); |
84 | 0 | *pstatus = status; |
85 | 0 | return NULL; |
86 | 0 | } |
87 | 0 | TALLOC_FREE(share_name); |
88 | |
|
89 | 0 | conn = conn_new(req->sconn); |
90 | 0 | if (!conn) { |
91 | 0 | TALLOC_FREE(tcon); |
92 | |
|
93 | 0 | DEBUG(0,("make_connection_smb1: Couldn't find free connection.\n")); |
94 | 0 | *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES; |
95 | 0 | return NULL; |
96 | 0 | } |
97 | | |
98 | 0 | conn->cnum = tcon->global->tcon_wire_id; |
99 | 0 | conn->tcon = tcon; |
100 | |
|
101 | 0 | *pstatus = make_connection_snum(req->xconn, |
102 | 0 | conn, |
103 | 0 | snum, |
104 | 0 | req->session, |
105 | 0 | pdev); |
106 | 0 | if (!NT_STATUS_IS_OK(*pstatus)) { |
107 | 0 | TALLOC_FREE(conn); |
108 | 0 | TALLOC_FREE(tcon); |
109 | 0 | return NULL; |
110 | 0 | } |
111 | | |
112 | 0 | tcon->compat = talloc_move(tcon, &conn); |
113 | 0 | tcon->status = NT_STATUS_OK; |
114 | |
|
115 | 0 | *pstatus = NT_STATUS_OK; |
116 | |
|
117 | 0 | return tcon->compat; |
118 | 0 | } |
119 | | |
120 | | /**************************************************************************** |
121 | | Make a connection to a service. External SMB1 interface. |
122 | | * |
123 | | * @param service |
124 | | ****************************************************************************/ |
125 | | |
126 | | connection_struct *make_connection(struct smb_request *req, |
127 | | NTTIME now, |
128 | | const char *service_in, |
129 | | const char *pdev, uint64_t vuid, |
130 | | NTSTATUS *status) |
131 | 0 | { |
132 | 0 | struct smbd_server_connection *sconn = req->sconn; |
133 | 0 | struct smbXsrv_session *session = req->session; |
134 | 0 | const struct loadparm_substitution *lp_sub = |
135 | 0 | loadparm_s3_global_substitution(); |
136 | 0 | uid_t euid; |
137 | 0 | char *service = NULL; |
138 | 0 | fstring dev; |
139 | 0 | int snum = -1; |
140 | |
|
141 | 0 | fstrcpy(dev, pdev); |
142 | | |
143 | | /* This must ONLY BE CALLED AS ROOT. As it exits this function as |
144 | | * root. */ |
145 | 0 | if (!non_root_mode() && (euid = geteuid()) != 0) { |
146 | 0 | DEBUG(0,("make_connection: PANIC ERROR. Called as nonroot " |
147 | 0 | "(%u)\n", (unsigned int)euid )); |
148 | 0 | smb_panic("make_connection: PANIC ERROR. Called as nonroot\n"); |
149 | 0 | } |
150 | | |
151 | 0 | if (conn_num_open(sconn) > 2047) { |
152 | 0 | *status = NT_STATUS_INSUFF_SERVER_RESOURCES; |
153 | 0 | return NULL; |
154 | 0 | } |
155 | | |
156 | 0 | if (session == NULL) { |
157 | 0 | DEBUG(1,("make_connection: refusing to connect with " |
158 | 0 | "no session setup\n")); |
159 | 0 | *status = NT_STATUS_ACCESS_DENIED; |
160 | 0 | return NULL; |
161 | 0 | } |
162 | | |
163 | | /* Logic to try and connect to the correct [homes] share, preferably |
164 | | without too many getpwnam() lookups. This is particularly nasty for |
165 | | winbind usernames, where the share name isn't the same as unix |
166 | | username. |
167 | | */ |
168 | | |
169 | 0 | if (strequal(service_in,HOMES_NAME)) { |
170 | 0 | if (session->homes_snum == -1) { |
171 | 0 | DEBUG(2, ("[homes] share not available for " |
172 | 0 | "this user because it was not found " |
173 | 0 | "or created at session setup " |
174 | 0 | "time\n")); |
175 | 0 | *status = NT_STATUS_BAD_NETWORK_NAME; |
176 | 0 | return NULL; |
177 | 0 | } |
178 | 0 | DEBUG(5, ("making a connection to [homes] service " |
179 | 0 | "created at session setup time\n")); |
180 | 0 | return make_connection_smb1(req, now, |
181 | 0 | session->homes_snum, |
182 | 0 | dev, status); |
183 | 0 | } else if ((session->homes_snum != -1) |
184 | 0 | && strequal(service_in, |
185 | 0 | lp_const_servicename(session->homes_snum))) { |
186 | 0 | DEBUG(5, ("making a connection to 'homes' service [%s] " |
187 | 0 | "created at session setup time\n", service_in)); |
188 | 0 | return make_connection_smb1(req, now, |
189 | 0 | session->homes_snum, |
190 | 0 | dev, status); |
191 | 0 | } |
192 | | |
193 | 0 | service = talloc_strdup(talloc_tos(), service_in); |
194 | 0 | if (!service) { |
195 | 0 | *status = NT_STATUS_NO_MEMORY; |
196 | 0 | return NULL; |
197 | 0 | } |
198 | | |
199 | 0 | if (!strlower_m(service)) { |
200 | 0 | DEBUG(2, ("strlower_m %s failed\n", service)); |
201 | 0 | *status = NT_STATUS_INVALID_PARAMETER; |
202 | 0 | return NULL; |
203 | 0 | } |
204 | | |
205 | 0 | snum = find_service(talloc_tos(), service, &service); |
206 | 0 | if (!service) { |
207 | 0 | *status = NT_STATUS_NO_MEMORY; |
208 | 0 | return NULL; |
209 | 0 | } |
210 | | |
211 | 0 | if (snum < 0) { |
212 | 0 | if (strequal(service,"IPC$") || |
213 | 0 | (lp_enable_asu_support() && strequal(service,"ADMIN$"))) { |
214 | 0 | DEBUG(3,("refusing IPC connection to %s\n", service)); |
215 | 0 | *status = NT_STATUS_ACCESS_DENIED; |
216 | 0 | return NULL; |
217 | 0 | } |
218 | | |
219 | 0 | DEBUG(3,("%s (%s) couldn't find service %s\n", |
220 | 0 | get_remote_machine_name(), |
221 | 0 | tsocket_address_string( |
222 | 0 | sconn->remote_address, talloc_tos()), |
223 | 0 | service)); |
224 | 0 | *status = NT_STATUS_BAD_NETWORK_NAME; |
225 | 0 | return NULL; |
226 | 0 | } |
227 | | |
228 | | /* Handle non-Dfs clients attempting connections to msdfs proxy */ |
229 | 0 | if (lp_host_msdfs() && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) != '\0')) { |
230 | 0 | DEBUG(3, ("refusing connection to dfs proxy share '%s' " |
231 | 0 | "(pointing to %s)\n", |
232 | 0 | service, lp_msdfs_proxy(talloc_tos(), lp_sub, snum))); |
233 | 0 | *status = NT_STATUS_BAD_NETWORK_NAME; |
234 | 0 | return NULL; |
235 | 0 | } |
236 | | |
237 | 0 | DEBUG(5, ("making a connection to 'normal' service %s\n", service)); |
238 | |
|
239 | 0 | return make_connection_smb1(req, now, snum, |
240 | 0 | dev, status); |
241 | 0 | } |