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.
25 #include "auth/auth.h"
29 setup the OS, Lanman and domain portions of a session setup reply
31 static void sesssetup_common_strings(struct smbsrv_request *req,
32 char **os, char **lanman, char **domain)
34 (*os) = talloc_asprintf(req, "Unix");
35 (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
36 (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
41 handler for old style session setup
43 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
46 struct auth_usersupplied_info *user_info = NULL;
47 struct auth_serversupplied_info *server_info = NULL;
48 struct auth_session_info *session_info;
50 TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
53 return NT_STATUS_NO_MEMORY;
56 if (!req->smb_conn->negotiate.done_sesssetup) {
57 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
60 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
61 status = make_user_info_for_reply_enc(req->smb_conn,
63 sess->old.in.user, sess->old.in.domain,
65 sess->old.in.password,
67 if (!NT_STATUS_IS_OK(status)) {
69 return NT_STATUS_ACCESS_DENIED;
72 status = req->smb_conn->negotiate.auth_context->check_ntlm_password(req->smb_conn->negotiate.auth_context,
76 if (!NT_STATUS_IS_OK(status)) {
78 return nt_status_squash(status);
81 /* This references server_info into session_info */
82 status = make_session_info(req, server_info, &session_info);
84 if (!NT_STATUS_IS_OK(status)) {
85 return nt_status_squash(status);
88 sess->old.out.action = 0;
89 sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
90 if (sess->old.out.vuid == UID_FIELD_INVALID) {
91 return NT_STATUS_ACCESS_DENIED;
93 sesssetup_common_strings(req,
95 &sess->old.out.lanman,
96 &sess->old.out.domain);
98 req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
105 handler for NT1 style session setup
107 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
110 struct auth_usersupplied_info *user_info = NULL;
111 struct auth_serversupplied_info *server_info = NULL;
112 struct auth_session_info *session_info;
113 TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
116 return NT_STATUS_NO_MEMORY;
119 if (!req->smb_conn->negotiate.done_sesssetup) {
120 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
121 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
124 if (req->smb_conn->negotiate.spnego_negotiated) {
125 struct auth_context *auth_context;
127 if (sess->nt1.in.user && *sess->nt1.in.user) {
128 return NT_STATUS_ACCESS_DENIED;
130 make_user_info_guest(req->smb_conn, &user_info);
133 status = make_auth_context_subsystem(req->smb_conn, &auth_context);
135 if (!NT_STATUS_IS_OK(status)) {
136 talloc_free(mem_ctx);
140 status = auth_context->check_ntlm_password(auth_context,
145 char *remote_machine;
146 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
147 status = make_user_info_for_reply_enc(req->smb_conn,
149 sess->nt1.in.user, sess->nt1.in.domain,
151 sess->nt1.in.password1,
152 sess->nt1.in.password2);
153 if (!NT_STATUS_IS_OK(status)) {
154 talloc_free(mem_ctx);
155 return NT_STATUS_ACCESS_DENIED;
158 status = req->smb_conn->negotiate
159 .auth_context->check_ntlm_password(req->smb_conn->negotiate
166 if (!NT_STATUS_IS_OK(status)) {
167 talloc_free(mem_ctx);
168 return nt_status_squash(status);
171 /* This references server_info into session_info */
172 status = make_session_info(mem_ctx, server_info, &session_info);
173 if (!NT_STATUS_IS_OK(status)) {
174 talloc_free(mem_ctx);
175 return nt_status_squash(status);
178 sess->nt1.out.action = 0;
179 sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
180 talloc_free(mem_ctx);
181 if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
182 return NT_STATUS_ACCESS_DENIED;
184 sesssetup_common_strings(req,
186 &sess->nt1.out.lanman,
187 &sess->nt1.out.domain);
189 req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
190 if (session_info->server_info->guest) {
193 if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
194 /* Already signing, or disabled */
198 /* Force check of the request packet, now we know the session key */
199 req_signing_check_incoming(req);
201 srv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2);
208 handler for SPNEGO style session setup
210 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
212 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
213 struct smbsrv_session *smb_sess;
214 struct gensec_security *gensec_ctx = NULL;
215 struct auth_session_info *session_info = NULL;
218 if (!req->smb_conn->negotiate.done_sesssetup) {
219 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
220 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
223 vuid = SVAL(req->in.hdr,HDR_UID);
224 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
225 if (smb_sess && !smb_sess->session_info) {
226 if (!smb_sess->gensec_ctx) {
227 return NT_STATUS_INVALID_HANDLE;
230 status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
234 status = gensec_server_start(req->smb_conn, &gensec_ctx);
235 if (!NT_STATUS_IS_OK(status)) {
236 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
240 gensec_want_feature(gensec_ctx, GENSEC_WANT_SESSION_KEY);
242 status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO);
243 if (!NT_STATUS_IS_OK(status)) {
244 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
248 status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
253 vuid = smbsrv_register_session(req->smb_conn,
254 session_info, gensec_ctx);
255 if (vuid == UID_FIELD_INVALID) {
256 return NT_STATUS_ACCESS_DENIED;
258 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
260 return NT_STATUS_FOOBAR;
264 if (NT_STATUS_IS_OK(status)) {
265 DATA_BLOB session_key;
267 status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
268 if (!NT_STATUS_IS_OK(status)) {
272 status = gensec_session_key(smb_sess->gensec_ctx,
274 if (NT_STATUS_IS_OK(status)
275 && !smb_sess->session_info->server_info->guest
276 && srv_setup_signing(req->smb_conn, &session_key, NULL)) {
277 /* Force check of the request packet, now we know the session key */
278 req_signing_check_incoming(req);
280 srv_signing_restart(req->smb_conn, &session_key, NULL);
284 status = nt_status_squash(status);
285 if (smb_sess->gensec_ctx &&
286 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
287 gensec_end(&smb_sess->gensec_ctx);
291 sess->spnego.out.action = 0;
292 sess->spnego.out.vuid = vuid;
293 sesssetup_common_strings(req,
294 &sess->spnego.out.os,
295 &sess->spnego.out.lanman,
296 &sess->spnego.out.domain);
302 backend for sessionsetup call - this takes all 3 variants of the call
304 NTSTATUS sesssetup_backend(struct smbsrv_request *req,
305 union smb_sesssetup *sess)
307 NTSTATUS status = NT_STATUS_INVALID_LEVEL;
309 switch (sess->generic.level) {
310 case RAW_SESSSETUP_GENERIC:
311 status = NT_STATUS_INVALID_LEVEL;
313 case RAW_SESSSETUP_OLD:
314 status = sesssetup_old(req, sess);
316 case RAW_SESSSETUP_NT1:
317 status = sesssetup_nt1(req, sess);
319 case RAW_SESSSETUP_SPNEGO:
320 status = sesssetup_spnego(req, sess);
324 if (NT_STATUS_IS_OK(status)) {
325 req->smb_conn->negotiate.done_sesssetup = True;