1 2/* 3 Unix SMB/CIFS implementation. 4 handle SMBsessionsetup 5 Copyright (C) Andrew Tridgell 1998-2001 6 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2001-2005 7 Copyright (C) Jim McDonough 2002 8 Copyright (C) Luke Howard 2003 9 Copyright (C) Stefan Metzmacher 2005 10 11 This program is free software; you can redistribute it and/or modify 12 it under the terms of the GNU General Public License as published by 13 the Free Software Foundation; either version 3 of the License, or 14 (at your option) any later version. 15 16 This program is distributed in the hope that it will be useful, 17 but WITHOUT ANY WARRANTY; without even the implied warranty of 18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 GNU General Public License for more details. 20 21 You should have received a copy of the GNU General Public License 22 along with this program. If not, see <http://www.gnu.org/licenses/>. 23*/ 24 25#include "includes.h" 26#include "version.h" 27#include "auth/gensec/gensec.h" 28#include "auth/auth.h" 29#include "smb_server/smb_server.h" 30#include "smbd/service_stream.h" 31#include "param/param.h" 32 33/* 34 setup the OS, Lanman and domain portions of a session setup reply 35*/ 36static void sesssetup_common_strings(struct smbsrv_request *req, 37 char **os, char **lanman, char **domain) 38{ 39 (*os) = talloc_asprintf(req, "Unix"); 40 (*lanman) = talloc_asprintf(req, "Samba %s", SAMBA_VERSION_STRING); 41 (*domain) = talloc_asprintf(req, "%s", 42 lp_workgroup(req->smb_conn->lp_ctx)); 43} 44 45static void smbsrv_sesssetup_backend_send(struct smbsrv_request *req, 46 union smb_sesssetup *sess, 47 NTSTATUS status) 48{ 49 if (NT_STATUS_IS_OK(status)) { 50 req->smb_conn->negotiate.done_sesssetup = true; 51 /* we need to keep the session long term */ 52 req->session = talloc_steal(req->smb_conn, req->session); 53 } 54 smbsrv_reply_sesssetup_send(req, sess, status); 55} 56 57static void sesssetup_old_send(struct auth_check_password_request *areq, 58 void *private_data) 59{ 60 struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request); 61 union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup); 62 struct auth_serversupplied_info *server_info = NULL; 63 struct auth_session_info *session_info; 64 struct smbsrv_session *smb_sess; 65 NTSTATUS status; 66 67 status = auth_check_password_recv(areq, req, &server_info); 68 if (!NT_STATUS_IS_OK(status)) goto failed; 69 70 /* This references server_info into session_info */ 71 status = auth_generate_session_info(req, req->smb_conn->connection->event.ctx, req->smb_conn->lp_ctx, 72 server_info, &session_info); 73 if (!NT_STATUS_IS_OK(status)) goto failed; 74 75 /* allocate a new session */ 76 smb_sess = smbsrv_session_new(req->smb_conn, req, NULL); 77 if (!smb_sess) { 78 status = NT_STATUS_INSUFFICIENT_RESOURCES; 79 goto failed; 80 } 81 82 /* Ensure this is marked as a 'real' vuid, not one 83 * simply valid for the session setup leg */ 84 status = smbsrv_session_sesssetup_finished(smb_sess, session_info); 85 if (!NT_STATUS_IS_OK(status)) goto failed; 86 87 /* To correctly process any AndX packet (like a tree connect) 88 * we need to fill in the session on the request here */ 89 req->session = smb_sess; 90 sess->old.out.vuid = smb_sess->vuid; 91 92failed: 93 status = auth_nt_status_squash(status); 94 smbsrv_sesssetup_backend_send(req, sess, status); 95} 96 97/* 98 handler for old style session setup 99*/ 100static void sesssetup_old(struct smbsrv_request *req, union smb_sesssetup *sess) 101{ 102 struct auth_usersupplied_info *user_info = NULL; 103 struct socket_address *remote_address; 104 const char *remote_machine = NULL; 105 106 sess->old.out.vuid = 0; 107 sess->old.out.action = 0; 108 109 sesssetup_common_strings(req, 110 &sess->old.out.os, 111 &sess->old.out.lanman, 112 &sess->old.out.domain); 113 114 if (!req->smb_conn->negotiate.done_sesssetup) { 115 req->smb_conn->negotiate.max_send = sess->old.in.bufsize; 116 } 117 118 if (req->smb_conn->negotiate.calling_name) { 119 remote_machine = req->smb_conn->negotiate.calling_name->name; 120 } 121 122 remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req); 123 if (!remote_address) goto nomem; 124 125 if (!remote_machine) { 126 remote_machine = remote_address->addr; 127 } 128 129 user_info = talloc(req, struct auth_usersupplied_info); 130 if (!user_info) goto nomem; 131 132 user_info->mapped_state = false; 133 user_info->logon_parameters = 0; 134 user_info->flags = 0; 135 user_info->client.account_name = sess->old.in.user; 136 user_info->client.domain_name = sess->old.in.domain; 137 user_info->workstation_name = remote_machine; 138 user_info->remote_host = talloc_steal(user_info, remote_address); 139 140 user_info->password_state = AUTH_PASSWORD_RESPONSE; 141 user_info->password.response.lanman = sess->old.in.password; 142 user_info->password.response.lanman.data = talloc_steal(user_info, sess->old.in.password.data); 143 user_info->password.response.nt = data_blob(NULL, 0); 144 145 auth_check_password_send(req->smb_conn->negotiate.auth_context, user_info, 146 sesssetup_old_send, req); 147 return; 148 149nomem: 150 smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_NO_MEMORY); 151} 152 153static void sesssetup_nt1_send(struct auth_check_password_request *areq, 154 void *private_data) 155{ 156 struct smbsrv_request *req = talloc_get_type(private_data, struct smbsrv_request); 157 union smb_sesssetup *sess = talloc_get_type(req->io_ptr, union smb_sesssetup); 158 struct auth_serversupplied_info *server_info = NULL; 159 struct auth_session_info *session_info; 160 struct smbsrv_session *smb_sess; 161 NTSTATUS status; 162 163 status = auth_check_password_recv(areq, req, &server_info); 164 if (!NT_STATUS_IS_OK(status)) goto failed; 165 166 /* This references server_info into session_info */ 167 status = auth_generate_session_info(req, req->smb_conn->connection->event.ctx, 168 req->smb_conn->lp_ctx, 169 server_info, &session_info); 170 if (!NT_STATUS_IS_OK(status)) goto failed; 171 172 /* allocate a new session */ 173 smb_sess = smbsrv_session_new(req->smb_conn, req, NULL); 174 if (!smb_sess) { 175 status = NT_STATUS_INSUFFICIENT_RESOURCES; 176 goto failed; 177 } 178 179 /* Ensure this is marked as a 'real' vuid, not one 180 * simply valid for the session setup leg */ 181 status = smbsrv_session_sesssetup_finished(smb_sess, session_info); 182 if (!NT_STATUS_IS_OK(status)) goto failed; 183 184 /* To correctly process any AndX packet (like a tree connect) 185 * we need to fill in the session on the request here */ 186 req->session = smb_sess; 187 sess->nt1.out.vuid = smb_sess->vuid; 188 189 if (!smbsrv_setup_signing(req->smb_conn, &session_info->session_key, &sess->nt1.in.password2)) { 190 /* Already signing, or disabled */ 191 goto done; 192 } 193 194done: 195 status = NT_STATUS_OK; 196failed: 197 status = auth_nt_status_squash(status); 198 smbsrv_sesssetup_backend_send(req, sess, status); 199} 200 201/* 202 handler for NT1 style session setup 203*/ 204static void sesssetup_nt1(struct smbsrv_request *req, union smb_sesssetup *sess) 205{ 206 NTSTATUS status; 207 struct auth_context *auth_context; 208 struct auth_usersupplied_info *user_info = NULL; 209 struct socket_address *remote_address; 210 const char *remote_machine = NULL; 211 212 sess->nt1.out.vuid = 0; 213 sess->nt1.out.action = 0; 214 215 sesssetup_common_strings(req, 216 &sess->nt1.out.os, 217 &sess->nt1.out.lanman, 218 &sess->nt1.out.domain); 219 220 if (!req->smb_conn->negotiate.done_sesssetup) { 221 req->smb_conn->negotiate.max_send = sess->nt1.in.bufsize; 222 req->smb_conn->negotiate.client_caps = sess->nt1.in.capabilities; 223 } 224 225 if (req->smb_conn->negotiate.oid) { 226 if (sess->nt1.in.user && *sess->nt1.in.user) { 227 /* We can't accept a normal login, because we 228 * don't have a challenge */ 229 status = NT_STATUS_LOGON_FAILURE; 230 goto failed; 231 } 232 233 /* TODO: should we use just "anonymous" here? */ 234 status = auth_context_create(req, 235 req->smb_conn->connection->event.ctx, 236 req->smb_conn->connection->msg_ctx, 237 req->smb_conn->lp_ctx, 238 &auth_context); 239 if (!NT_STATUS_IS_OK(status)) goto failed; 240 } else { 241 auth_context = req->smb_conn->negotiate.auth_context; 242 } 243 244 if (req->smb_conn->negotiate.calling_name) { 245 remote_machine = req->smb_conn->negotiate.calling_name->name; 246 } 247 248 remote_address = socket_get_peer_addr(req->smb_conn->connection->socket, req); 249 if (!remote_address) goto nomem; 250 251 if (!remote_machine) { 252 remote_machine = remote_address->addr; 253 } 254 255 user_info = talloc(req, struct auth_usersupplied_info); 256 if (!user_info) goto nomem; 257 258 user_info->mapped_state = false; 259 user_info->logon_parameters = 0; 260 user_info->flags = 0; 261 user_info->client.account_name = sess->nt1.in.user; 262 user_info->client.domain_name = sess->nt1.in.domain; 263 user_info->workstation_name = remote_machine; 264 user_info->remote_host = talloc_steal(user_info, remote_address); 265 266 user_info->password_state = AUTH_PASSWORD_RESPONSE; 267 user_info->password.response.lanman = sess->nt1.in.password1; 268 user_info->password.response.lanman.data = talloc_steal(user_info, sess->nt1.in.password1.data); 269 user_info->password.response.nt = sess->nt1.in.password2; 270 user_info->password.response.nt.data = talloc_steal(user_info, sess->nt1.in.password2.data); 271 272 auth_check_password_send(auth_context, user_info, 273 sesssetup_nt1_send, req); 274 return; 275 276nomem: 277 status = NT_STATUS_NO_MEMORY; 278failed: 279 status = auth_nt_status_squash(status); 280 smbsrv_sesssetup_backend_send(req, sess, status); 281} 282 283struct sesssetup_spnego_state { 284 struct smbsrv_request *req; 285 union smb_sesssetup *sess; 286 struct smbsrv_session *smb_sess; 287}; 288 289static void sesssetup_spnego_send(struct gensec_update_request *greq, void *private_data) 290{ 291 struct sesssetup_spnego_state *s = talloc_get_type(private_data, 292 struct sesssetup_spnego_state); 293 struct smbsrv_request *req = s->req; 294 union smb_sesssetup *sess = s->sess; 295 struct smbsrv_session *smb_sess = s->smb_sess; 296 struct auth_session_info *session_info = NULL; 297 NTSTATUS status; 298 NTSTATUS skey_status; 299 DATA_BLOB session_key; 300 301 status = gensec_update_recv(greq, req, &sess->spnego.out.secblob); 302 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 303 goto done; 304 } else if (!NT_STATUS_IS_OK(status)) { 305 goto failed; 306 } 307 308 status = gensec_session_info(smb_sess->gensec_ctx, &session_info); 309 if (!NT_STATUS_IS_OK(status)) goto failed; 310 311 skey_status = gensec_session_key(smb_sess->gensec_ctx, &session_key); 312 if (NT_STATUS_IS_OK(skey_status)) { 313 smbsrv_setup_signing(req->smb_conn, &session_key, NULL); 314 } 315 316 /* Ensure this is marked as a 'real' vuid, not one 317 * simply valid for the session setup leg */ 318 status = smbsrv_session_sesssetup_finished(smb_sess, session_info); 319 if (!NT_STATUS_IS_OK(status)) goto failed; 320 321 req->session = smb_sess; 322 323done: 324 sess->spnego.out.vuid = smb_sess->vuid; 325failed: 326 status = auth_nt_status_squash(status); 327 smbsrv_sesssetup_backend_send(req, sess, status); 328 if (!NT_STATUS_IS_OK(status) && 329 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { 330 talloc_free(smb_sess); 331 } 332} 333 334/* 335 handler for SPNEGO style session setup 336*/ 337static void sesssetup_spnego(struct smbsrv_request *req, union smb_sesssetup *sess) 338{ 339 NTSTATUS status; 340 struct smbsrv_session *smb_sess = NULL; 341 struct sesssetup_spnego_state *s = NULL; 342 uint16_t vuid; 343 344 sess->spnego.out.vuid = 0; 345 sess->spnego.out.action = 0; 346 347 sesssetup_common_strings(req, 348 &sess->spnego.out.os, 349 &sess->spnego.out.lanman, 350 &sess->spnego.out.workgroup); 351 352 if (!req->smb_conn->negotiate.done_sesssetup) { 353 req->smb_conn->negotiate.max_send = sess->spnego.in.bufsize; 354 req->smb_conn->negotiate.client_caps = sess->spnego.in.capabilities; 355 } 356 357 vuid = SVAL(req->in.hdr,HDR_UID); 358 359 /* lookup an existing session */ 360 smb_sess = smbsrv_session_find_sesssetup(req->smb_conn, vuid); 361 if (!smb_sess) { 362 struct gensec_security *gensec_ctx; 363 364 status = samba_server_gensec_start(req, 365 req->smb_conn->connection->event.ctx, 366 req->smb_conn->connection->msg_ctx, 367 req->smb_conn->lp_ctx, 368 req->smb_conn->negotiate.server_credentials, 369 "cifs", 370 &gensec_ctx); 371 if (!NT_STATUS_IS_OK(status)) { 372 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status))); 373 goto failed; 374 } 375 376 gensec_want_feature(gensec_ctx, GENSEC_FEATURE_SESSION_KEY); 377 378 status = gensec_start_mech_by_oid(gensec_ctx, req->smb_conn->negotiate.oid); 379 if (!NT_STATUS_IS_OK(status)) { 380 DEBUG(1, ("Failed to start GENSEC %s server code: %s\n", 381 gensec_get_name_by_oid(gensec_ctx, req->smb_conn->negotiate.oid), nt_errstr(status))); 382 goto failed; 383 } 384 385 /* allocate a new session */ 386 smb_sess = smbsrv_session_new(req->smb_conn, req->smb_conn, gensec_ctx); 387 if (!smb_sess) { 388 status = NT_STATUS_INSUFFICIENT_RESOURCES; 389 goto failed; 390 } 391 } 392 393 if (!smb_sess) { 394 status = NT_STATUS_ACCESS_DENIED; 395 goto failed; 396 } 397 398 if (!smb_sess->gensec_ctx) { 399 status = NT_STATUS_INTERNAL_ERROR; 400 DEBUG(1, ("Internal ERROR: no gensec_ctx on session: %s\n", nt_errstr(status))); 401 goto failed; 402 } 403 404 s = talloc(req, struct sesssetup_spnego_state); 405 if (!s) goto nomem; 406 s->req = req; 407 s->sess = sess; 408 s->smb_sess = smb_sess; 409 410 gensec_update_send(smb_sess->gensec_ctx, sess->spnego.in.secblob, 411 sesssetup_spnego_send, s); 412 return; 413 414nomem: 415 status = NT_STATUS_NO_MEMORY; 416failed: 417 talloc_free(smb_sess); 418 status = auth_nt_status_squash(status); 419 smbsrv_sesssetup_backend_send(req, sess, status); 420} 421 422/* 423 backend for sessionsetup call - this takes all 3 variants of the call 424*/ 425void smbsrv_sesssetup_backend(struct smbsrv_request *req, 426 union smb_sesssetup *sess) 427{ 428 switch (sess->old.level) { 429 case RAW_SESSSETUP_OLD: 430 sesssetup_old(req, sess); 431 return; 432 433 case RAW_SESSSETUP_NT1: 434 sesssetup_nt1(req, sess); 435 return; 436 437 case RAW_SESSSETUP_SPNEGO: 438 sesssetup_spnego(req, sess); 439 return; 440 441 case RAW_SESSSETUP_SMB2: 442 break; 443 } 444 445 smbsrv_sesssetup_backend_send(req, sess, NT_STATUS_INVALID_LEVEL); 446} 447