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"
28 setup the OS, Lanman and domain portions of a session setup reply
30 static void sesssetup_common_strings(struct smbsrv_request *req,
31 char **os, char **lanman, char **domain)
33 (*os) = talloc_asprintf(req, "Unix");
34 (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
35 (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
40 handler for old style session setup
42 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
45 struct auth_usersupplied_info *user_info = NULL;
46 struct auth_serversupplied_info *server_info = NULL;
47 struct auth_session_info *session_info;
49 TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
52 return NT_STATUS_NO_MEMORY;
55 if (!req->smb_conn->negotiate.done_sesssetup) {
56 req->smb_conn->negotiate.max_send = sess->old.in.bufsize;
59 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
60 status = make_user_info_for_reply_enc(req->smb_conn,
62 sess->old.in.user, sess->old.in.domain,
64 sess->old.in.password,
66 if (!NT_STATUS_IS_OK(status)) {
68 return NT_STATUS_ACCESS_DENIED;
71 status = req->smb_conn->negotiate.auth_context->check_ntlm_password(req->smb_conn->negotiate.auth_context,
75 if (!NT_STATUS_IS_OK(status)) {
77 return nt_status_squash(status);
80 /* This references server_info into session_info */
81 status = make_session_info(req, server_info, &session_info);
83 if (!NT_STATUS_IS_OK(status)) {
84 return nt_status_squash(status);
87 sess->old.out.action = 0;
88 sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
89 if (sess->old.out.vuid == UID_FIELD_INVALID) {
90 return NT_STATUS_ACCESS_DENIED;
92 sesssetup_common_strings(req,
94 &sess->old.out.lanman,
95 &sess->old.out.domain);
97 req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
104 handler for NT1 style session setup
106 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
109 struct auth_usersupplied_info *user_info = NULL;
110 struct auth_serversupplied_info *server_info = NULL;
111 struct auth_session_info *session_info;
112 TALLOC_CTX *mem_ctx = talloc_named(req, 0, "NT1 session setup");
115 return NT_STATUS_NO_MEMORY;
118 if (!req->smb_conn->negotiate.done_sesssetup) {
119 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
120 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
123 if (req->smb_conn->negotiate.spnego_negotiated) {
124 struct auth_context *auth_context;
126 if (sess->nt1.in.user && *sess->nt1.in.user) {
127 return NT_STATUS_ACCESS_DENIED;
129 make_user_info_guest(req->smb_conn, &user_info);
132 status = make_auth_context_subsystem(req->smb_conn, &auth_context);
134 if (!NT_STATUS_IS_OK(status)) {
135 talloc_free(mem_ctx);
139 status = auth_context->check_ntlm_password(auth_context,
144 char *remote_machine;
145 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
146 status = make_user_info_for_reply_enc(req->smb_conn,
148 sess->nt1.in.user, sess->nt1.in.domain,
150 sess->nt1.in.password1,
151 sess->nt1.in.password2);
152 if (!NT_STATUS_IS_OK(status)) {
153 talloc_free(mem_ctx);
154 return NT_STATUS_ACCESS_DENIED;
157 status = req->smb_conn->negotiate
158 .auth_context->check_ntlm_password(req->smb_conn->negotiate
165 if (!NT_STATUS_IS_OK(status)) {
166 talloc_free(mem_ctx);
167 return nt_status_squash(status);
170 /* This references server_info into session_info */
171 status = make_session_info(mem_ctx, server_info, &session_info);
172 if (!NT_STATUS_IS_OK(status)) {
173 talloc_free(mem_ctx);
174 return nt_status_squash(status);
177 sess->nt1.out.action = 0;
178 sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
179 talloc_free(mem_ctx);
180 if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
181 return NT_STATUS_ACCESS_DENIED;
183 sesssetup_common_strings(req,
185 &sess->nt1.out.lanman,
186 &sess->nt1.out.domain);
188 req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
189 if (session_info->server_info->guest) {
192 if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
193 /* Already signing, or disabled */
197 /* Force check of the request packet, now we know the session key */
198 req_signing_check_incoming(req);
200 srv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2);
207 handler for SPNEGO style session setup
209 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
211 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
212 struct smbsrv_session *smb_sess;
213 struct gensec_security *gensec_ctx = NULL;
214 struct auth_session_info *session_info = NULL;
217 if (!req->smb_conn->negotiate.done_sesssetup) {
218 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
219 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
222 vuid = SVAL(req->in.hdr,HDR_UID);
223 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
224 if (smb_sess && !smb_sess->session_info) {
225 if (!smb_sess->gensec_ctx) {
226 return NT_STATUS_INVALID_HANDLE;
229 status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
233 status = gensec_server_start(req->smb_conn, &gensec_ctx);
234 if (!NT_STATUS_IS_OK(status)) {
235 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
239 gensec_want_feature(gensec_ctx, GENSEC_WANT_SESSION_KEY);
241 status = gensec_start_mech_by_oid(gensec_ctx, OID_SPNEGO);
242 if (!NT_STATUS_IS_OK(status)) {
243 DEBUG(1, ("Failed to start GENSEC SPNEGO server code: %s\n", nt_errstr(status)));
247 status = gensec_update(gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
252 vuid = smbsrv_register_session(req->smb_conn,
253 session_info, gensec_ctx);
254 if (vuid == UID_FIELD_INVALID) {
255 return NT_STATUS_ACCESS_DENIED;
257 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
259 return NT_STATUS_FOOBAR;
263 if (NT_STATUS_IS_OK(status)) {
264 DATA_BLOB session_key;
266 status = gensec_session_info(smb_sess->gensec_ctx, &smb_sess->session_info);
267 if (!NT_STATUS_IS_OK(status)) {
271 status = gensec_session_key(smb_sess->gensec_ctx,
273 if (NT_STATUS_IS_OK(status)
274 && !smb_sess->session_info->server_info->guest
275 && srv_setup_signing(req->smb_conn, &session_key, NULL)) {
276 /* Force check of the request packet, now we know the session key */
277 req_signing_check_incoming(req);
279 srv_signing_restart(req->smb_conn, &session_key, NULL);
283 status = nt_status_squash(status);
284 if (smb_sess->gensec_ctx &&
285 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
286 gensec_end(&smb_sess->gensec_ctx);
290 sess->spnego.out.action = 0;
291 sess->spnego.out.vuid = vuid;
292 sesssetup_common_strings(req,
293 &sess->spnego.out.os,
294 &sess->spnego.out.lanman,
295 &sess->spnego.out.domain);
301 backend for sessionsetup call - this takes all 3 variants of the call
303 NTSTATUS sesssetup_backend(struct smbsrv_request *req,
304 union smb_sesssetup *sess)
306 NTSTATUS status = NT_STATUS_INVALID_LEVEL;
308 switch (sess->generic.level) {
309 case RAW_SESSSETUP_GENERIC:
310 status = NT_STATUS_INVALID_LEVEL;
312 case RAW_SESSSETUP_OLD:
313 status = sesssetup_old(req, sess);
315 case RAW_SESSSETUP_NT1:
316 status = sesssetup_nt1(req, sess);
318 case RAW_SESSSETUP_SPNEGO:
319 status = sesssetup_spnego(req, sess);
323 if (NT_STATUS_IS_OK(status)) {
324 req->smb_conn->negotiate.done_sesssetup = True;