static void generic_blocking_lock_error(struct blocking_lock_record *blr, NTSTATUS status) { /* whenever a timeout is given w2k maps LOCK_NOT_GRANTED to FILE_LOCK_CONFLICT! (tridge) */ if (NT_STATUS_EQUAL(status, NT_STATUS_LOCK_NOT_GRANTED)) { status = NT_STATUS_FILE_LOCK_CONFLICT; } if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) { /* Store the last lock error. */ files_struct *fsp = blr->fsp; if (fsp) { fsp->last_lock_failure.context.smbpid = blr->lock_pid; fsp->last_lock_failure.context.tid = fsp->conn->cnum; fsp->last_lock_failure.context.pid = procid_self(); fsp->last_lock_failure.start = blr->offset; fsp->last_lock_failure.size = blr->count; fsp->last_lock_failure.fnum = fsp->fnum; fsp->last_lock_failure.lock_type = READ_LOCK; /* Don't care. */ fsp->last_lock_failure.lock_flav = blr->lock_flav; } } reply_nterror(blr->req, status); if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf, true, blr->req->seqnum+1, blr->req->encrypted, NULL)) { exit_server_cleanly("generic_blocking_lock_error: srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); }
static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status) { DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr)); switch(blr->req->cmd) { case SMBlockingX: reply_lockingX_error(blr, status); break; case SMBtrans2: case SMBtranss2: reply_nterror(blr->req, status); /* * construct_reply_common has done us the favor to pre-fill * the command field with SMBtranss2 which is wrong :-) */ SCVAL(blr->req->outbuf,smb_com,SMBtrans2); if (!srv_send_smb(smbd_server_fd(), (char *)blr->req->outbuf, true, blr->req->seqnum+1, IS_CONN_ENCRYPTED(blr->fsp->conn), NULL)) { exit_server_cleanly("blocking_lock_reply_error: " "srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); break; default: DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); exit_server("PANIC - unknown type on blocking lock queue"); } }
/* * this is the entry point if SMB2 is selected via * the SMB negprot and the given dialect. */ static void reply_smb20xx(struct smb_request *req, uint16_t dialect) { uint8_t *smb2_inpdu; uint8_t *smb2_hdr; uint8_t *smb2_body; uint8_t *smb2_dyn; size_t len = SMB2_HDR_BODY + 0x24 + 2; smb2_inpdu = talloc_zero_array(talloc_tos(), uint8_t, len); if (smb2_inpdu == NULL) { DEBUG(0, ("Could not push spnego blob\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } smb2_hdr = smb2_inpdu; smb2_body = smb2_hdr + SMB2_HDR_BODY; smb2_dyn = smb2_body + 0x24; SIVAL(smb2_hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); SIVAL(smb2_hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); SSVAL(smb2_body, 0x00, 0x0024); /* struct size */ SSVAL(smb2_body, 0x02, 0x0001); /* dialect count */ SSVAL(smb2_dyn, 0x00, dialect); req->outbuf = NULL; smbd_smb2_process_negprot(req->xconn, 0, smb2_inpdu, len); return; }
/* * this is the entry point if SMB2 is selected via * the SMB negprot */ void reply_smb2002(struct smb_request *req, uint16_t choice) { uint8_t *smb2_inbuf; uint8_t *smb2_hdr; uint8_t *smb2_body; uint8_t *smb2_dyn; size_t len = 4 + SMB2_HDR_BODY + 0x24 + 2; smb2_inbuf = talloc_zero_array(talloc_tos(), uint8_t, len); if (smb2_inbuf == NULL) { DEBUG(0, ("Could not push spnego blob\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } smb2_hdr = smb2_inbuf + 4; smb2_body = smb2_hdr + SMB2_HDR_BODY; smb2_dyn = smb2_body + 0x24; SIVAL(smb2_hdr, SMB2_HDR_PROTOCOL_ID, SMB2_MAGIC); SIVAL(smb2_hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY); SSVAL(smb2_body, 0x00, 0x0024); /* struct size */ SSVAL(smb2_body, 0x02, 0x0001); /* dialect count */ SSVAL(smb2_dyn, 0x00, 0x0202); /* dialect 2.002 */ req->outbuf = NULL; smbd_smb2_first_negprot(smbd_server_conn, smb2_inbuf, len); return; }
static void blocking_lock_reply_error(struct blocking_lock_record *blr, NTSTATUS status) { DEBUG(10, ("Replying with error=%s. BLR = %p\n", nt_errstr(status), blr)); switch(blr->req->cmd) { case SMBlockingX: /* * This code can be called during the rundown of a * file after it was already closed. In that case, * blr->fsp==NULL and we do not need to undo any * locks, they are already gone. */ if (blr->fsp != NULL) { undo_locks_obtained(blr); } generic_blocking_lock_error(blr, status); break; case SMBtrans2: case SMBtranss2: reply_nterror(blr->req, status); /* * construct_reply_common has done us the favor to pre-fill * the command field with SMBtranss2 which is wrong :-) */ SCVAL(blr->req->outbuf,smb_com,SMBtrans2); if (!srv_send_smb(blr->req->sconn, (char *)blr->req->outbuf, true, blr->req->seqnum+1, IS_CONN_ENCRYPTED(blr->fsp->conn), NULL)) { exit_server_cleanly("blocking_lock_reply_error: " "srv_send_smb failed."); } TALLOC_FREE(blr->req->outbuf); break; default: DEBUG(0,("blocking_lock_reply_error: PANIC - unknown type on blocking lock queue - exiting.!\n")); exit_server("PANIC - unknown type on blocking lock queue"); } }
void reply_pipe_write(struct smb_request *req) { smb_np_struct *p = get_rpc_pipe_p(SVAL(req->inbuf,smb_vwv0)); size_t numtowrite = SVAL(req->inbuf,smb_vwv1); int nwritten; char *data; if (!p) { reply_doserror(req, ERRDOS, ERRbadfid); return; } if (p->vuid != req->vuid) { reply_nterror(req, NT_STATUS_INVALID_HANDLE); return; } data = smb_buf(req->inbuf) + 3; if (numtowrite == 0) { nwritten = 0; } else { nwritten = write_to_pipe(p, data, numtowrite); } if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) { reply_unixerror(req, ERRDOS, ERRnoaccess); return; } reply_outbuf(req, 1, 0); SSVAL(req->outbuf,smb_vwv0,nwritten); DEBUG(3,("write-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten)); return; }
static void reply_sesssetup_and_X_spnego(struct smb_request *req) { const uint8_t *p; DATA_BLOB in_blob; DATA_BLOB out_blob = data_blob_null; size_t bufrem; char *tmp; const char *native_os; const char *native_lanman; const char *primary_domain; uint16_t data_blob_len = SVAL(req->vwv+7, 0); enum remote_arch_types ra_type = get_remote_arch(); uint64_t vuid = req->vuid; NTSTATUS status = NT_STATUS_OK; struct smbXsrv_connection *xconn = req->xconn; struct smbd_server_connection *sconn = req->sconn; uint16_t action = 0; bool is_authenticated = false; NTTIME now = timeval_to_nttime(&req->request_time); struct smbXsrv_session *session = NULL; uint16_t smb_bufsize = SVAL(req->vwv+2, 0); uint32_t client_caps = IVAL(req->vwv+10, 0); struct smbXsrv_session_auth0 *auth; DEBUG(3,("Doing spnego session setup\n")); if (!xconn->smb1.sessions.done_sesssetup) { global_client_caps = client_caps; if (!(global_client_caps & CAP_STATUS32)) { remove_from_common_flags2(FLAGS2_32_BIT_ERROR_CODES); } } p = req->buf; if (data_blob_len == 0) { /* an invalid request */ reply_nterror(req, nt_status_squash(NT_STATUS_LOGON_FAILURE)); return; } bufrem = smbreq_bufrem(req, p); /* pull the spnego blob */ in_blob = data_blob_const(p, MIN(bufrem, data_blob_len)); #if 0 file_save("negotiate.dat", in_blob.data, in_blob.length); #endif p = req->buf + in_blob.length; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_os = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); native_lanman = tmp ? tmp : ""; p += srvstr_pull_req_talloc(talloc_tos(), req, &tmp, p, STR_TERMINATE); primary_domain = tmp ? tmp : ""; DEBUG(3,("NativeOS=[%s] NativeLanMan=[%s] PrimaryDomain=[%s]\n", native_os, native_lanman, primary_domain)); if ( ra_type == RA_WIN2K ) { /* Vista sets neither the OS or lanman strings */ if ( !strlen(native_os) && !strlen(native_lanman) ) set_remote_arch(RA_VISTA); /* Windows 2003 doesn't set the native lanman string, but does set primary domain which is a bug I think */ if ( !strlen(native_lanman) ) { ra_lanman_string( primary_domain ); } else { ra_lanman_string( native_lanman ); } } else if ( ra_type == RA_VISTA ) { if ( strncmp(native_os, "Mac OS X", 8) == 0 ) { set_remote_arch(RA_OSX); } } if (vuid != 0) { status = smb1srv_session_lookup(xconn, vuid, now, &session); if (NT_STATUS_EQUAL(status, NT_STATUS_USER_SESSION_DELETED)) { reply_force_doserror(req, ERRSRV, ERRbaduid); return; } if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_SESSION_EXPIRED)) { status = NT_STATUS_OK; } if (NT_STATUS_IS_OK(status)) { session->status = NT_STATUS_MORE_PROCESSING_REQUIRED; status = NT_STATUS_MORE_PROCESSING_REQUIRED; TALLOC_FREE(session->pending_auth); } if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { reply_nterror(req, nt_status_squash(status)); return; } } if (session == NULL) { /* create a new session */ status = smbXsrv_session_create(xconn, now, &session); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } status = smbXsrv_session_find_auth(session, xconn, now, &auth); if (!NT_STATUS_IS_OK(status)) { status = smbXsrv_session_create_auth(session, xconn, now, 0, /* flags */ 0, /* security */ &auth); if (!NT_STATUS_IS_OK(status)) { reply_nterror(req, nt_status_squash(status)); return; } } if (auth->gensec == NULL) { status = auth_generic_prepare(session, xconn->remote_address, xconn->local_address, "SMB", &auth->gensec); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } gensec_want_feature(auth->gensec, GENSEC_FEATURE_SESSION_KEY); gensec_want_feature(auth->gensec, GENSEC_FEATURE_UNIX_TOKEN); gensec_want_feature(auth->gensec, GENSEC_FEATURE_SMB_TRANSPORT); status = gensec_start_mech_by_oid(auth->gensec, GENSEC_OID_SPNEGO); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to start SPNEGO handler!\n")); TALLOC_FREE(session);; reply_nterror(req, nt_status_squash(status)); return; } } become_root(); status = gensec_update(auth->gensec, talloc_tos(), in_blob, &out_blob); unbecome_root(); if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) { TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (NT_STATUS_IS_OK(status) && session->global->auth_session_info == NULL) { struct auth_session_info *session_info = NULL; status = gensec_session_info(auth->gensec, session, &session_info); if (!NT_STATUS_IS_OK(status)) { DEBUG(1,("Failed to generate session_info " "(user and group token) for session setup: %s\n", nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, nt_status_squash(status)); return; } if (security_session_user_level(session_info, NULL) == SECURITY_GUEST) { action |= SMB_SETUP_GUEST; } if (session_info->session_key.length > 0) { struct smbXsrv_session *x = session; /* * Note: the SMB1 signing key is not truncated to 16 byte! */ x->global->signing_key = data_blob_dup_talloc(x->global, session_info->session_key); if (x->global->signing_key.data == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } /* * clear the session key * the first tcon will add setup the application key */ data_blob_clear_free(&session_info->session_key); } session->compat = talloc_zero(session, struct user_struct); if (session->compat == NULL) { data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } session->compat->session = session; session->compat->homes_snum = -1; session->compat->session_info = session_info; session->compat->session_keystr = NULL; session->compat->vuid = session->global->session_wire_id; DLIST_ADD(sconn->users, session->compat); sconn->num_users++; if (security_session_user_level(session_info, NULL) >= SECURITY_USER) { is_authenticated = true; session->compat->homes_snum = register_homes_share(session_info->unix_info->unix_name); } if (srv_is_signing_negotiated(xconn) && is_authenticated && session->global->signing_key.length > 0) { /* * Try and turn on server signing on the first non-guest * sessionsetup. */ srv_set_signing(xconn, session->global->signing_key, data_blob_null); } set_current_user_info(session_info->unix_info->sanitized_username, session_info->unix_info->unix_name, session_info->info->domain_name); session->status = NT_STATUS_OK; session->global->auth_session_info = talloc_move(session->global, &session_info); session->global->auth_session_info_seqnum += 1; session->global->channels[0].auth_session_info_seqnum = session->global->auth_session_info_seqnum; session->global->auth_time = now; if (client_caps & CAP_DYNAMIC_REAUTH) { session->global->expiration_time = gensec_expire_time(auth->gensec); } else { session->global->expiration_time = GENSEC_EXPIRE_TIME_INFINITY; } if (!session_claim(session)) { DEBUG(1, ("smb1: Failed to claim session for vuid=%llu\n", (unsigned long long)session->compat->vuid)); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } status = smbXsrv_session_update(session); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("smb1: Failed to update session for vuid=%llu - %s\n", (unsigned long long)session->compat->vuid, nt_errstr(status))); data_blob_free(&out_blob); TALLOC_FREE(session); reply_nterror(req, NT_STATUS_LOGON_FAILURE); return; } if (!xconn->smb1.sessions.done_sesssetup) { if (smb_bufsize < SMB_BUFFER_SIZE_MIN) { reply_force_doserror(req, ERRSRV, ERRerror); return; } xconn->smb1.sessions.max_send = smb_bufsize; xconn->smb1.sessions.done_sesssetup = true; } /* current_user_info is changed on new vuid */ reload_services(sconn, conn_snum_used, true); } else if (NT_STATUS_IS_OK(status)) {
void reply_open_pipe_and_X(connection_struct *conn, struct smb_request *req) { const char *fname = NULL; char *pipe_name = NULL; files_struct *fsp; TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status; /* XXXX we need to handle passed times, sattr and flags */ srvstr_pull_req_talloc(ctx, req, &pipe_name, req->buf, STR_TERMINATE); if (!pipe_name) { reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpipe); return; } /* If the name doesn't start \PIPE\ then this is directed */ /* at a mailslot or something we really, really don't understand, */ /* not just something we really don't understand. */ if ( strncmp(pipe_name,PIPE,PIPELEN) != 0 ) { reply_doserror(req, ERRSRV, ERRaccess); return; } DEBUG(4,("Opening pipe %s.\n", pipe_name)); /* Strip \PIPE\ off the name. */ fname = pipe_name + PIPELEN; #if 0 /* * Hack for NT printers... JRA. */ if(should_fail_next_srvsvc_open(fname)) { reply_doserror(req, ERRSRV, ERRaccess); return; } #endif status = open_np_file(req, fname, &fsp); if (!NT_STATUS_IS_OK(status)) { if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { reply_botherror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND, ERRDOS, ERRbadpipe); return; } reply_nterror(req, status); return; } /* Prepare the reply */ reply_outbuf(req, 15, 0); /* Mark the opened file as an existing named pipe in message mode. */ SSVAL(req->outbuf,smb_vwv9,2); SSVAL(req->outbuf,smb_vwv10,0xc700); SSVAL(req->outbuf, smb_vwv2, fsp->fnum); SSVAL(req->outbuf, smb_vwv3, 0); /* fmode */ srv_put_dos_date3((char *)req->outbuf, smb_vwv4, 0); /* mtime */ SIVAL(req->outbuf, smb_vwv6, 0); /* size */ SSVAL(req->outbuf, smb_vwv8, 0); /* rmode */ SSVAL(req->outbuf, smb_vwv11, 0x0001); chain_reply(req); return; }
void reply_negprot(struct smb_request *req) { int choice= -1; int chosen_level = -1; int protocol; const char *p; int arch = ARCH_ALL; int num_cliprotos; char **cliprotos; int i; size_t converted_size; struct smbd_server_connection *sconn = req->sconn; START_PROFILE(SMBnegprot); if (sconn->smb1.negprot.done) { END_PROFILE(SMBnegprot); exit_server_cleanly("multiple negprot's are not permitted"); } sconn->smb1.negprot.done = true; if (req->buflen == 0) { DEBUG(0, ("negprot got no protocols\n")); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnegprot); return; } if (req->buf[req->buflen-1] != '\0') { DEBUG(0, ("negprot protocols not 0-terminated\n")); reply_nterror(req, NT_STATUS_INVALID_PARAMETER); END_PROFILE(SMBnegprot); return; } p = (const char *)req->buf + 1; num_cliprotos = 0; cliprotos = NULL; while (smbreq_bufrem(req, p) > 0) { char **tmp; tmp = talloc_realloc(talloc_tos(), cliprotos, char *, num_cliprotos+1); if (tmp == NULL) { DEBUG(0, ("talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnegprot); return; } cliprotos = tmp; if (!pull_ascii_talloc(cliprotos, &cliprotos[num_cliprotos], p, &converted_size)) { DEBUG(0, ("pull_ascii_talloc failed\n")); TALLOC_FREE(cliprotos); reply_nterror(req, NT_STATUS_NO_MEMORY); END_PROFILE(SMBnegprot); return; } DEBUG(3, ("Requested protocol [%s]\n", cliprotos[num_cliprotos])); num_cliprotos += 1; p += strlen(p) + 2; } for (i=0; i<num_cliprotos; i++) { if (strcsequal(cliprotos[i], "Windows for Workgroups 3.1a")) arch &= ( ARCH_WFWG | ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K ); else if (strcsequal(cliprotos[i], "DOS LM1.2X002")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(cliprotos[i], "DOS LANMAN2.1")) arch &= ( ARCH_WFWG | ARCH_WIN95 ); else if (strcsequal(cliprotos[i], "NT LM 0.12")) arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS); else if (strcsequal(cliprotos[i], "SMB 2.001")) arch = ARCH_VISTA; else if (strcsequal(cliprotos[i], "LANMAN2.1")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "LM1.2X002")) arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "MICROSOFT NETWORKS 1.03")) arch &= ARCH_WINNT; else if (strcsequal(cliprotos[i], "XENIX CORE")) arch &= ( ARCH_WINNT | ARCH_OS2 ); else if (strcsequal(cliprotos[i], "Samba")) { arch = ARCH_SAMBA; break; } else if (strcsequal(cliprotos[i], "POSIX 2")) { arch = ARCH_CIFSFS; break; } } /* CIFSFS can send one arch only, NT LM 0.12. */ if (i == 1 && (arch & ARCH_CIFSFS)) { arch = ARCH_CIFSFS; } switch ( arch ) { case ARCH_CIFSFS: set_remote_arch(RA_CIFSFS); break; case ARCH_SAMBA: set_remote_arch(RA_SAMBA); break; case ARCH_WFWG: set_remote_arch(RA_WFWG); break; case ARCH_WIN95: set_remote_arch(RA_WIN95); break; case ARCH_WINNT: if(req->flags2 == FLAGS2_WIN2K_SIGNATURE) set_remote_arch(RA_WIN2K); else set_remote_arch(RA_WINNT); break; case ARCH_WIN2K: /* Vista may have been set in the negprot so don't override it here */ if ( get_remote_arch() != RA_VISTA ) set_remote_arch(RA_WIN2K); break; case ARCH_VISTA: set_remote_arch(RA_VISTA); break; case ARCH_OS2: set_remote_arch(RA_OS2); break; default: set_remote_arch(RA_UNKNOWN); break; } /* possibly reload - change of architecture */ reload_services(sconn, conn_snum_used, true); /* moved from the netbios session setup code since we don't have that when the client connects to port 445. Of course there is a small window where we are listening to messages -- jerry */ serverid_register(messaging_server_id(sconn->msg_ctx), FLAG_MSG_GENERAL|FLAG_MSG_SMBD |FLAG_MSG_PRINT_GENERAL); /* Check for protocols, most desirable first */ for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) { i = 0; if ((supported_protocols[protocol].protocol_level <= lp_server_max_protocol()) && (supported_protocols[protocol].protocol_level >= lp_server_min_protocol())) while (i < num_cliprotos) { if (strequal(cliprotos[i],supported_protocols[protocol].proto_name)) { choice = i; chosen_level = supported_protocols[protocol].protocol_level; } i++; } if(choice != -1) break; } if(choice != -1) { fstrcpy(remote_proto,supported_protocols[protocol].short_name); reload_services(sconn, conn_snum_used, true); supported_protocols[protocol].proto_reply_fn(req, choice); DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); } else { DEBUG(0,("No protocol supported !\n")); reply_outbuf(req, 1, 0); SSVAL(req->outbuf, smb_vwv0, choice); } DEBUG( 5, ( "negprot index=%d\n", choice ) ); if ((lp_server_signing() == SMB_SIGNING_REQUIRED) && (chosen_level < PROTOCOL_NT1)) { exit_server_cleanly("SMB signing is required and " "client negotiated a downlevel protocol"); } TALLOC_FREE(cliprotos); if (lp_async_smb_echo_handler() && (chosen_level < PROTOCOL_SMB2_02) && !fork_echo_handler(sconn)) { exit_server("Failed to fork echo handler"); } END_PROFILE(SMBnegprot); return; }
static void reply_nt1(struct smb_request *req, uint16 choice) { /* dual names + lock_and_read + nt SMBs + remote API calls */ int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ| CAP_LEVEL_II_OPLOCKS; int secword=0; bool negotiate_spnego = False; struct timespec ts; ssize_t ret; struct smbd_server_connection *sconn = req->sconn; bool signing_enabled = false; bool signing_required = false; sconn->smb1.negprot.encrypted_passwords = lp_encrypt_passwords(); /* Check the flags field to see if this is Vista. WinXP sets it and Vista does not. But we have to distinguish from NT which doesn't set it either. */ if ( (req->flags2 & FLAGS2_EXTENDED_SECURITY) && ((req->flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED) == 0) ) { if (get_remote_arch() != RA_SAMBA) { set_remote_arch( RA_VISTA ); } } reply_outbuf(req,17,0); /* do spnego in user level security if the client supports it and we can do encrypted passwords */ if (sconn->smb1.negprot.encrypted_passwords && lp_use_spnego() && (req->flags2 & FLAGS2_EXTENDED_SECURITY)) { negotiate_spnego = True; capabilities |= CAP_EXTENDED_SECURITY; add_to_common_flags2(FLAGS2_EXTENDED_SECURITY); /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already partially constructed. */ SSVAL(req->outbuf, smb_flg2, req->flags2 | FLAGS2_EXTENDED_SECURITY); } capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS; if (lp_unicode()) { capabilities |= CAP_UNICODE; } if (lp_unix_extensions()) { capabilities |= CAP_UNIX; } if (lp_large_readwrite()) capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS; capabilities |= CAP_LARGE_FILES; if (!lp_async_smb_echo_handler() && lp_read_raw() && lp_write_raw()) capabilities |= CAP_RAW_MODE; if (lp_nt_status_support()) capabilities |= CAP_STATUS32; if (lp_host_msdfs()) capabilities |= CAP_DFS; secword |= NEGOTIATE_SECURITY_USER_LEVEL; if (sconn->smb1.negprot.encrypted_passwords) { secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE; } signing_enabled = smb_signing_is_allowed(req->sconn->smb1.signing_state); signing_required = smb_signing_is_mandatory(req->sconn->smb1.signing_state); if (signing_enabled) { secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED; /* No raw mode with smb signing. */ capabilities &= ~CAP_RAW_MODE; if (signing_required) { secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED; } } SSVAL(req->outbuf,smb_vwv0,choice); SCVAL(req->outbuf,smb_vwv1,secword); smbXsrv_connection_init_tables(req->sconn->conn, PROTOCOL_NT1); SSVAL(req->outbuf,smb_vwv1+1, lp_max_mux()); /* maxmpx */ SSVAL(req->outbuf,smb_vwv2+1, 1); /* num vcs */ SIVAL(req->outbuf,smb_vwv3+1, sconn->smb1.negprot.max_recv); /* max buffer. LOTS! */ SIVAL(req->outbuf,smb_vwv5+1, 0x10000); /* raw size. full 64k */ SIVAL(req->outbuf,smb_vwv7+1, getpid()); /* session key */ SIVAL(req->outbuf,smb_vwv9+1, capabilities); /* capabilities */ clock_gettime(CLOCK_REALTIME,&ts); put_long_date_timespec(TIMESTAMP_SET_NT_OR_BETTER,(char *)req->outbuf+smb_vwv11+1,ts); SSVALS(req->outbuf,smb_vwv15+1,set_server_zone_offset(ts.tv_sec)/60); if (!negotiate_spnego) { /* Create a token value and add it to the outgoing packet. */ if (sconn->smb1.negprot.encrypted_passwords) { uint8 chal[8]; /* note that we do not send a challenge at all if we are using plaintext */ get_challenge(sconn, chal); ret = message_push_blob( &req->outbuf, data_blob_const(chal, sizeof(chal))); if (ret == -1) { DEBUG(0, ("Could not push challenge\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } SCVAL(req->outbuf, smb_vwv16+1, ret); } ret = message_push_string(&req->outbuf, lp_workgroup(), STR_UNICODE|STR_TERMINATE |STR_NOALIGN); if (ret == -1) { DEBUG(0, ("Could not push workgroup string\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } ret = message_push_string(&req->outbuf, lp_netbios_name(), STR_UNICODE|STR_TERMINATE |STR_NOALIGN); if (ret == -1) { DEBUG(0, ("Could not push netbios name string\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } DEBUG(3,("not using SPNEGO\n")); } else { DATA_BLOB spnego_blob = negprot_spnego(req, req->sconn); if (spnego_blob.data == NULL) { reply_nterror(req, NT_STATUS_NO_MEMORY); return; } ret = message_push_blob(&req->outbuf, spnego_blob); if (ret == -1) { DEBUG(0, ("Could not push spnego blob\n")); reply_nterror(req, NT_STATUS_NO_MEMORY); return; } data_blob_free(&spnego_blob); SCVAL(req->outbuf,smb_vwv16+1, 0); DEBUG(3,("using SPNEGO\n")); } return; }
void reply_pipe_write_and_X(struct smb_request *req) { smb_np_struct *p = get_rpc_pipe_p(SVAL(req->inbuf,smb_vwv2)); size_t numtowrite = SVAL(req->inbuf,smb_vwv10); int nwritten = -1; int smb_doff = SVAL(req->inbuf, smb_vwv11); bool pipe_start_message_raw = ((SVAL(req->inbuf, smb_vwv7) & (PIPE_START_MESSAGE|PIPE_RAW_MODE)) == (PIPE_START_MESSAGE|PIPE_RAW_MODE)); char *data; if (!p) { reply_doserror(req, ERRDOS, ERRbadfid); return; } if (p->vuid != req->vuid) { reply_nterror(req, NT_STATUS_INVALID_HANDLE); return; } data = smb_base(req->inbuf) + smb_doff; if (numtowrite == 0) { nwritten = 0; } else { if(pipe_start_message_raw) { /* * For the start of a message in named pipe byte mode, * the first two bytes are a length-of-pdu field. Ignore * them (we don't trust the client). JRA. */ if(numtowrite < 2) { DEBUG(0,("reply_pipe_write_and_X: start of " "message set and not enough data " "sent.(%u)\n", (unsigned int)numtowrite )); reply_unixerror(req, ERRDOS, ERRnoaccess); return; } data += 2; numtowrite -= 2; } nwritten = write_to_pipe(p, data, numtowrite); } if ((nwritten == 0 && numtowrite != 0) || (nwritten < 0)) { reply_unixerror(req, ERRDOS,ERRnoaccess); return; } reply_outbuf(req, 6, 0); nwritten = (pipe_start_message_raw ? nwritten + 2 : nwritten); SSVAL(req->outbuf,smb_vwv2,nwritten); DEBUG(3,("writeX-IPC pnum=%04x nwritten=%d\n", p->pnum, nwritten)); chain_reply(req); }