+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbd_smb2_spnego_auth(struct smbd_smb2_session *session,
+ struct smbd_smb2_request *smb2req,
+ uint8_t in_security_mode,
+ DATA_BLOB in_security_buffer,
+ uint16_t *out_session_flags,
+ DATA_BLOB *out_security_buffer,
+ uint64_t *out_session_id)
+{
+ DATA_BLOB auth = data_blob_null;
+ DATA_BLOB auth_out = data_blob_null;
+ NTSTATUS status;
+
+ if (!spnego_parse_auth(talloc_tos(), in_security_buffer, &auth)) {
+ TALLOC_FREE(session);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ if (auth.data[0] == ASN1_APPLICATION(0)) {
+ /* Might be a second negTokenTarg packet */
+ DATA_BLOB secblob_in = data_blob_null;
+ char *kerb_mech = NULL;
+
+ status = parse_spnego_mechanisms(talloc_tos(),
+ in_security_buffer,
+ &secblob_in, &kerb_mech);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(session);
+ return status;
+ }
+
+#ifdef HAVE_KRB5
+ if (kerb_mech && ((lp_security()==SEC_ADS) ||
+ USE_KERBEROS_KEYTAB) ) {
+ status = smbd_smb2_session_setup_krb5(session,
+ smb2req,
+ in_security_mode,
+ &secblob_in,
+ kerb_mech,
+ out_session_flags,
+ out_security_buffer,
+ out_session_id);
+
+ data_blob_free(&secblob_in);
+ TALLOC_FREE(kerb_mech);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(session);
+ }
+ return status;
+ }
+#endif
+
+ /* Can't blunder into NTLMSSP auth if we have
+ * a krb5 ticket. */
+
+ if (kerb_mech) {
+ DEBUG(3,("smb2: network "
+ "misconfiguration, client sent us a "
+ "krb5 ticket and kerberos security "
+ "not enabled\n"));
+ TALLOC_FREE(session);
+ data_blob_free(&secblob_in);
+ TALLOC_FREE(kerb_mech);
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ data_blob_free(&secblob_in);
+ }
+
+ if (session->auth_ntlmssp_state == NULL) {
+ status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ data_blob_free(&auth);
+ TALLOC_FREE(session);
+ return status;
+ }
+ }
+
+ status = auth_ntlmssp_update(session->auth_ntlmssp_state,
+ auth,
+ &auth_out);
+ /* We need to call setup_ntlmssp_session_info() if status==NT_STATUS_OK,
+ or if status is anything except NT_STATUS_MORE_PROCESSING_REQUIRED,
+ as this can trigger map to guest. */
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ status = setup_ntlmssp_session_info(session, status);
+ }
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ TALLOC_FREE(session->auth_ntlmssp_state);
+ data_blob_free(&auth);
+ TALLOC_FREE(session);
+ return status;
+ }
+
+ data_blob_free(&auth);
+
+ *out_security_buffer = spnego_gen_auth_response(smb2req,
+ &auth_out, status, NULL);
+
+ if (out_security_buffer->data == NULL) {
+ TALLOC_FREE(session->auth_ntlmssp_state);
+ TALLOC_FREE(session);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ *out_session_id = session->vuid;
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ return NT_STATUS_MORE_PROCESSING_REQUIRED;
+ }
+
+ /* We're done - claim the session. */
+ return smbd_smb2_common_ntlmssp_auth_return(session,
+ smb2req,
+ in_security_mode,
+ in_security_buffer,
+ out_session_flags,
+ out_session_id);
+}
+
+static NTSTATUS smbd_smb2_raw_ntlmssp_auth(struct smbd_smb2_session *session,
+ struct smbd_smb2_request *smb2req,
+ uint8_t in_security_mode,
+ DATA_BLOB in_security_buffer,
+ uint16_t *out_session_flags,
+ DATA_BLOB *out_security_buffer,
+ uint64_t *out_session_id)
+{
+ NTSTATUS status;
+ DATA_BLOB secblob_out = data_blob_null;
+
+ if (session->auth_ntlmssp_state == NULL) {
+ status = auth_ntlmssp_start(&session->auth_ntlmssp_state);
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(session);
+ return status;
+ }
+ }
+
+ /* RAW NTLMSSP */
+ status = auth_ntlmssp_update(session->auth_ntlmssp_state,
+ in_security_buffer,
+ &secblob_out);
+
+ if (NT_STATUS_IS_OK(status) ||
+ NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ *out_security_buffer = data_blob_talloc(smb2req,
+ secblob_out.data,
+ secblob_out.length);
+ if (secblob_out.data && out_security_buffer->data == NULL) {
+ TALLOC_FREE(session->auth_ntlmssp_state);
+ TALLOC_FREE(session);
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
+ *out_session_id = session->vuid;
+ return status;
+ }
+
+ status = setup_ntlmssp_session_info(session, status);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(session->auth_ntlmssp_state);
+ TALLOC_FREE(session);
+ return status;
+ }
+ *out_session_id = session->vuid;
+
+ return smbd_smb2_common_ntlmssp_auth_return(session,
+ smb2req,
+ in_security_mode,
+ in_security_buffer,
+ out_session_flags,
+ out_session_id);
+}
+
+static NTSTATUS smbd_smb2_session_setup(struct smbd_smb2_request *smb2req,
+ uint64_t in_session_id,
+ uint8_t in_security_mode,
+ DATA_BLOB in_security_buffer,
+ uint16_t *out_session_flags,
+ DATA_BLOB *out_security_buffer,
+ uint64_t *out_session_id)
+{
+ struct smbd_smb2_session *session;
+
+ *out_session_flags = 0;
+ *out_session_id = 0;
+
+ if (in_session_id == 0) {
+ int id;
+
+ /* create a new session */
+ session = talloc_zero(smb2req->sconn, struct smbd_smb2_session);
+ if (session == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ session->status = NT_STATUS_MORE_PROCESSING_REQUIRED;
+ id = idr_get_new_random(smb2req->sconn->smb2.sessions.idtree,
+ session,
+ smb2req->sconn->smb2.sessions.limit);
+ if (id == -1) {
+ return NT_STATUS_INSUFFICIENT_RESOURCES;
+ }
+ session->vuid = id;
+
+ session->tcons.idtree = idr_init(session);
+ if (session->tcons.idtree == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ session->tcons.limit = 0x0000FFFE;
+ session->tcons.list = NULL;
+
+ DLIST_ADD_END(smb2req->sconn->smb2.sessions.list, session,
+ struct smbd_smb2_session *);
+ session->sconn = smb2req->sconn;
+ talloc_set_destructor(session, smbd_smb2_session_destructor);
+ } else {
+ void *p;
+
+ /* lookup an existing session */
+ p = idr_find(smb2req->sconn->smb2.sessions.idtree, in_session_id);
+ if (p == NULL) {
+ return NT_STATUS_USER_SESSION_DELETED;
+ }
+ session = talloc_get_type_abort(p, struct smbd_smb2_session);
+ }
+
+ if (NT_STATUS_IS_OK(session->status)) {
+ return NT_STATUS_REQUEST_NOT_ACCEPTED;
+ }
+
+ if (in_security_buffer.data[0] == ASN1_APPLICATION(0)) {
+ return smbd_smb2_spnego_negotiate(session,
+ smb2req,
+ in_security_mode,
+ in_security_buffer,
+ out_session_flags,
+ out_security_buffer,
+ out_session_id);
+ } else if (in_security_buffer.data[0] == ASN1_CONTEXT(1)) {
+ return smbd_smb2_spnego_auth(session,
+ smb2req,
+ in_security_mode,
+ in_security_buffer,
+ out_session_flags,
+ out_security_buffer,
+ out_session_id);
+ } else if (strncmp((char *)(in_security_buffer.data), "NTLMSSP", 7) == 0) {
+ return smbd_smb2_raw_ntlmssp_auth(session,
+ smb2req,
+ in_security_mode,
+ in_security_buffer,
+ out_session_flags,
+ out_security_buffer,
+ out_session_id);
+ }
+
+ /* Unknown packet type. */
+ DEBUG(1,("Unknown packet type %u in smb2 sessionsetup\n",
+ (unsigned int)in_security_buffer.data[0] ));
+ TALLOC_FREE(session->auth_ntlmssp_state);
+ TALLOC_FREE(session);
+ return NT_STATUS_LOGON_FAILURE;