~zulcss/samba/server-dailies-3.4

« back to all changes in this revision

Viewing changes to source4/smb_server/smb_server.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:38:39 UTC
  • Revision ID: zulcss@ubuntu.com-20100928203839-pgjulytsi9ue63x1
Initial version

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Unix SMB/CIFS implementation.
 
3
   process incoming packets - main loop
 
4
   Copyright (C) Andrew Tridgell        2004-2005
 
5
   Copyright (C) Stefan Metzmacher      2004-2005
 
6
   
 
7
   This program is free software; you can redistribute it and/or modify
 
8
   it under the terms of the GNU General Public License as published by
 
9
   the Free Software Foundation; either version 3 of the License, or
 
10
   (at your option) any later version.
 
11
   
 
12
   This program is distributed in the hope that it will be useful,
 
13
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
   GNU General Public License for more details.
 
16
   
 
17
   You should have received a copy of the GNU General Public License
 
18
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
19
*/
 
20
 
 
21
#include "includes.h"
 
22
#include "smbd/service_task.h"
 
23
#include "smbd/service_stream.h"
 
24
#include "smbd/service.h"
 
25
#include "smb_server/smb_server.h"
 
26
#include "smb_server/service_smb_proto.h"
 
27
#include "lib/messaging/irpc.h"
 
28
#include "lib/stream/packet.h"
 
29
#include "libcli/smb2/smb2.h"
 
30
#include "smb_server/smb2/smb2_server.h"
 
31
#include "system/network.h"
 
32
#include "lib/socket/netif.h"
 
33
#include "param/share.h"
 
34
#include "dsdb/samdb/samdb.h"
 
35
#include "param/param.h"
 
36
 
 
37
static NTSTATUS smbsrv_recv_generic_request(void *private_data, DATA_BLOB blob)
 
38
{
 
39
        NTSTATUS status;
 
40
        struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection);
 
41
        uint32_t protocol_version;
 
42
 
 
43
        /* see if its a special NBT packet */
 
44
        if (CVAL(blob.data,0) != 0) {
 
45
                status = smbsrv_init_smb_connection(smb_conn, smb_conn->lp_ctx);
 
46
                NT_STATUS_NOT_OK_RETURN(status);
 
47
                packet_set_callback(smb_conn->packet, smbsrv_recv_smb_request);
 
48
                return smbsrv_recv_smb_request(smb_conn, blob);
 
49
        }
 
50
 
 
51
        if (blob.length < (NBT_HDR_SIZE + MIN_SMB_SIZE)) {
 
52
                DEBUG(2,("Invalid SMB packet length count %ld\n", (long)blob.length));
 
53
                smbsrv_terminate_connection(smb_conn, "Invalid SMB packet");
 
54
                return NT_STATUS_OK;
 
55
        }
 
56
 
 
57
        protocol_version = IVAL(blob.data, NBT_HDR_SIZE);
 
58
 
 
59
        switch (protocol_version) {
 
60
        case SMB_MAGIC:
 
61
                status = smbsrv_init_smb_connection(smb_conn, smb_conn->lp_ctx);
 
62
                NT_STATUS_NOT_OK_RETURN(status);
 
63
                packet_set_callback(smb_conn->packet, smbsrv_recv_smb_request);
 
64
                return smbsrv_recv_smb_request(smb_conn, blob);
 
65
        case SMB2_MAGIC:
 
66
                if (lp_srv_maxprotocol(smb_conn->lp_ctx) < PROTOCOL_SMB2) break;
 
67
                status = smbsrv_init_smb2_connection(smb_conn);
 
68
                NT_STATUS_NOT_OK_RETURN(status);
 
69
                packet_set_callback(smb_conn->packet, smbsrv_recv_smb2_request);
 
70
                return smbsrv_recv_smb2_request(smb_conn, blob);
 
71
        }
 
72
 
 
73
        DEBUG(2,("Invalid SMB packet: protocol prefix: 0x%08X\n", protocol_version));
 
74
        smbsrv_terminate_connection(smb_conn, "NON-SMB packet");
 
75
        return NT_STATUS_OK;
 
76
}
 
77
 
 
78
/*
 
79
  close the socket and shutdown a server_context
 
80
*/
 
81
void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason)
 
82
{
 
83
        stream_terminate_connection(smb_conn->connection, reason);
 
84
}
 
85
 
 
86
/*
 
87
  called when a SMB socket becomes readable
 
88
*/
 
89
static void smbsrv_recv(struct stream_connection *conn, uint16_t flags)
 
90
{
 
91
        struct smbsrv_connection *smb_conn = talloc_get_type(conn->private_data,
 
92
                                                             struct smbsrv_connection);
 
93
 
 
94
        DEBUG(10,("smbsrv_recv\n"));
 
95
 
 
96
        packet_recv(smb_conn->packet);
 
97
}
 
98
 
 
99
/*
 
100
  called when a SMB socket becomes writable
 
101
*/
 
102
static void smbsrv_send(struct stream_connection *conn, uint16_t flags)
 
103
{
 
104
        struct smbsrv_connection *smb_conn = talloc_get_type(conn->private_data,
 
105
                                                             struct smbsrv_connection);
 
106
        packet_queue_run(smb_conn->packet);
 
107
}
 
108
 
 
109
/*
 
110
  handle socket recv errors
 
111
*/
 
112
static void smbsrv_recv_error(void *private_data, NTSTATUS status)
 
113
{
 
114
        struct smbsrv_connection *smb_conn = talloc_get_type(private_data, struct smbsrv_connection);
 
115
        
 
116
        smbsrv_terminate_connection(smb_conn, nt_errstr(status));
 
117
}
 
118
 
 
119
/*
 
120
  initialise a server_context from a open socket and register a event handler
 
121
  for reading from that socket
 
122
*/
 
123
static void smbsrv_accept(struct stream_connection *conn)
 
124
{
 
125
        struct smbsrv_connection *smb_conn;
 
126
 
 
127
        DEBUG(5,("smbsrv_accept\n"));
 
128
 
 
129
        smb_conn = talloc_zero(conn, struct smbsrv_connection);
 
130
        if (!smb_conn) {
 
131
                stream_terminate_connection(conn, "out of memory");
 
132
                return;
 
133
        }
 
134
 
 
135
        smb_conn->packet = packet_init(smb_conn);
 
136
        if (!smb_conn->packet) {
 
137
                smbsrv_terminate_connection(smb_conn, "out of memory");
 
138
                return;
 
139
        }
 
140
        packet_set_private(smb_conn->packet, smb_conn);
 
141
        packet_set_socket(smb_conn->packet, conn->socket);
 
142
        packet_set_callback(smb_conn->packet, smbsrv_recv_generic_request);
 
143
        packet_set_full_request(smb_conn->packet, packet_full_request_nbt);
 
144
        packet_set_error_handler(smb_conn->packet, smbsrv_recv_error);
 
145
        packet_set_event_context(smb_conn->packet, conn->event.ctx);
 
146
        packet_set_fde(smb_conn->packet, conn->event.fde);
 
147
        packet_set_serialise(smb_conn->packet);
 
148
 
 
149
        smb_conn->lp_ctx = conn->lp_ctx;
 
150
        smb_conn->connection = conn;
 
151
        conn->private_data = smb_conn;
 
152
 
 
153
        smb_conn->statistics.connect_time = timeval_current();
 
154
 
 
155
        smbsrv_management_init(smb_conn);
 
156
 
 
157
        irpc_add_name(conn->msg_ctx, "smb_server");
 
158
 
 
159
        if (!NT_STATUS_IS_OK(share_get_context_by_name(smb_conn, lp_share_backend(smb_conn->lp_ctx), 
 
160
                                                       smb_conn->connection->event.ctx,
 
161
                                                       smb_conn->lp_ctx, &(smb_conn->share_context)))) {
 
162
                smbsrv_terminate_connection(smb_conn, "share_init failed!");
 
163
                return;
 
164
        }
 
165
}
 
166
 
 
167
static const struct stream_server_ops smb_stream_ops = {
 
168
        .name                   = "smbsrv",
 
169
        .accept_connection      = smbsrv_accept,
 
170
        .recv_handler           = smbsrv_recv,
 
171
        .send_handler           = smbsrv_send,
 
172
};
 
173
 
 
174
/*
 
175
  setup a listening socket on all the SMB ports for a particular address
 
176
*/
 
177
_PUBLIC_ NTSTATUS smbsrv_add_socket(struct tevent_context *event_context,
 
178
                                    struct loadparm_context *lp_ctx,
 
179
                               const struct model_ops *model_ops,
 
180
                               const char *address)
 
181
{
 
182
        const char **ports = lp_smb_ports(lp_ctx);
 
183
        int i;
 
184
        NTSTATUS status;
 
185
 
 
186
        for (i=0;ports[i];i++) {
 
187
                uint16_t port = atoi(ports[i]);
 
188
                if (port == 0) continue;
 
189
                status = stream_setup_socket(event_context, lp_ctx, 
 
190
                                             model_ops, &smb_stream_ops, 
 
191
                                             "ipv4", address, &port, 
 
192
                                             lp_socket_options(lp_ctx), 
 
193
                                             NULL);
 
194
                NT_STATUS_NOT_OK_RETURN(status);
 
195
        }
 
196
 
 
197
        return NT_STATUS_OK;
 
198
}
 
199
 
 
200
 
 
201
/*
 
202
  pre-open some of our ldb databases, to prevent an explosion of memory usage
 
203
  when we fork
 
204
 */
 
205
static void smbsrv_preopen_ldb(struct task_server *task)
 
206
{
 
207
        /* yes, this looks strange. It is a hack to preload the
 
208
           schema. I'd like to share most of the ldb context with the
 
209
           child too. That will come later */
 
210
        talloc_free(samdb_connect(task, task->event_ctx, task->lp_ctx, NULL));
 
211
}
 
212
 
 
213
/*
 
214
  open the smb server sockets
 
215
*/
 
216
static void smbsrv_task_init(struct task_server *task)
 
217
{       
 
218
        NTSTATUS status;
 
219
 
 
220
        task_server_set_title(task, "task[smbsrv]");
 
221
 
 
222
        if (lp_interfaces(task->lp_ctx) && lp_bind_interfaces_only(task->lp_ctx)) {
 
223
                int num_interfaces;
 
224
                int i;
 
225
                struct interface *ifaces;
 
226
 
 
227
                load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces);
 
228
 
 
229
                num_interfaces = iface_count(ifaces);
 
230
 
 
231
                /* We have been given an interfaces line, and been 
 
232
                   told to only bind to those interfaces. Create a
 
233
                   socket per interface and bind to only these.
 
234
                */
 
235
                for(i = 0; i < num_interfaces; i++) {
 
236
                        const char *address = iface_n_ip(ifaces, i);
 
237
                        status = smbsrv_add_socket(task->event_ctx, task->lp_ctx, task->model_ops, address);
 
238
                        if (!NT_STATUS_IS_OK(status)) goto failed;
 
239
                }
 
240
        } else {
 
241
                /* Just bind to lp_socket_address() (usually 0.0.0.0) */
 
242
                status = smbsrv_add_socket(task->event_ctx, task->lp_ctx, task->model_ops, 
 
243
                                           lp_socket_address(task->lp_ctx));
 
244
                if (!NT_STATUS_IS_OK(status)) goto failed;
 
245
        }
 
246
 
 
247
        smbsrv_preopen_ldb(task);
 
248
 
 
249
        return;
 
250
failed:
 
251
        task_server_terminate(task, "Failed to startup smb server task");       
 
252
}
 
253
 
 
254
/* called at smbd startup - register ourselves as a server service */
 
255
NTSTATUS server_service_smb_init(void)
 
256
{
 
257
        share_init();
 
258
        return register_server_service("smb", smbsrv_task_init);
 
259
}