Coverage Report

Created: 2026-07-25 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}