2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 1998-2001
5 Copyright (C) Andrew Bartlett 2001
6 Copyright (C) Jim McDonough 2002
7 Copyright (C) Luke Howard 2003
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 setup the OS, Lanman and domain portions of a session setup reply
29 static void sesssetup_common_strings(struct smbsrv_request *req,
30 char **os, char **lanman, char **domain)
32 (*os) = talloc_asprintf(req, "Unix");
33 (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
34 (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
39 handler for old style session setup
41 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
44 struct auth_usersupplied_info *user_info = NULL;
45 struct auth_serversupplied_info *server_info = NULL;
46 struct auth_session_info *session_info;
48 TALLOC_CTX *mem_ctx = talloc_init("NT1 session setup");
51 return NT_STATUS_NO_MEMORY;
54 if (!req->smb_conn->negotiate.done_sesssetup) {
55 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
58 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
59 status = make_user_info_for_reply_enc(&user_info,
60 sess->old.in.user, sess->old.in.domain,
62 sess->old.in.password,
65 if (!NT_STATUS_IS_OK(status)) {
66 return NT_STATUS_ACCESS_DENIED;
69 status = req->smb_conn->negotiate.auth_context->check_ntlm_password(req->smb_conn->negotiate.auth_context,
72 if (!NT_STATUS_IS_OK(status)) {
73 return nt_status_squash(status);
76 status = make_session_info(server_info, &session_info);
77 if (!NT_STATUS_IS_OK(status)) {
78 return nt_status_squash(status);
81 sess->old.out.action = 0;
82 sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
83 if (sess->old.out.vuid == UID_FIELD_INVALID) {
84 return NT_STATUS_ACCESS_DENIED;
86 sesssetup_common_strings(req,
88 &sess->old.out.lanman,
89 &sess->old.out.domain);
91 req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
98 handler for NT1 style session setup
100 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
103 struct auth_usersupplied_info *user_info = NULL;
104 struct auth_serversupplied_info *server_info = NULL;
105 struct auth_session_info *session_info;
107 if (!req->smb_conn->negotiate.done_sesssetup) {
108 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
109 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
112 if (req->smb_conn->negotiate.spnego_negotiated) {
113 struct auth_context *auth_context;
115 if (sess->nt1.in.user && *sess->nt1.in.user) {
116 return NT_STATUS_ACCESS_DENIED;
118 make_user_info_guest(&user_info);
121 status = make_auth_context_subsystem(&auth_context);
123 if (!NT_STATUS_IS_OK(status)) {
127 status = auth_context->check_ntlm_password(auth_context,
131 free_auth_context(&auth_context);
134 TALLOC_CTX *mem_ctx = talloc_init("NT1 session setup");
135 char *remote_machine;
137 return NT_STATUS_NO_MEMORY;
139 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
140 status = make_user_info_for_reply_enc(&user_info,
141 sess->nt1.in.user, sess->nt1.in.domain,
143 sess->nt1.in.password1,
144 sess->nt1.in.password2);
145 talloc_free(mem_ctx);
146 if (!NT_STATUS_IS_OK(status)) {
147 return NT_STATUS_ACCESS_DENIED;
150 status = req->smb_conn->negotiate
151 .auth_context->check_ntlm_password(req->smb_conn->negotiate
157 if (!NT_STATUS_IS_OK(status)) {
158 return nt_status_squash(status);
161 status = make_session_info(server_info, &session_info);
162 if (!NT_STATUS_IS_OK(status)) {
163 return nt_status_squash(status);
166 sess->nt1.out.action = 0;
167 sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
168 if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
169 return NT_STATUS_ACCESS_DENIED;
171 sesssetup_common_strings(req,
173 &sess->nt1.out.lanman,
174 &sess->nt1.out.domain);
176 req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
177 if (session_info->server_info->guest) {
180 if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
181 /* Already signing, or disabled */
185 /* Force check of the request packet, now we know the session key */
186 req_signing_check_incoming(req);
188 srv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2);
195 handler for SPNEGO style session setup
197 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
199 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
200 struct smbsrv_session *smb_sess;
201 struct gensec_security *gensec_ctx = NULL;
202 struct auth_session_info *session_info = NULL;
205 if (!req->smb_conn->negotiate.done_sesssetup) {
206 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
207 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
210 vuid = SVAL(req->in.hdr,HDR_UID);
211 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
213 if (!smb_sess->gensec_ctx) {
214 return NT_STATUS_INVALID_HANDLE;
217 /* what is when the client is already successful authentificated? */
218 if (smb_sess->session_info) {
219 return NT_STATUS_ACCESS_DENIED;
222 status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
224 status = gensec_server_start(&gensec_ctx);
225 if (!NT_STATUS_IS_OK(status)) {
226 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
230 gensec_want_feature(gensec_ctx, GENSEC_WANT_SESSION_KEY);
232 status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO);
233 if (!NT_STATUS_IS_OK(status)) {
234 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
238 status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
243 vuid = smbsrv_register_session(req->smb_conn, session_info, gensec_ctx);
244 if (vuid == UID_FIELD_INVALID) {
245 return NT_STATUS_ACCESS_DENIED;
247 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
249 return NT_STATUS_FOOBAR;
253 if (NT_STATUS_IS_OK(status)) {
254 DATA_BLOB session_key;
256 status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
257 if (!NT_STATUS_IS_OK(status)) {
261 status = gensec_session_key(smb_sess->gensec_ctx,
263 if (NT_STATUS_IS_OK(status)
264 && !smb_sess->session_info->server_info->guest
265 && srv_setup_signing(req->smb_conn, &session_key, NULL)) {
266 /* Force check of the request packet, now we know the session key */
267 req_signing_check_incoming(req);
269 srv_signing_restart(req->smb_conn, &session_key, NULL);
273 status = nt_status_squash(status);
274 if (smb_sess->gensec_ctx &&
275 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
276 gensec_end(&smb_sess->gensec_ctx);
280 sess->spnego.out.action = 0;
281 sess->spnego.out.vuid = vuid;
282 sesssetup_common_strings(req,
283 &sess->spnego.out.os,
284 &sess->spnego.out.lanman,
285 &sess->spnego.out.domain);
291 backend for sessionsetup call - this takes all 3 variants of the call
293 NTSTATUS sesssetup_backend(struct smbsrv_request *req,
294 union smb_sesssetup *sess)
296 NTSTATUS status = NT_STATUS_INVALID_LEVEL;
298 switch (sess->generic.level) {
299 case RAW_SESSSETUP_GENERIC:
300 status = NT_STATUS_INVALID_LEVEL;
302 case RAW_SESSSETUP_OLD:
303 status = sesssetup_old(req, sess);
305 case RAW_SESSSETUP_NT1:
306 status = sesssetup_nt1(req, sess);
308 case RAW_SESSSETUP_SPNEGO:
309 status = sesssetup_spnego(req, sess);
313 if (NT_STATUS_IS_OK(status)) {
314 req->smb_conn->negotiate.done_sesssetup = True;