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"
26 #include "smb_server/smb_server.h"
30 setup the OS, Lanman and domain portions of a session setup reply
32 static void sesssetup_common_strings(struct smbsrv_request *req,
33 char **os, char **lanman, char **domain)
35 (*os) = talloc_asprintf(req, "Unix");
36 (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING);
37 (*domain) = talloc_asprintf(req, "%s", lp_workgroup());
42 handler for old style session setup
44 static NTSTATUS sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess)
47 struct auth_usersupplied_info *user_info = NULL;
48 struct auth_serversupplied_info *server_info = NULL;
49 struct auth_session_info *session_info;
53 mem_ctx = talloc_named(req, 0, "OLD session setup");
54 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
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,
62 sess->old.in.user, sess->old.in.domain,
64 sess->old.in.password,
67 if (!NT_STATUS_IS_OK(status)) {
69 return NT_STATUS_ACCESS_DENIED;
72 status = auth_check_password(req->smb_conn->negotiate.auth_context,
73 mem_ctx, user_info, &server_info);
74 if (!NT_STATUS_IS_OK(status)) {
76 return auth_nt_status_squash(status);
79 /* This references server_info into session_info */
80 status = auth_generate_session_info(req, server_info, &session_info);
82 if (!NT_STATUS_IS_OK(status)) {
83 return auth_nt_status_squash(status);
86 sess->old.out.action = 0;
87 sess->old.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
88 if (sess->old.out.vuid == UID_FIELD_INVALID) {
89 return NT_STATUS_ACCESS_DENIED;
91 sesssetup_common_strings(req,
93 &sess->old.out.lanman,
94 &sess->old.out.domain);
96 req->session = smbsrv_session_find(req->smb_conn, sess->old.out.vuid);
103 handler for NT1 style session setup
105 static NTSTATUS sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess)
108 struct auth_usersupplied_info *user_info = NULL;
109 struct auth_serversupplied_info *server_info = NULL;
110 struct auth_session_info *session_info;
113 mem_ctx = talloc_named(req, 0, "NT1 session setup");
114 NT_STATUS_HAVE_NO_MEMORY(mem_ctx);
116 if (!req->smb_conn->negotiate.done_sesssetup) {
117 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
118 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
121 if (req->smb_conn->negotiate.spnego_negotiated) {
122 struct auth_context *auth_context;
124 if (sess->nt1.in.user && *sess->nt1.in.user) {
125 return NT_STATUS_ACCESS_DENIED;
128 status = make_user_info_anonymous(req->smb_conn, &user_info);
129 if (!NT_STATUS_IS_OK(status)) {
130 talloc_free(mem_ctx);
134 /* TODO: should we use just "anonymous" here? */
135 status = auth_context_create(req->smb_conn, lp_auth_methods(), &auth_context);
136 if (!NT_STATUS_IS_OK(status)) {
137 talloc_free(mem_ctx);
141 status = auth_check_password(auth_context, mem_ctx,
142 user_info, &server_info);
144 char *remote_machine;
146 remote_machine = socket_get_peer_addr(req->smb_conn->connection->socket, mem_ctx);
148 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,
154 if (!NT_STATUS_IS_OK(status)) {
155 talloc_free(mem_ctx);
156 return NT_STATUS_ACCESS_DENIED;
159 status = auth_check_password(req->smb_conn->negotiate.auth_context,
160 req, user_info, &server_info);
163 if (!NT_STATUS_IS_OK(status)) {
164 talloc_free(mem_ctx);
165 return auth_nt_status_squash(status);
168 /* This references server_info into session_info */
169 status = auth_generate_session_info(mem_ctx, server_info, &session_info);
170 if (!NT_STATUS_IS_OK(status)) {
171 talloc_free(mem_ctx);
172 return auth_nt_status_squash(status);
175 sess->nt1.out.action = 0;
176 sess->nt1.out.vuid = smbsrv_register_session(req->smb_conn, session_info, NULL);
177 talloc_free(mem_ctx);
178 if (sess->nt1.out.vuid == UID_FIELD_INVALID) {
179 return NT_STATUS_ACCESS_DENIED;
181 sesssetup_common_strings(req,
183 &sess->nt1.out.lanman,
184 &sess->nt1.out.domain);
186 req->session = smbsrv_session_find(req->smb_conn, sess->nt1.out.vuid);
187 if (!session_info->server_info->authenticated) {
191 if (!srv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) {
192 /* Already signing, or disabled */
196 /* Force check of the request packet, now we know the session key */
197 req_signing_check_incoming(req);
199 srv_signing_restart(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2);
206 handler for SPNEGO style session setup
208 static NTSTATUS sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess)
210 NTSTATUS status = NT_STATUS_ACCESS_DENIED;
211 struct smbsrv_session *smb_sess;
212 struct gensec_security *gensec_ctx = NULL;
213 struct auth_session_info *session_info = NULL;
216 if (!req->smb_conn->negotiate.done_sesssetup) {
217 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize;
218 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities;
221 vuid = SVAL(req->in.hdr,HDR_UID);
222 smb_sess = smbsrv_session_find(req->smb_conn, vuid);
223 if (smb_sess && !smb_sess->session_info) {
224 if (!smb_sess->gensec_ctx) {
225 return NT_STATUS_INVALID_HANDLE;
228 status = gensec_update(smb_sess->gensec_ctx, req, sess->spnego.in.secblob, &sess->spnego.out.secblob);
232 status = gensec_server_start(req->smb_conn, &gensec_ctx);
233 if (!NT_STATUS_IS_OK(status)) {
234 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
238 gensec_set_target_service(gensec_ctx, "cifs");
240 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY);
242 status = gensec_start_mech_by_oid(gensec_ctx, GENSEC_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->authenticated
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 = auth_nt_status_squash(status);
285 if (smb_sess->gensec_ctx &&
286 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
287 talloc_free(smb_sess->gensec_ctx);
288 smb_sess->gensec_ctx = NULL;
292 sess->spnego.out.action = 0;
293 sess->spnego.out.vuid = vuid;
294 sesssetup_common_strings(req,
295 &sess->spnego.out.os,
296 &sess->spnego.out.lanman,
297 &sess->spnego.out.domain);
303 backend for sessionsetup call - this takes all 3 variants of the call
305 NTSTATUS sesssetup_backend(struct smbsrv_request *req,
306 union smb_sesssetup *sess)
308 NTSTATUS status = NT_STATUS_INVALID_LEVEL;
310 switch (sess->generic.level) {
311 case RAW_SESSSETUP_GENERIC:
312 status = NT_STATUS_INVALID_LEVEL;
314 case RAW_SESSSETUP_OLD:
315 status = sesssetup_old(req, sess);
317 case RAW_SESSSETUP_NT1:
318 status = sesssetup_nt1(req, sess);
320 case RAW_SESSSETUP_SPNEGO:
321 status = sesssetup_spnego(req, sess);
325 if (NT_STATUS_IS_OK(status)) {
326 req->smb_conn->negotiate.done_sesssetup = True;