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